From 44741e1b7730ab6a52dbd979901768d6e7eb33c7 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 26 Aug 2020 07:24:54 -0400 Subject: [PATCH 1/3] widget: Avoid a crash in crossing event handling We need to make sure that the crossing data stays alive until we are done handling it, so take references on all the widgets in it. --- gtk/gtkwidget.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 9f538f42ea..e8106fca84 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4376,12 +4376,30 @@ gtk_widget_handle_crossing (GtkWidget *widget, g_object_ref (widget); + if (crossing->old_target) + g_object_ref (crossing->old_target); + if (crossing->new_target) + g_object_ref (crossing->new_target); + if (crossing->old_descendent) + g_object_ref (crossing->old_descendent); + if (crossing->new_descendent) + g_object_ref (crossing->new_descendent); + for (l = priv->event_controllers; l; l = l->next) { GtkEventController *controller = l->data; gtk_event_controller_handle_crossing (controller, crossing, x, y); } + if (crossing->old_target) + g_object_unref (crossing->old_target); + if (crossing->new_target) + g_object_unref (crossing->new_target); + if (crossing->old_descendent) + g_object_unref (crossing->old_descendent); + if (crossing->new_descendent) + g_object_unref (crossing->new_descendent); + g_object_unref (widget); } From b6eb85ee72c228fd5f9657dce7ac7d352be57ad3 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 26 Aug 2020 07:26:01 -0400 Subject: [PATCH 2/3] main: Avoid a crash with crossing event handling We are reusing the GtkCrossingData struct for multiple calls here, so we need to make sure that the targets stay alive from beginning to end. Fixes: #3090 --- gtk/gtkmain.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index a517a0e6e7..23c61cd270 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1335,9 +1335,9 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel, crossing.type = crossing_type; crossing.mode = mode; - crossing.old_target = old_target; + crossing.old_target = old_target ? g_object_ref (old_target) : NULL; crossing.old_descendent = NULL; - crossing.new_target = new_target; + crossing.new_target = new_target ? g_object_ref (new_target) : NULL; crossing.new_descendent = NULL; crossing.drop = drop; @@ -1417,6 +1417,9 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel, gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE); } + g_clear_object (&crossing.old_target); + g_clear_object (&crossing.new_target); + gtk_widget_stack_clear (&target_array); } From 74a452df6c04c6c9bff82d96c63c90c4f0ad47fd Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 26 Aug 2020 09:01:48 -0400 Subject: [PATCH 3/3] Make gdk_surface_get_device_position return a boolean A year ago, we make this function not return the child surface anymore. But the information whether the device is actually over the surface is still useful, and we should not loose it. --- gdk/gdksurface.c | 25 ++++++++++++++++--------- gdk/gdksurface.h | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index cf471d49c6..f89061a002 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1627,8 +1627,10 @@ gdk_surface_constrain_size (GdkGeometry *geometry, * Obtains the current device position in doubles and modifier state. * The position is given in coordinates relative to the upper left * corner of @surface. + * + * Return: %TRUE if the device is over the surface **/ -void +gboolean gdk_surface_get_device_position (GdkSurface *surface, GdkDevice *device, double *x, @@ -1637,17 +1639,20 @@ gdk_surface_get_device_position (GdkSurface *surface, { double tmp_x, tmp_y; GdkModifierType tmp_mask; + gboolean ret; - g_return_if_fail (GDK_IS_SURFACE (surface)); - g_return_if_fail (GDK_IS_DEVICE (device)); - g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD); + g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE); + g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE); + g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, FALSE); - tmp_x = tmp_y = 0; + tmp_x = 0; + tmp_y = 0; tmp_mask = 0; - GDK_SURFACE_GET_CLASS (surface)->get_device_state (surface, - device, - &tmp_x, &tmp_y, - &tmp_mask); + + ret = GDK_SURFACE_GET_CLASS (surface)->get_device_state (surface, + device, + &tmp_x, &tmp_y, + &tmp_mask); if (x) *x = tmp_x; @@ -1655,6 +1660,8 @@ gdk_surface_get_device_position (GdkSurface *surface, *y = tmp_y; if (mask) *mask = tmp_mask; + + return ret; } /** diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h index 9b1613147f..a03b02a4e3 100644 --- a/gdk/gdksurface.h +++ b/gdk/gdksurface.h @@ -187,7 +187,7 @@ GDK_AVAILABLE_IN_ALL int gdk_surface_get_scale_factor (GdkSurface *surface); GDK_AVAILABLE_IN_ALL -void gdk_surface_get_device_position (GdkSurface *surface, +gboolean gdk_surface_get_device_position (GdkSurface *surface, GdkDevice *device, double *x, double *y,