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.
This commit is contained in:
Campbell Barton 2022-06-30 22:53:20 +10:00
parent df40e9d0aa
commit 6bd2c6789b
9 changed files with 128 additions and 34 deletions

View File

@ -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,

View File

@ -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.

View File

@ -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,

View File

@ -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;

View File

@ -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
* <pre>

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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);