#include "runtime/cursor_state_provider.h" #include #if defined(_WIN32) #include #include "platform/windows/input/windows_cursor_state.h" #include "platform/windows/screen_capturer/captured_cursor_state.h" #include "platform/windows/screen_capturer/dxgi_cursor_state.h" #include "platform/windows/screen_capturer/secure_desktop_cursor_state.h" #include "runtime/cursor_position.h" namespace crossdesk { struct CursorStateProvider::Impl { WindowsCursorState cursor; }; CursorStateProvider::CursorStateProvider() : impl_(std::make_unique()) {} CursorStateProvider::~CursorStateProvider() = default; bool CursorStateProvider::Sample(const std::vector& displays, int preferred_display, CursorState* state) { if (!state) return false; SecureDesktopCursorSnapshot secure_cursor{}; if (SharedSecureDesktopCursorState().Get(&secure_cursor)) { if (!secure_cursor.valid) { state->hidden_reason = CursorHiddenReason::secure_desktop_pending; return false; } state->seq = 0; NormalizeCursorPosition(secure_cursor.x, secure_cursor.y, displays, preferred_display, state); state->visible = secure_cursor.visible != 0; state->render_mode = static_cast(secure_cursor.render_mode); state->hidden_reason = static_cast(secure_cursor.hidden_reason); state->shape = state->visible ? static_cast(secure_cursor.shape) : RemoteCursorShape::none; return true; } CURSORINFO info{}; info.cbSize = sizeof(info); if (!GetCursorInfo(&info)) return false; state->seq = 0; NormalizeCursorPosition(info.ptScreenPos.x, info.ptScreenPos.y, displays, preferred_display, state); void* cursor_monitor = state->position_valid ? displays[state->display_id].handle : nullptr; const bool embedded = SharedCapturedCursorState().IsEmbedded(cursor_monitor) || ((info.flags & CURSOR_SHOWING) != 0 && !SharedDxgiCursorState().ShouldDrawCursor(true, cursor_monitor)); impl_->cursor.Sample(info, embedded, state); return true; } } // namespace crossdesk #elif defined(__linux__) && !defined(__APPLE__) #include #include #include #include "linux_cursor_shape.h" #include "platform.h" #include "shared_cursor_state.h" #include "runtime/cursor_position.h" namespace crossdesk { namespace { bool CursorHasVisiblePixel(const XFixesCursorImage& image) { const size_t pixel_count = static_cast(image.width) * static_cast(image.height); for (size_t index = 0; index < pixel_count; ++index) { if (((image.pixels[index] >> 24U) & 0xffU) != 0) return true; } return false; } } // namespace struct CursorStateProvider::Impl { Display* display = XOpenDisplay(nullptr); ~Impl() { if (display) XCloseDisplay(display); } }; CursorStateProvider::CursorStateProvider() : impl_(std::make_unique()) {} CursorStateProvider::~CursorStateProvider() = default; bool CursorStateProvider::Sample(const std::vector& displays, int preferred_display, CursorState* state) { if (!state || !impl_) return false; ResetCursorPosition(state); if (IsWaylandSession()) { SharedCursorState shared{}; if (GetSharedCursorState(&shared)) { state->seq = 0; state->visible = shared.visible; state->shape = shared.visible ? shared.shape : RemoteCursorShape::none; return true; } } if (!impl_->display) return false; XFixesCursorImage* image = XFixesGetCursorImage(impl_->display); if (!image) return false; const std::string name = image->name ? image->name : ""; state->seq = 0; state->visible = CursorHasVisiblePixel(*image); state->shape = state->visible ? ShapeFromLinuxCursorName(name) : RemoteCursorShape::none; NormalizeCursorPosition(image->x, image->y, displays, preferred_display, state); XFree(image); return true; } } // namespace crossdesk #endif