Browse Source

Hit testing tweaks for X11 and Wayland (#8582)

Hit testing on X11 and Wayland should now behave more like it
does on Windows - the current active zone is tracked on mouse
motion events and the cursor is changed accordingly when hovering
a "special" zone (such as the resize handles).
Ionuț Leonte 1 year ago
parent
commit
b76f8de298

+ 28 - 12
src/video/wayland/SDL_waylandevents.c

@@ -32,6 +32,7 @@
 #include "SDL_waylandvideo.h"
 #include "SDL_waylandevents_c.h"
 #include "SDL_waylandwindow.h"
+#include "SDL_waylandmouse.h"
 
 #include "pointer-constraints-unstable-v1-client-protocol.h"
 #include "relative-pointer-unstable-v1-client-protocol.h"
@@ -490,13 +491,26 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
                                   uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
 {
     struct SDL_WaylandInput *input = data;
-    SDL_WindowData *window = input->pointer_focus;
+    SDL_WindowData *window_data = input->pointer_focus;
+    SDL_Window *window = window_data ? window_data->sdlwindow : NULL;
+
     input->sx_w = sx_w;
     input->sy_w = sy_w;
     if (input->pointer_focus) {
-        float sx = (float)(wl_fixed_to_double(sx_w) * window->pointer_scale_x);
-        float sy = (float)(wl_fixed_to_double(sy_w) * window->pointer_scale_y);
-        SDL_SendMouseMotion(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, 0, 0, sx, sy);
+        float sx = (float)(wl_fixed_to_double(sx_w) * window_data->pointer_scale_x);
+        float sy = (float)(wl_fixed_to_double(sy_w) * window_data->pointer_scale_y);
+        SDL_SendMouseMotion(Wayland_GetPointerTimestamp(input, time), window_data->sdlwindow, 0, 0, sx, sy);
+    }
+
+    if (window && window->hit_test) {
+        const SDL_Point point = { wl_fixed_to_int(sx_w), wl_fixed_to_int(sy_w) };
+        SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
+        if (rc == window_data->hit_test_result) {
+            return;
+        }
+
+        Wayland_SetHitTestCursor(rc);
+        window_data->hit_test_result = rc;
     }
 }
 
@@ -540,7 +554,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
         /* If the cursor was changed while our window didn't have pointer
          * focus, we might need to trigger another call to
          * wl_pointer_set_cursor() for the new cursor to be displayed. */
-        SDL_SetCursor(NULL);
+        Wayland_SetHitTestCursor(window->hit_test_result);
     }
 }
 
@@ -580,9 +594,6 @@ static SDL_bool ProcessHitTest(SDL_WindowData *window_data,
     SDL_Window *window = window_data->sdlwindow;
 
     if (window->hit_test) {
-        const SDL_Point point = { wl_fixed_to_int(sx_w), wl_fixed_to_int(sy_w) };
-        const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
-
         static const uint32_t directions[] = {
             XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_TOP,
             XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT,
@@ -599,12 +610,14 @@ static SDL_bool ProcessHitTest(SDL_WindowData *window_data,
         };
 #endif
 
-        switch (rc) {
+        switch (window_data->hit_test_result) {
         case SDL_HITTEST_DRAGGABLE:
 #ifdef HAVE_LIBDECOR_H
             if (window_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
                 if (window_data->shell_surface.libdecor.frame) {
-                    libdecor_frame_move(window_data->shell_surface.libdecor.frame, seat, serial);
+                    libdecor_frame_move(window_data->shell_surface.libdecor.frame,
+                                        seat,
+                                        serial);
                 }
             } else
 #endif
@@ -628,7 +641,10 @@ static SDL_bool ProcessHitTest(SDL_WindowData *window_data,
 #ifdef HAVE_LIBDECOR_H
             if (window_data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
                 if (window_data->shell_surface.libdecor.frame) {
-                    libdecor_frame_resize(window_data->shell_surface.libdecor.frame, seat, serial, directions_libdecor[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
+                    libdecor_frame_resize(window_data->shell_surface.libdecor.frame,
+                                          seat,
+                                          serial,
+                                          directions_libdecor[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
                 }
             } else
 #endif
@@ -637,7 +653,7 @@ static SDL_bool ProcessHitTest(SDL_WindowData *window_data,
                     xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel,
                                         seat,
                                         serial,
-                                        directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
+                                        directions[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
                 }
             }
             return SDL_TRUE;

+ 42 - 13
src/video/wayland/SDL_waylandmouse.c

@@ -41,6 +41,8 @@
 
 #include "../../SDL_hints_c.h"
 
+static SDL_Cursor *sys_cursors[SDL_HITTEST_RESIZE_LEFT + 1];
+
 static int Wayland_SetRelativeMouseMode(SDL_bool enabled);
 
 typedef struct
@@ -315,43 +317,44 @@ static SDL_bool wayland_get_system_cursor(SDL_VideoData *vdata, Wayland_CursorDa
         vdata->cursor_themes[vdata->num_cursor_themes++].theme = theme;
     }
 
-    /* Next, find the cursor from the theme... */
+    /* Next, find the cursor from the theme. Names taken from: */
+    /*   https://www.freedesktop.org/wiki/Specifications/cursor-spec/ */
     switch (cdata->system_cursor) {
     case SDL_SYSTEM_CURSOR_ARROW:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "left_ptr");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "default");
         break;
     case SDL_SYSTEM_CURSOR_IBEAM:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "xterm");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "text");
         break;
     case SDL_SYSTEM_CURSOR_WAIT:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "watch");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "wait");
         break;
     case SDL_SYSTEM_CURSOR_CROSSHAIR:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "tcross");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "crosshair");
         break;
     case SDL_SYSTEM_CURSOR_WAITARROW:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "watch");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "progress");
         break;
     case SDL_SYSTEM_CURSOR_SIZENWSE:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "top_left_corner");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "nw-resize");
         break;
     case SDL_SYSTEM_CURSOR_SIZENESW:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "top_right_corner");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "ne-resize");
         break;
     case SDL_SYSTEM_CURSOR_SIZEWE:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "sb_h_double_arrow");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "e-resize");
         break;
     case SDL_SYSTEM_CURSOR_SIZENS:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "sb_v_double_arrow");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "n-resize");
         break;
     case SDL_SYSTEM_CURSOR_SIZEALL:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "fleur");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "fleur");  // ?
         break;
     case SDL_SYSTEM_CURSOR_NO:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "pirate");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "not-allowed");
         break;
     case SDL_SYSTEM_CURSOR_HAND:
-        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "hand2");
+        cursor = WAYLAND_wl_cursor_theme_get_cursor(theme, "pointer");
         break;
     default:
         SDL_assert(0);
@@ -771,6 +774,23 @@ void Wayland_InitMouse(void)
     input->relative_mode_override = SDL_FALSE;
     input->cursor_visible = SDL_TRUE;
 
+    SDL_HitTestResult r = SDL_HITTEST_NORMAL;
+    while (r <= SDL_HITTEST_RESIZE_LEFT) {
+        switch (r) {
+        case SDL_HITTEST_NORMAL: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); break;
+        case SDL_HITTEST_DRAGGABLE: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); break;
+        case SDL_HITTEST_RESIZE_TOPLEFT: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); break;
+        case SDL_HITTEST_RESIZE_TOP: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); break;
+        case SDL_HITTEST_RESIZE_TOPRIGHT: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); break;
+        case SDL_HITTEST_RESIZE_RIGHT: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); break;
+        case SDL_HITTEST_RESIZE_BOTTOMRIGHT: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); break;
+        case SDL_HITTEST_RESIZE_BOTTOM: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); break;
+        case SDL_HITTEST_RESIZE_BOTTOMLEFT: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); break;
+        case SDL_HITTEST_RESIZE_LEFT: sys_cursors[r] = Wayland_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); break;
+        }
+        r++;
+    }
+
 #ifdef SDL_USE_LIBDBUS
     Wayland_DBusInitCursorProperties(d);
 #endif
@@ -795,4 +815,13 @@ void Wayland_FiniMouse(SDL_VideoData *data)
                         Wayland_EmulateMouseWarpChanged, input);
 }
 
+void Wayland_SetHitTestCursor(SDL_HitTestResult rc)
+{
+    if (rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
+        SDL_SetCursor(NULL);
+    } else {
+        Wayland_ShowCursor(sys_cursors[rc]);
+    }
+}
+
 #endif /* SDL_VIDEO_DRIVER_WAYLAND */

+ 1 - 0
src/video/wayland/SDL_waylandmouse.h

@@ -26,6 +26,7 @@
 
 extern void Wayland_InitMouse(void);
 extern void Wayland_FiniMouse(SDL_VideoData *data);
+extern void Wayland_SetHitTestCursor(SDL_HitTestResult rc);
 #if 0  /* TODO RECONNECT: See waylandvideo.c for more information! */
 extern void Wayland_RecreateCursors(void);
 #endif /* 0 */

+ 2 - 0
src/video/wayland/SDL_waylandwindow.c

@@ -2109,6 +2109,8 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
     SDL_SetProperty(props, "SDL.window.wayland.surface", data->surface);
     SDL_SetProperty(props, "SDL.window.wayland.egl_window", data->egl_window);
 
