From 6bd2c6789b244a03bccdb254502567691c42b944 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 30 Jun 2022 22:53:20 +1000 Subject: [PATCH] GHOST: get/set cursor position now uses client instead of screen coords Use client (window) relative coordinates for cursor position access, this only moves the conversion from window-manager into GHOST, (no functional changes). This is needed for fix a bug in GHOST/Wayland which doesn't support accessing absolute cursor coordinates & the window is needed to properly access the cursor coordinates. As it happens every caller to GHOST_GetCursorPosition was already making the values window-relative, so there is little benefit in attempting to workaround the problem on the Wayland side. If needed the screen-space versions of functions can be exposed again. --- intern/ghost/GHOST_C-api.h | 19 ++++++----- intern/ghost/GHOST_ISystem.h | 19 +++++++++++ intern/ghost/intern/GHOST_C-api.cpp | 34 +++++++++++++++++-- intern/ghost/intern/GHOST_System.cpp | 23 +++++++++++++ intern/ghost/intern/GHOST_System.h | 11 ++++++ .../blender/windowmanager/intern/wm_cursors.c | 6 ++-- .../windowmanager/intern/wm_playanim.c | 11 +++--- .../blender/windowmanager/intern/wm_window.c | 32 ++++++++++------- source/blender/windowmanager/wm_window.h | 7 ++-- 9 files changed, 128 insertions(+), 34 deletions(-) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 0f05e501d17..4cbc0d65b11 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -383,27 +383,28 @@ extern bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle); extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, bool visible); /** - * Returns the current location of the cursor (location in screen coordinates) + * Returns the current location of the cursor (location in client relative coordinates) * \param systemhandle: The handle to the system. * \param x: The x-coordinate of the cursor. * \param y: The y-coordinate of the cursor. * \return Indication of success. */ -extern GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, - int32_t *x, - int32_t *y); - +GHOST_TSuccess GHOST_GetCursorPosition(const GHOST_SystemHandle systemhandle, + const GHOST_WindowHandle windowhandle, + int32_t *x, + int32_t *y); /** - * Updates the location of the cursor (location in screen coordinates). + * Updates the location of the cursor (location in client relative coordinates). * Not all operating systems allow the cursor to be moved (without the input device being moved). * \param systemhandle: The handle to the system. * \param x: The x-coordinate of the cursor. * \param y: The y-coordinate of the cursor. * \return Indication of success. */ -extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, - int32_t x, - int32_t y); +GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle, + int32_t x, + int32_t y); void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle, GHOST_TGrabCursorMode *r_mode, diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index d7485975906..91cf1c4c558 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -364,6 +364,25 @@ class GHOST_ISystem { * Cursor management functionality ***************************************************************************************/ + /** + * Returns the current location of the cursor (location in window coordinates) + * \param x: The x-coordinate of the cursor. + * \param y: The y-coordinate of the cursor. + * \return Indication of success. + */ + virtual GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window, + int32_t &x, + int32_t &y) const = 0; + /** + * Updates the location of the cursor (location in window coordinates). + * \param x: The x-coordinate of the cursor. + * \param y: The y-coordinate of the cursor. + * \return Indication of success. + */ + virtual GHOST_TSuccess setCursorPositionClientRelative(GHOST_IWindow *window, + int32_t x, + int32_t y) = 0; + /** * Returns the current location of the cursor (location in screen coordinates) * \param x: The x-coordinate of the cursor. diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 8c690767810..65e7de707ec 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -348,19 +348,49 @@ GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, bool v return window->setCursorVisibility(visible); } -GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, int32_t *x, int32_t *y) +/* Unused, can expose again if needed although WAYLAND + * can only properly use client relative coordinates, so leave disabled if possible. */ +#if 0 +GHOST_TSuccess GHOST_GetCursorPositionScreenCoords(GHOST_SystemHandle systemhandle, + int32_t *x, + int32_t *y) { GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; return system->getCursorPosition(*x, *y); } -GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, int32_t x, int32_t y) +GHOST_TSuccess GHOST_SetCursorPositionScreenCoords(GHOST_SystemHandle systemhandle, + int32_t x, + int32_t y) { GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; return system->setCursorPosition(x, y); } +#endif + +GHOST_TSuccess GHOST_GetCursorPosition(const GHOST_SystemHandle systemhandle, + const GHOST_WindowHandle windowhandle, + int32_t *x, + int32_t *y) +{ + const GHOST_ISystem *system = (const GHOST_ISystem *)systemhandle; + const GHOST_IWindow *window = (const GHOST_IWindow *)windowhandle; + + return system->getCursorPositionClientRelative(window, *x, *y); +} + +GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, + GHOST_WindowHandle windowhandle, + int32_t x, + int32_t y) +{ + GHOST_ISystem *system = (GHOST_ISystem *)systemhandle; + GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; + + return system->setCursorPositionClientRelative(window, x, y); +} GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, GHOST_TGrabCursorMode mode, diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 2f4ab9ee37c..cf04287af9f 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -260,6 +260,29 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event) return success; } +GHOST_TSuccess GHOST_System::getCursorPositionClientRelative(const GHOST_IWindow *window, + int32_t &x, + int32_t &y) const +{ + /* Sub-classes that can implement this directly should do so. */ + int32_t screen_x, screen_y; + GHOST_TSuccess success = getCursorPosition(screen_x, screen_y); + if (success == GHOST_kSuccess) { + window->screenToClient(screen_x, screen_y, x, y); + } + return success; +} + +GHOST_TSuccess GHOST_System::setCursorPositionClientRelative(GHOST_IWindow *window, + int32_t x, + int32_t y) +{ + /* Sub-classes that can implement this directly should do so. */ + int32_t screen_x, screen_y; + window->clientToScreen(x, y, screen_x, screen_y); + return setCursorPosition(screen_x, screen_y); +} + GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKey mask, bool &isDown) const { GHOST_ModifierKeys keys; diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index e4a49551222..42f0a773dea 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -203,6 +203,17 @@ class GHOST_System : public GHOST_ISystem { * Cursor management functionality ***************************************************************************************/ + /* Client relative functions use a default implementation + * that converts from screen-coordinates to client coordinates. + * Implementations may override. */ + + GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window, + int32_t &x, + int32_t &y) const override; + GHOST_TSuccess setCursorPositionClientRelative(GHOST_IWindow *window, + int32_t x, + int32_t y) override; + /** * Inherited from GHOST_ISystem but left pure virtual *
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 54636cb57ec..43be87fce39 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -231,8 +231,8 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
   GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kAxisY;
 
   if (bounds) {
-    wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]);
-    wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]);
+    wm_cursor_position_to_ghost_screen_coords(win, &bounds[0], &bounds[1]);
+    wm_cursor_position_to_ghost_screen_coords(win, &bounds[2], &bounds[3]);
   }
 
   if (hide) {
@@ -266,7 +266,7 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
     if (win && win->ghostwin) {
       if (mouse_ungrab_xy) {
         int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]};
-        wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]);
+        wm_cursor_position_to_ghost_screen_coords(win, &mouse_xy[0], &mouse_xy[1]);
         GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kAxisNone, NULL, mouse_xy);
       }
       else {
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index baba64b2230..99f117f267a 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1217,8 +1217,7 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
       GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
       int cx, cy, sizex, sizey, inside_window;
 
-      GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy);
-      GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy);
+      GHOST_GetCursorPosition(g_WS.ghost_system, g_WS.ghost_window, &cx, &cy);
       playanim_window_get_size(&sizex, &sizey);
 
       inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
