[PATCH xwayland 2/2 v2] xwayland: Always update the wl_pointer cursor on pointer focus

Jonas Ådahl jadahl at gmail.com
Mon Sep 28 19:25:22 PDT 2015


In Wayland, a client (in this case XWayland) should set the cursor
surface when it receives pointer focus. Not doing this will leave the
curser at whatever it was previously.

When running on XWayland, the X server will not be the entity that
controls what actual pointer cursor is displayed, and it wont be notified
about the pointer cursor changes done by the Wayland compositor. This
causes X11 clients running via XWayland to end up with incorrect pointer
cursors because the X server believes that, if the cursor was previously
set to the cursor C, if we receive Wayland pointer focus over window W
which also has the pointer cursor C, we do not need to update it. This
will cause us to end up with the wrong cursor if cursor C was not the
same one that was already set by the Wayland compositor.

This patch introduces new API to mi/ to make it possible for a XWayland
to trigger resetting of the pointer cursor sprite the next time dix asks
it to display one.

XWayland will now call this function upon receiving pointer focus, making
sure that subsequent calls will trigger resetting of the pointer cursor
sprite.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---

Hi,

This is the second version. In this patch I avoid poking at dix/ because
it not needed thanks to PATCH 1/2 in this series. I still don't wrap the
DisplayCursor vfunc, because the problem is still that only on enter do I
want to force-trigger updating the cursor on wl_pointer.enter, and I
can't cause mipointer.c to do that without new API and state, and there
is setting a state in xwayland letting a wrapped DisplayCursor do that
when one can do it up front before calling CheckMotion().

As mentioned, a different approach would be to work-around the issue in
xwayland, but I consider such a solution more hacky than this. Please let
me know what you think.


Jonas

 hw/xwayland/xwayland-input.c |  6 +++++-
 mi/mipointer.c               | 12 +++++++++++-
 mi/mipointer.h               |  3 +++
 mi/mipointrst.h              |  1 +
 4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 010d28c..0c466c1 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -32,6 +32,7 @@
 #include <xkbsrv.h>
 #include <xserver-properties.h>
 #include <inpututils.h>
+#include <mipointer.h>
 
 static void
 xwl_pointer_control(DeviceIntPtr device, PtrCtrl *ctrl)
@@ -210,6 +211,7 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
 {
     struct xwl_seat *xwl_seat = data;
     DeviceIntPtr dev = xwl_seat->pointer;
+    DeviceIntPtr master;
     int i;
     int sx = wl_fixed_to_int(sx_w);
     int sy = wl_fixed_to_int(sy_w);
@@ -230,8 +232,10 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
 
     xwl_seat->focus_window = wl_surface_get_user_data(surface);
 
+    master = GetMaster(dev, POINTER_OR_FLOAT);
     (*pScreen->SetCursorPosition) (dev, pScreen, sx, sy, TRUE);
-    CheckMotion(NULL, GetMaster(dev, POINTER_OR_FLOAT));
+    miPointerInvalidateCursor(master);
+    CheckMotion(NULL, master);
 
     /* Ideally, X clients shouldn't see these button releases.  When
      * the pointer leaves a window with buttons down, it means that
diff --git a/mi/mipointer.c b/mi/mipointer.c
index ada1ab5..1afba24 100644
--- a/mi/mipointer.c
+++ b/mi/mipointer.c
@@ -389,6 +389,14 @@ miPointerWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
         UpdateSpriteForScreen(pDev, pScreen);
 }
 
+void
+miPointerInvalidateCursor(DeviceIntPtr pDev)
+{
+    miPointerPtr pPointer = MIPOINTER(pDev);
+
+    pPointer->cursorInvalidated = TRUE;
+}
+
 /**
  * Syncronize the sprite with the cursor.
  *
@@ -448,7 +456,8 @@ miPointerUpdateSprite(DeviceIntPtr pDev)
     /*
      * if the cursor has changed, display the new one
      */
-    else if (pPointer->pCursor != pPointer->pSpriteCursor) {
+    else if (pPointer->pCursor != pPointer->pSpriteCursor ||
+             pPointer->cursorInvalidated) {
         pCursor = pPointer->pCursor;
         if (!pCursor ||
             (pCursor->bits->emptyMask && !pScreenPriv->showTransparent))
@@ -465,6 +474,7 @@ miPointerUpdateSprite(DeviceIntPtr pDev)
         if (pPointer->pCursor && !pPointer->pCursor->bits->emptyMask)
             (*pScreenPriv->spriteFuncs->MoveCursor) (pDev, pScreen, x, y);
     }
+    pPointer->cursorInvalidated = FALSE;
 }
 
 /**
diff --git a/mi/mipointer.h b/mi/mipointer.h
index bdeed12..ef5e082 100644
--- a/mi/mipointer.h
+++ b/mi/mipointer.h
@@ -91,6 +91,9 @@ extern _X_EXPORT void miPointerWarpCursor(DeviceIntPtr /*pDev */ ,
                                           int   /*y */
     );
 
+extern _X_EXPORT void miPointerInvalidateCursor(DeviceIntPtr /*pDev */
+    );
+
 extern _X_EXPORT ScreenPtr
 miPointerGetScreen(DeviceIntPtr pDev);
 extern _X_EXPORT void
diff --git a/mi/mipointrst.h b/mi/mipointrst.h
index 104e45c..38a9f6f 100644
--- a/mi/mipointrst.h
+++ b/mi/mipointrst.h
@@ -44,6 +44,7 @@ typedef struct {
     int x, y;                   /* hot spot location */
     int devx, devy;             /* sprite position */
     Bool generateEvent;         /* generate an event during warping? */
+    Bool cursorInvalidated;     /* update cursor even if it didn't change */
 } miPointerRec, *miPointerPtr;
 
 typedef struct {
-- 
2.4.3



More information about the xorg-devel mailing list