Fix clicking on the titlebar causing mouse input to freeze until esc is pressed

When the titlebar drage region is clicked two actions are triggered:
  * The WM transfers focus to the application
  * The application starts a drag operation because the drag region was clicked

When the drag operation starts before input has been transferred to the application the
window manager gets in a bad state where mouse clicks don't work and the system isn't
actually dragging.

In this CL we delay drag operations until after the application has acquired active focus.
This fixes the problems outlined above.
main
Sam Lantinga 2024-03-06 13:33:23 -08:00
parent 65a718f8c6
commit 610e798406
3 changed files with 25 additions and 4 deletions

View File

@ -506,7 +506,7 @@ static void X11_DispatchUnmapNotify(SDL_WindowData *data)
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
}
static void InitiateWindowMove(SDL_VideoDevice *_this, const SDL_WindowData *data, const SDL_Point *point)
static void DispatchWindowMove(SDL_VideoDevice *_this, const SDL_WindowData *data, const SDL_Point *point)
{
SDL_VideoData *viddata = _this->driverdata;
SDL_Window *window = data->window;
@ -531,6 +531,12 @@ static void InitiateWindowMove(SDL_VideoDevice *_this, const SDL_WindowData *dat
X11_XSync(display, 0);
}
static void ScheduleWindowMove(SDL_VideoDevice *_this, SDL_WindowData *data, const SDL_Point *point)
{
data->pending_move = SDL_TRUE;
data->pending_move_point = *point;
}
static void InitiateWindowResize(SDL_VideoDevice *_this, const SDL_WindowData *data, const SDL_Point *point, int direction)
{
SDL_VideoData *viddata = _this->driverdata;
@ -574,7 +580,7 @@ SDL_bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const
return SDL_TRUE;
}
SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, const SDL_WindowData *data, const float x, const float y)
SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y)
{
SDL_Window *window = data->window;
@ -589,7 +595,14 @@ SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, const SDL_WindowData *
switch (data->hit_test_result) {
case SDL_HITTEST_DRAGGABLE:
InitiateWindowMove(_this, data, &point);
/* Some window managers get in a bad state when a move event starts while input is transitioning
to the SDL window. This can happen when clicking on a drag region of an unfocused window
where the same mouse down event will trigger a drag event and a window activate. */
if (data->window->flags & SDL_WINDOW_INPUT_FOCUS) {
DispatchWindowMove(_this, data, &point);
} else {
ScheduleWindowMove(_this, data, &point);
}
return SDL_TRUE;
case SDL_HITTEST_RESIZE_TOPLEFT:
@ -1719,6 +1732,12 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
X11_XResizeWindow(display, data->xwindow, data->window->floating.w, data->window->floating.h);
}
}
if ((flags & SDL_WINDOW_INPUT_FOCUS)) {
if (data->pending_move) {
DispatchWindowMove(_this, data, &data->pending_move_point);
data->pending_move = SDL_FALSE;
}
}
}
if (changed & SDL_WINDOW_OCCLUDED) {
SDL_SendWindowEvent(data->window, (flags & SDL_WINDOW_OCCLUDED) ? SDL_EVENT_WINDOW_OCCLUDED : SDL_EVENT_WINDOW_EXPOSED, 0, 0);

View File

@ -33,6 +33,6 @@ extern void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *wdata,
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, 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);
extern SDL_bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y);
#endif /* SDL_x11events_h_ */

View File

@ -63,6 +63,8 @@ struct SDL_WindowData
Uint64 last_focus_event_time;
PendingFocusEnum pending_focus;
Uint64 pending_focus_time;
SDL_bool pending_move;
SDL_Point pending_move_point;
XConfigureEvent last_xconfigure;
struct SDL_VideoData *videodata;
unsigned long user_time;