@@ -1267,15 +1266,15 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
          * however the API currently doesn't support this. */
         {
           int x_test, y_test;
-          GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test);
-          if (x_test != cd->x || y_test != cd->y) {
+          GHOST_GetCursorPosition(g_WS.ghost_system, g_WS.ghost_window, &cx, &cy);
+          GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &x_test, &y_test);
+
+          if (cx != x_test || cy != y_test) {
             /* we're not the last event... skipping */
             break;
           }
         }
 
-        GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
-
         tag_change_frame(ps, cx);
       }
       break;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index baf137e6665..36f91f8414a 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -920,25 +920,33 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
 
 /* ************ events *************** */
 
-void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y)
+void wm_cursor_position_from_ghost_client_coords(wmWindow *win, int *x, int *y)
 {
   float fac = GHOST_GetNativePixelSize(win->ghostwin);
-
-  GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
   *x *= fac;
 
   *y = (win->sizey - 1) - *y;
   *y *= fac;
 }
 
-void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
+void wm_cursor_position_to_ghost_client_coords(wmWindow *win, int *x, int *y)
 {
   float fac = GHOST_GetNativePixelSize(win->ghostwin);
 
   *x /= fac;
   *y /= fac;
   *y = win->sizey - *y - 1;
+}
 
+void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *x, int *y)
+{
+  GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
+  wm_cursor_position_from_ghost_client_coords(win, x, y);
+}
+
+void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y)
+{
+  wm_cursor_position_to_ghost_client_coords(win, x, y);
   GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
 }
 