+    data->hit_test_result = SDL_HITTEST_NORMAL;
+
     return 0;
 }
 

+ 2 - 0
src/video/wayland/SDL_waylandwindow.h

@@ -121,6 +121,8 @@ struct SDL_WindowData
     SDL_bool is_fullscreen;
     SDL_bool in_fullscreen_transition;
     SDL_bool fullscreen_was_positioned;
+
+    SDL_HitTestResult hit_test_result;
 };
 
 extern void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);

+ 21 - 5
src/video/x11/SDL_x11events.c

@@ -559,13 +559,26 @@ static void InitiateWindowResize(SDL_VideoDevice *_this, const SDL_WindowData *d
     X11_XSync(display, 0);
 }
 
-SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, const SDL_WindowData *data, const float x, const float y)
+SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y, SDL_bool force_new_result)
+{
+    SDL_Window *window = data->window;
+    if (!window->hit_test) return SDL_FALSE;
+    const SDL_Point point = { x, y };
+    SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
+    if (!force_new_result && rc == data->hit_test_result) {
+        return SDL_TRUE;
+    }
+    X11_SetHitTestCursor(rc);
+    data->hit_test_result = rc;
+    return SDL_TRUE;
+}
+
+SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, const SDL_WindowData *data, const float x, const float y)
 {
     SDL_Window *window = data->window;
 
     if (window->hit_test) {
         const SDL_Point point = { x, y };
-        const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
         static const int directions[] = {
             _NET_WM_MOVERESIZE_SIZE_TOPLEFT, _NET_WM_MOVERESIZE_SIZE_TOP,
             _NET_WM_MOVERESIZE_SIZE_TOPRIGHT, _NET_WM_MOVERESIZE_SIZE_RIGHT,
@@ -573,7 +586,7 @@ SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, const SDL_WindowData *data,
             _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT, _NET_WM_MOVERESIZE_SIZE_LEFT
         };
 
-        switch (rc) {
+        switch (data->hit_test_result) {
         case SDL_HITTEST_DRAGGABLE:
             InitiateWindowMove(_this, data, &point);
             return SDL_TRUE;
@@ -586,7 +599,7 @@ SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, const SDL_WindowData *data,
         case SDL_HITTEST_RESIZE_BOTTOM:
         case SDL_HITTEST_RESIZE_BOTTOMLEFT:
         case SDL_HITTEST_RESIZE_LEFT:
-            InitiateWindowResize(_this, data, &point, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
+            InitiateWindowResize(_this, data, &point, directions[data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
             return SDL_TRUE;
 
         default:
@@ -819,7 +832,7 @@ void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, i
     } else {
         SDL_bool ignore_click = SDL_FALSE;
         if (button == Button1) {
-            if (X11_ProcessHitTest(_this, windowdata, x, y)) {
+            if (X11_TriggerHitTestAction(_this, windowdata, x, y)) {
                 SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HIT_TEST, 0, 0);
                 return; /* don't pass this event on to app. */
             }
@@ -1078,6 +1091,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
 
         /* We ungrab in LeaveNotify, so we may need to grab again here */
         SDL_UpdateWindowGrab(data->window);
+
+        X11_ProcessHitTest(_this, data, mouse->last_x, mouse->last_y, SDL_TRUE);
     } break;
         /* Losing mouse coverage? */
     case LeaveNotify:
@@ -1483,6 +1498,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
             printf("window %p: X11 motion: %d,%d\n", data, xevent->xmotion.x, xevent->xmotion.y);
 #endif
 
+            X11_ProcessHitTest(_this, data, (float)xevent->xmotion.x, (float)xevent->xmotion.y, SDL_FALSE);
             SDL_SendMouseMotion(0, data->window, 0, 0, (float)xevent->xmotion.x, (float)xevent->xmotion.y);
         }
     } break;

+ 2 - 1
src/video/x11/SDL_x11events.h

@@ -32,6 +32,7 @@ extern void X11_GetBorderValues(SDL_WindowData *data);
 extern void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *wdata, int button, const float x, const float y, const unsigned long time);
 extern void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *wdata, int button);
 extern SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window);
-extern SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, const SDL_WindowData *data, const float x, const float y);
+extern SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y, SDL_bool force_new_result);
+extern SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, const SDL_WindowData *data, const float x, const float y);
 
 #endif /* SDL_x11events_h_ */

+ 28 - 0
src/video/x11/SDL_x11mouse.c

@@ -31,6 +31,8 @@
 /* FIXME: Find a better place to put this... */
 static Cursor x11_empty_cursor = None;
 
