Fix #107594: Phantom cursor motion when resizing windows under Wayland

Resizing a window in Wayland caused cursor motion events in the window
which could be seen as buttons flashing when the cursor was detected
as hovering over buttons.

This was caused by two bugs:

- Missing checks for failure to access the cursor location before
  converting the coordinates from GHOST to screen-space meant the
  wmWindow::eventstate location would move each time the location
  was updated.

- Resizing the window wasn't detecting state changes and would
  continuously send window activation events. Window activation set
  wmWindpw::addmousemove which triggered the previous bug, making the
  cursor flicker during resize.

This commit only addresses the first issue, where failure to access
the cursor location wasn't accounted for
(window activation will be fixed separately).

All GHOST_GetCursorPosition & wm_cursor_position_get calls now account
for failure, resolving uninitialized stack memory use in some cases.

This resolves similar issues for macOS, WIN32 & X11 although it seems
likely these platforms rarely fail to access the cursor location.
This commit is contained in:
Campbell Barton 2023-10-06 17:10:33 +11:00
parent c801c73d79
commit 35edcf2ed6
7 changed files with 47 additions and 33 deletions

View File

@ -314,8 +314,9 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
{
/* NOTE: don't use wmEvent coords because of continuous grab #36409. */
int cx, cy;
wm_cursor_position_get(win, &cx, &cy);
WM_cursor_warp(win, cx + x, cy + y);
if (wm_cursor_position_get(win, &cx, &cy)) {
WM_cursor_warp(win, cx + x, cy + y);
}
}
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)

View File

@ -1005,13 +1005,13 @@ void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int
void wm_drags_draw(bContext *C, wmWindow *win)
{
int xy[2];
if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
wm_cursor_position_get(win, &xy[0], &xy[1]);
}
else {
xy[0] = win->eventstate->xy[0];
xy[1] = win->eventstate->xy[1];
const int *xy = win->eventstate->xy;
int xy_buf[2];
if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide) &&
wm_cursor_position_get(win, &xy_buf[0], &xy_buf[1]))
{
xy = xy_buf;
}
bScreen *screen = CTX_wm_screen(C);

View File

@ -140,16 +140,16 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
* cursor coordinates so limit reading the cursor location to when the cursor is grabbed and
* wrapping in a region since this is the case when it would otherwise attempt to draw the
* cursor outside the view/window. See: #102792. */
const int *xy = win->eventstate->xy;
int xy_buf[2];
if ((WM_capabilities_flag() & WM_CAPABILITY_CURSOR_WARP) &&
wm_window_grab_warp_region_is_set(win)) {
int x = 0, y = 0;
wm_cursor_position_get(win, &x, &y);
pc->draw(C, x, y, pc->customdata);
}
else {
pc->draw(C, win->eventstate->xy[0], win->eventstate->xy[1], pc->customdata);
wm_window_grab_warp_region_is_set(win) &&
wm_cursor_position_get(win, &xy_buf[0], &xy_buf[1]))
{
xy = xy_buf;
}
pc->draw(C, xy[0], xy[1], pc->customdata);
GPU_scissor_test(false);
}
}

View File

@ -2738,7 +2738,10 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
wm_window_make_drawable(wm, root_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
* opening (#UI_BLOCK_MOVEMOUSE_QUIT). */
wm_cursor_position_get(root_win, &eventstate->xy[0], &eventstate->xy[1]);
int xy[2];
if (wm_cursor_position_get(root_win, &xy[0], &xy[1])) {
copy_v2_v2_int(eventstate->xy, xy);
}
wm->winactive = root_win; /* Reports use this... */
}
else if (file_area->full) {

View File

@ -1326,12 +1326,12 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kEventButtonUp: {
GHOST_TEventButtonData *bd = reinterpret_cast<GHOST_TEventButtonData *>(
GHOST_GetEventData(evt));
int cx, cy, sizex, sizey, inside_window;
GHOST_GetCursorPosition(ghost_system, ghost_window, &cx, &cy);
int cx, cy, sizex, sizey;
playanim_window_get_size(ghost_window, &sizex, &sizey);
inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
const bool inside_window = (GHOST_GetCursorPosition(ghost_system, ghost_window, &cx, &cy) ==
GHOST_kSuccess) &&
(cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
if (bd->button == GHOST_kButtonMaskLeft) {
if (type == GHOST_kEventButtonDown) {
@ -1378,12 +1378,12 @@ 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(ghost_system, ghost_window, &cx, &cy);
GHOST_ScreenToClient(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;
if (GHOST_GetCursorPosition(ghost_system, ghost_window, &cx, &cy) == GHOST_kSuccess) {
GHOST_ScreenToClient(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;
}
}
}

View File

@ -663,7 +663,10 @@ static void wm_window_update_eventstate_modifiers_clear(wmWindowManager *wm, wmW
static void wm_window_update_eventstate(wmWindow *win)
{
/* Update mouse position when a window is activated. */
wm_cursor_position_get(win, &win->eventstate->xy[0], &win->eventstate->xy[1]);
int xy[2];
if (wm_cursor_position_get(win, &xy[0], &xy[1])) {
copy_v2_v2_int(win->eventstate->xy, xy);
}
}
static void wm_window_ensure_eventstate(wmWindow *win)
@ -1181,15 +1184,22 @@ void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y)
GHOST_ClientToScreen(static_cast<GHOST_WindowHandle>(win->ghostwin), *x, *y, x, y);
}
void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
*r_x = win->eventstate->xy[0];
*r_y = win->eventstate->xy[1];
return;
return true;
}
GHOST_GetCursorPosition(g_system, static_cast<GHOST_WindowHandle>(win->ghostwin), r_x, r_y);
wm_cursor_position_from_ghost_client_coords(win, r_x, r_y);
if (GHOST_GetCursorPosition(
g_system, static_cast<GHOST_WindowHandle>(win->ghostwin), r_x, r_y) == GHOST_kSuccess)
{
wm_cursor_position_from_ghost_client_coords(win, r_x, r_y);
return true;
}
return false;
}
/** Check if specified modifier key type is pressed. */

View File

@ -104,7 +104,7 @@ void wm_window_swap_buffers(wmWindow *win);
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);
bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y) ATTR_WARN_UNUSED_RESULT;
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);