diff --git a/events.cpp b/events.cpp --- a/events.cpp +++ b/events.cpp @@ -286,6 +286,10 @@ break; } case XCB_MOTION_NOTIFY: { + if (kwinApp()->operationMode() != Application::OperationModeX11) { + // ignore X11 pointer events generated on X windows if we are not on X + return true; + } auto *mouseEvent = reinterpret_cast(e); const QPoint rootPos(mouseEvent->root_x, mouseEvent->root_y); #ifdef KWIN_BUILD_TABBOX diff --git a/pointer_input.h b/pointer_input.h --- a/pointer_input.h +++ b/pointer_input.h @@ -29,6 +29,14 @@ class QWindow; +namespace KWayland +{ +namespace Server +{ +class SurfaceInterface; +} +} + namespace KWin { @@ -122,6 +130,7 @@ private: void updatePosition(const QPointF &pos); void updateButton(uint32_t button, InputRedirection::PointerButtonState state); + void warpXcbOnSurfaceLeft(KWayland::Server::SurfaceInterface *surface); CursorImage *m_cursor; bool m_inited = false; bool m_supportsWarping; diff --git a/pointer_input.cpp b/pointer_input.cpp --- a/pointer_input.cpp +++ b/pointer_input.cpp @@ -405,6 +405,7 @@ if (t && t->surface()) { m_window = QPointer(t); // TODO: add convenient API to update global pos together with updating focused surface + warpXcbOnSurfaceLeft(t->surface()); seat->setFocusedPointerSurface(nullptr); seat->setPointerPos(m_pos.toPoint()); seat->setFocusedPointerSurface(t->surface(), t->inputTransformation()); @@ -427,11 +428,40 @@ ); } else { m_window.clear(); + warpXcbOnSurfaceLeft(nullptr); seat->setFocusedPointerSurface(nullptr); t = nullptr; } } +void PointerInputRedirection::warpXcbOnSurfaceLeft(KWayland::Server::SurfaceInterface *newSurface) +{ + auto xc = waylandServer()->xWaylandConnection(); + if (!xc) { + // No XWayland, no point in warping the x cursor + return; + } + if (!kwinApp()->x11Connection()) { + return; + } + static bool s_hasXWayland119 = xcb_get_setup(kwinApp()->x11Connection())->release_number >= 11900000; + if (s_hasXWayland119) { + return; + } + if (newSurface && newSurface->client() == xc) { + // new window is an X window + return; + } + auto s = waylandServer()->seat()->focusedPointerSurface(); + if (!s || s->client() != xc) { + // pointer was not on an X window + return; + } + // warp pointer to 0/0 to trigger leave events on previously focused X window + xcb_warp_pointer(connection(), XCB_WINDOW_NONE, rootWindow(), 0, 0, 0, 0, 0, 0), + xcb_flush(connection()); +} + void PointerInputRedirection::updatePosition(const QPointF &pos) { // verify that at least one screen contains the pointer position