+static SDL_Cursor *sys_cursors[SDL_HITTEST_RESIZE_LEFT + 1];
+
 static Display *GetDisplay(void)
 {
     return SDL_GetVideoDevice()->driverdata->display;
@@ -472,6 +474,23 @@ void X11_InitMouse(SDL_VideoDevice *_this)
     mouse->CaptureMouse = X11_CaptureMouse;
     mouse->GetGlobalMouseState = X11_GetGlobalMouseState;
 
+    SDL_HitTestResult r = SDL_HITTEST_NORMAL;
+    while (r <= SDL_HITTEST_RESIZE_LEFT) {
+        switch (r) {
+        case SDL_HITTEST_NORMAL: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); break;
+        case SDL_HITTEST_DRAGGABLE: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); break;
+        case SDL_HITTEST_RESIZE_TOPLEFT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); break;
+        case SDL_HITTEST_RESIZE_TOP: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); break;
+        case SDL_HITTEST_RESIZE_TOPRIGHT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); break;
+        case SDL_HITTEST_RESIZE_RIGHT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); break;
+        case SDL_HITTEST_RESIZE_BOTTOMRIGHT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); break;
+        case SDL_HITTEST_RESIZE_BOTTOM: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); break;
+        case SDL_HITTEST_RESIZE_BOTTOMLEFT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); break;
+        case SDL_HITTEST_RESIZE_LEFT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); break;
+        }
+        r++;
+    }
+
     SDL_SetDefaultCursor(X11_CreateDefaultCursor());
 }
 
@@ -490,4 +509,13 @@ void X11_QuitMouse(SDL_VideoDevice *_this)
     X11_DestroyEmptyCursor();
 }
 
+void X11_SetHitTestCursor(SDL_HitTestResult rc)
+{
+    if (rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
+        SDL_SetCursor(NULL);
+    } else {
+        X11_ShowCursor(sys_cursors[rc]);
+    }
+}
+
 #endif /* SDL_VIDEO_DRIVER_X11 */

+ 1 - 0
src/video/x11/SDL_x11mouse.h

@@ -35,5 +35,6 @@ typedef struct SDL_XInput2DeviceInfo
 
 extern void X11_InitMouse(SDL_VideoDevice *_this);
 extern void X11_QuitMouse(SDL_VideoDevice *_this);
+extern void X11_SetHitTestCursor(SDL_HitTestResult rc);
 
 #endif /* SDL_x11mouse_h_ */

+ 1 - 0
src/video/x11/SDL_x11window.c

@@ -317,6 +317,7 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, Window w)
     }
     data->window = window;
     data->xwindow = w;
+    data->hit_test_result = SDL_HITTEST_NORMAL;
 
 #ifdef X_HAVE_UTF8_STRING
     if (SDL_X11_HAVE_UTF8 && videodata->im) {

+ 1 - 0
src/video/x11/SDL_x11window.h

@@ -79,6 +79,7 @@ struct SDL_WindowData
     PointerBarrier barrier[4];
     SDL_Rect barrier_rect;
 #endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
+    SDL_HitTestResult hit_test_result;
 };
 
 extern void X11_SetNetWMState(SDL_VideoDevice *_this, Window xwindow, Uint32 flags);

+ 5 - 5
src/video/x11/SDL_x11xinput2.c

@@ -395,11 +395,10 @@ int X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
 		/* button 1 is the pen tip */
 		if (pressed && SDL_PenPerformHitTest()) {
 		    /* Check whether we should handle window resize / move events */
-		    const SDL_WindowData *windowdata = X11_FindWindow(_this, xev->event);
-
-		    if (X11_ProcessHitTest(_this, windowdata, pen->last.x, pen->last.y)) {
-			SDL_SendWindowEvent(windowdata->window, SDL_EVENT_WINDOW_HIT_TEST, 0, 0);
-			return 1; /* Don't pass on this event */
+		    SDL_WindowData *windowdata = X11_FindWindow(_this, xev->event);
+		    if (windowdata && X11_TriggerHitTestAction(_this, windowdata, pen->last.x, pen->last.y)) {
+                SDL_SendWindowEvent(windowdata->window, SDL_EVENT_WINDOW_HIT_TEST, 0, 0);
+                return 1; /* Don't pass on this event */
 		    }
 		}
 		SDL_SendPenTipEvent(0, pen->header.id,
@@ -467,6 +466,7 @@ int X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
             if (!mouse->relative_mode || mouse->relative_mode_warp) {
                 SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
                 if (window) {
+                    X11_ProcessHitTest(_this, window->driverdata, (float)xev->event_x, (float)xev->event_y, SDL_FALSE);
                     SDL_SendMouseMotion(0, window, 0, 0, (float)xev->event_x, (float)xev->event_y);
                 }
             }