@@ -949,8 +957,8 @@ void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
     *r_y = win->eventstate->xy[1];
     return;
   }
-  GHOST_GetCursorPosition(g_system, r_x, r_y);
-  wm_cursor_position_from_ghost(win, r_x, r_y);
+  GHOST_GetCursorPosition(g_system, win->ghostwin, r_x, r_y);
+  wm_cursor_position_from_ghost_client_coords(win, r_x, r_y);
 }
 
 typedef enum {
@@ -1418,14 +1426,14 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
       case GHOST_kEventTrackpad: {
         GHOST_TEventTrackpadData *pd = data;
 
-        wm_cursor_position_from_ghost(win, &pd->x, &pd->y);
+        wm_cursor_position_from_ghost_screen_coords(win, &pd->x, &pd->y);
         wm_event_add_ghostevent(wm, win, type, data);
         break;
       }
       case GHOST_kEventCursorMove: {
         GHOST_TEventCursorData *cd = data;
 
-        wm_cursor_position_from_ghost(win, &cd->x, &cd->y);
+        wm_cursor_position_from_ghost_screen_coords(win, &cd->x, &cd->y);
         wm_event_add_ghostevent(wm, win, type, data);
         break;
       }
@@ -1866,7 +1874,7 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
 {
   int tmp[2];
   copy_v2_v2_int(tmp, mval);
-  wm_cursor_position_to_ghost(win, &tmp[0], &tmp[1]);
+  wm_cursor_position_to_ghost_screen_coords(win, &tmp[0], &tmp[1]);
 
   GHOST_WindowHandle ghostwin = GHOST_GetWindowUnderCursor(g_system, tmp[0], tmp[1]);
 
@@ -1875,7 +1883,7 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
   }
 
   wmWindow *win_other = GHOST_GetWindowUserData(ghostwin);
-  wm_cursor_position_from_ghost(win_other, &tmp[0], &tmp[1]);
+  wm_cursor_position_from_ghost_screen_coords(win_other, &tmp[0], &tmp[1]);
   copy_v2_v2_int(r_mval, tmp);
   return win_other;
 }
@@ -2015,8 +2023,8 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
   if (win && win->ghostwin) {
     int oldx = x, oldy = y;
 
-    wm_cursor_position_to_ghost(win, &x, &y);
-    GHOST_SetCursorPosition(g_system, x, y);
+    wm_cursor_position_to_ghost_client_coords(win, &x, &y);
+    GHOST_SetCursorPosition(g_system, win->ghostwin, x, y);
 
     win->eventstate->prev_xy[0] = oldx;
     win->eventstate->prev_xy[1] = oldy;
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 67557768413..3644aa085f7 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -100,8 +100,11 @@ void wm_window_set_swap_interval(wmWindow *win, int interval);
 bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
 
 void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y);
-void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y);
-void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y);
+void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *r_x, int *r_y);
+void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y);
+
+void wm_cursor_position_from_ghost_client_coords(wmWindow *win, int *x, int *y);
+void wm_cursor_position_to_ghost_client_coords(wmWindow *win, int *x, int *y);
 
 #ifdef WITH_INPUT_IME
 void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete);