Disclosure: written with AI assistance (Claude) to fix one machine (Fedora 45, Plasma 6.8.2, krfb 26.08.3, one monitor 2560x1440 at 125%). Tested on that setup only. Not a recommended fix; posted in case it helps. Context: KDE bugs 466276 (comment 13) and 524406. It may need small manual changes on other krfb versions (e.g. 26.04.x). --- a/events/xdp/xdpevents.cpp +++ b/events/xdp/xdpevents.cpp @@ -15,6 +15,10 @@ #include #include +#include +#include +#include +#include class EventData { @@ -45,6 +49,40 @@ QStringLiteral("/org/freedesktop/portal/desktop"), QDBusConnection::sessionBus())); } +// The VNC client reports pointer positions in framebuffer (physical) pixels, but the +// RemoteDesktop portal expects the compositor's logical (scaled) coordinates. +// Divide by the display scale. An optional override can be set in ~/.config/krfbrc: +// [General] +// pointerScale=1.25 +// Without it, the scale is derived from the captured frame width and the logical screen width. +static qreal configuredPointerScale() +{ + static const qreal value = []() -> qreal { + QSettings cfg(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/krfbrc"), QSettings::IniFormat); + bool ok = false; + const qreal v = cfg.value(QStringLiteral("pointerScale")).toDouble(&ok); + return (ok && v > 0) ? v : 0; + }(); + return value; +} + +static qreal pointerScale(int frameBufferWidth) +{ + const qreal configured = configuredPointerScale(); + if (configured > 0) { + return configured; + } + // QScreen::devicePixelRatio() is rounded up to a whole number on Wayland (2 for a 1.25x + // output), so derive the scale from the captured frame width and the logical screen width. + if (const QScreen *screen = QGuiApplication::primaryScreen()) { + const int logicalWidth = screen->geometry().width(); + if (logicalWidth > 0 && frameBufferWidth > 0) { + return qreal(frameBufferWidth) / logicalWidth; + } + } + return 1.0; +} + void XdpEventHandler::handleKeyboard(bool down, rfbKeySym keySym) { const QDBusObjectPath sessionHandle = frameBuffer()->customProperty(QStringLiteral("session_handle")).value(); @@ -61,7 +99,8 @@ } if (x != data->x || y != data->y) { - data->dbusXdpRemoteDesktopService->NotifyPointerMotionAbsolute(sessionHandle, QVariantMap(), streamNodeId, x, y); + const qreal scale = pointerScale(frameBuffer()->width()); + data->dbusXdpRemoteDesktopService->NotifyPointerMotionAbsolute(sessionHandle, QVariantMap(), streamNodeId, x / scale, y / scale); data->x = x; data->y = y; }