seat/impl: Wait for pointer constraining when updating viewports
It is generally assumed here and there that the pointer at all point in time is within some logical monitor, if there is any logical monitor to be within. With the input thread, this was for a short amount of time not reliable, resulting in crashes in combination with hotplugging or suspend/resume, where monitors come and go quickly. What happens is that the pointer at first is within a logical monitor, but when that logical monitor is removed, while the new monitor viewports are handed to the input thread, the constraining happens asynchronously, meaning there is a time between between the new viewports are sent, and before clutter_seat_query_state() starts reporting the constrained position. If a new client mapped a maximized window during this short time frame, we'd crash with #0 meta_window_place at ../src/core/place.c:883 #1 place_window_if_needed at ../src/core/constraints.c:562 #2 meta_window_constrain at ../src/core/constraints.c:310 #3 meta_window_move_resize_internal at ../src/core/window.c:3869 #4 meta_window_force_placement at ../src/core/window.c:2120 #5 xdg_toplevel_set_maximized at ../src/wayland/meta-wayland-xdg-shell.c:429 #6 ffi_call_unix64 at ../src/x86/unix64.S:105 #7 ffi_call_int at ../src/x86/ffi64.c:672 #8 wl_closure_invoke at ../src/connection.c:1025 #9 wl_client_connection_data at ../src/wayland-server.c:437 The fix for this is to make sure that the viewports are updated and pointers constrained synchronously, i.e. the main thread will wait until after the input thread is done constraining before continuing. Related: https://bugzilla.redhat.com/show_bug.cgi?id=2147502 Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2711>
This commit is contained in:
parent
eb7abdacd8
commit
1645171d4b
@ -3623,17 +3623,31 @@ ensure_pointer_onscreen (MetaSeatImpl *seat_impl)
|
|||||||
coords.x, coords.y, NULL);
|
coords.x, coords.y, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
MetaViewportInfo *viewports;
|
||||||
|
GMutex mutex;
|
||||||
|
GCond cond;
|
||||||
|
gboolean constrained;
|
||||||
|
} SetViewportsData;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
set_viewports (GTask *task)
|
set_viewports (GTask *task)
|
||||||
{
|
{
|
||||||
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
|
MetaSeatImpl *seat_impl = g_task_get_source_object (task);
|
||||||
MetaViewportInfo *viewports = g_task_get_task_data (task);
|
SetViewportsData *data = g_task_get_task_data (task);
|
||||||
|
MetaViewportInfo *viewports = data->viewports;
|
||||||
|
|
||||||
g_set_object (&seat_impl->viewports, viewports);
|
g_set_object (&seat_impl->viewports, viewports);
|
||||||
g_task_return_boolean (task, TRUE);
|
g_task_return_boolean (task, TRUE);
|
||||||
|
|
||||||
ensure_pointer_onscreen (seat_impl);
|
ensure_pointer_onscreen (seat_impl);
|
||||||
|
|
||||||
|
g_mutex_lock (&data->mutex);
|
||||||
|
data->constrained = TRUE;
|
||||||
|
g_cond_signal (&data->cond);
|
||||||
|
g_mutex_unlock (&data->mutex);
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3641,15 +3655,28 @@ void
|
|||||||
meta_seat_impl_set_viewports (MetaSeatImpl *seat_impl,
|
meta_seat_impl_set_viewports (MetaSeatImpl *seat_impl,
|
||||||
MetaViewportInfo *viewports)
|
MetaViewportInfo *viewports)
|
||||||
{
|
{
|
||||||
|
SetViewportsData data = {};
|
||||||
GTask *task;
|
GTask *task;
|
||||||
|
|
||||||
g_return_if_fail (META_IS_SEAT_IMPL (seat_impl));
|
g_return_if_fail (META_IS_SEAT_IMPL (seat_impl));
|
||||||
|
|
||||||
|
data.viewports = viewports;
|
||||||
|
g_mutex_init (&data.mutex);
|
||||||
|
g_cond_init (&data.cond);
|
||||||
|
|
||||||
task = g_task_new (seat_impl, NULL, NULL, NULL);
|
task = g_task_new (seat_impl, NULL, NULL, NULL);
|
||||||
g_task_set_task_data (task, g_object_ref (viewports), g_object_unref);
|
g_task_set_task_data (task, &data, NULL);
|
||||||
meta_seat_impl_run_input_task (seat_impl, task,
|
meta_seat_impl_run_input_task (seat_impl, task,
|
||||||
(GSourceFunc) set_viewports);
|
(GSourceFunc) set_viewports);
|
||||||
g_object_unref (task);
|
g_object_unref (task);
|
||||||
|
|
||||||
|
g_mutex_lock (&data.mutex);
|
||||||
|
while (!data.constrained)
|
||||||
|
g_cond_wait (&data.cond, &data.mutex);
|
||||||
|
g_mutex_unlock (&data.mutex);
|
||||||
|
|
||||||
|
g_mutex_clear (&data.mutex);
|
||||||
|
g_cond_clear (&data.cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaSeatImpl *
|
MetaSeatImpl *
|
||||||
|
Loading…
Reference in New Issue
Block a user