mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-18 09:53:05 +08:00
137 lines
4.1 KiB
C++
137 lines
4.1 KiB
C++
#include "runtime/cursor_state_provider.h"
|
|
|
|
#include <remote_action.h>
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <windows.h>
|
|
|
|
#include "runtime/cursor_position.h"
|
|
|
|
namespace crossdesk {
|
|
namespace {
|
|
|
|
bool IsSystemCursor(HCURSOR cursor, LPCWSTR resource) {
|
|
return cursor != nullptr && cursor == LoadCursorW(nullptr, resource);
|
|
}
|
|
|
|
RemoteCursorShape ShapeFromWindowsCursor(HCURSOR cursor) {
|
|
if (IsSystemCursor(cursor, IDC_HELP)) return RemoteCursorShape::help;
|
|
if (IsSystemCursor(cursor, IDC_HAND)) return RemoteCursorShape::pointer;
|
|
if (IsSystemCursor(cursor, IDC_APPSTARTING))
|
|
return RemoteCursorShape::progress;
|
|
if (IsSystemCursor(cursor, IDC_WAIT)) return RemoteCursorShape::wait;
|
|
if (IsSystemCursor(cursor, IDC_CROSS)) return RemoteCursorShape::crosshair;
|
|
if (IsSystemCursor(cursor, IDC_IBEAM)) return RemoteCursorShape::text;
|
|
if (IsSystemCursor(cursor, IDC_NO))
|
|
return RemoteCursorShape::not_allowed;
|
|
if (IsSystemCursor(cursor, IDC_SIZEALL)) return RemoteCursorShape::move;
|
|
if (IsSystemCursor(cursor, IDC_SIZEWE)) return RemoteCursorShape::ew_resize;
|
|
if (IsSystemCursor(cursor, IDC_SIZENS)) return RemoteCursorShape::ns_resize;
|
|
if (IsSystemCursor(cursor, IDC_SIZENESW))
|
|
return RemoteCursorShape::nesw_resize;
|
|
if (IsSystemCursor(cursor, IDC_SIZENWSE))
|
|
return RemoteCursorShape::nwse_resize;
|
|
if (IsSystemCursor(cursor, IDC_UPARROW)) return RemoteCursorShape::n_resize;
|
|
return RemoteCursorShape::default_cursor;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
struct CursorStateProvider::Impl {};
|
|
|
|
CursorStateProvider::CursorStateProvider() : impl_(std::make_unique<Impl>()) {}
|
|
CursorStateProvider::~CursorStateProvider() = default;
|
|
|
|
bool CursorStateProvider::Sample(const std::vector<DisplayInfo>& displays,
|
|
int preferred_display, CursorState* state) {
|
|
if (!state) return false;
|
|
|
|
CURSORINFO info{};
|
|
info.cbSize = sizeof(info);
|
|
if (!GetCursorInfo(&info)) return false;
|
|
|
|
state->seq = 0;
|
|
state->visible = (info.flags & CURSOR_SHOWING) != 0;
|
|
state->shape = state->visible ? ShapeFromWindowsCursor(info.hCursor)
|
|
: RemoteCursorShape::none;
|
|
NormalizeCursorPosition(info.ptScreenPos.x, info.ptScreenPos.y, displays,
|
|
preferred_display, state);
|
|
return true;
|
|
}
|
|
|
|
} // namespace crossdesk
|
|
|
|
#elif defined(__linux__) && !defined(__APPLE__)
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/Xfixes.h>
|
|
|
|
#include <string>
|
|
|
|
#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<size_t>(image.width) * static_cast<size_t>(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<Impl>()) {}
|
|
CursorStateProvider::~CursorStateProvider() = default;
|
|
|
|
bool CursorStateProvider::Sample(const std::vector<DisplayInfo>& 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
|