Warp the xcb pointer whenever pointer leaves an X11 surface
Summary: For Xwayland windows we observed that passing pointer focus to another window does not trigger proper leave events on X. Which results in e.g. tooltip windows to show after the pointer moved to a completely different position on a completely different surface. This is a bug in Xwayland which will be fixed in 1.19 (already fixed in master). Given that there is a runtime version check. Although it's fixed in Xwayland master it's worth to carry a workaround. To circumvent this problem KWin warps the xcb pointer to 0/0 whever an X window loses pointer focus. That way the X window gets a proper leave through the X protocol. This created a problem though: when giving focus back to the X window it started to warp the pointer for maximized windows as KWin got pointer motion events through the X11 event filter for positions on the window decoration. These are passed into the screen edge filter which pushes the pointer back and warps our Wayland pointer. To solve this problem KWin no longer performs any actions for pointer motion in the X11 event filter if not on X11. The event filter needs to be reworked and most of it should be moved into the Platform API, if possible. Test Plan: Reproduced situations where one could see that pointer updates don't trigger leave. E.g. going from a highlighted window to the decoration. Reviewers: #kwin, #plasma_on_wayland, bshah Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2531
This commit is contained in:
parent
455c5c07a0
commit
2feea7837a
4 changed files with 43 additions and 1 deletions
|
@ -195,7 +195,6 @@ void XWaylandInputTest::testPointerEnterLeave()
|
|||
|
||||
// move out of window
|
||||
Cursor::setPos(client->geometry().bottomRight() + QPoint(10, 10));
|
||||
QEXPECT_FAIL("", "Xwayland doesn't send leave events when the surface gets a leave", Continue);
|
||||
QVERIFY(leftSpy.wait());
|
||||
|
||||
// destroy window again
|
||||
|
|
|
@ -286,6 +286,10 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
|
|||
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<xcb_motion_notify_event_t*>(e);
|
||||
const QPoint rootPos(mouseEvent->root_x, mouseEvent->root_y);
|
||||
#ifdef KWIN_BUILD_TABBOX
|
||||
|
|
|
@ -405,6 +405,7 @@ void PointerInputRedirection::update()
|
|||
if (t && t->surface()) {
|
||||
m_window = QPointer<Toplevel>(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 @@ void PointerInputRedirection::update()
|
|||
);
|
||||
} 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
|
||||
|
|
|
@ -29,6 +29,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
class QWindow;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Server
|
||||
{
|
||||
class SurfaceInterface;
|
||||
}
|
||||
}
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -122,6 +130,7 @@ public:
|
|||
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;
|
||||
|
|
Loading…
Reference in a new issue