From b894c350080f5686a7c8bb7107001373da097b5f Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 25 May 2017 16:00:40 +0200 Subject: [PATCH] gtk: Make GtkPointerFocus refcounted In order to make it really sure the GtkPointerFocus is valid while being removed from a GtkWindow. --- gtk/gtkpointerfocus.c | 23 ++++++++++++++++++----- gtk/gtkpointerfocusprivate.h | 4 +++- gtk/gtkwindow.c | 20 ++++++++++++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/gtk/gtkpointerfocus.c b/gtk/gtkpointerfocus.c index 3a4026d3d5..cb484b8d34 100644 --- a/gtk/gtkpointerfocus.c +++ b/gtk/gtkpointerfocus.c @@ -39,6 +39,7 @@ gtk_pointer_focus_new (GtkWindow *toplevel, GtkPointerFocus *focus; focus = g_new0 (GtkPointerFocus, 1); + focus->ref_count = 1; focus->toplevel = toplevel; focus->device = device; focus->sequence = sequence; @@ -48,12 +49,24 @@ gtk_pointer_focus_new (GtkWindow *toplevel, return focus; } -void -gtk_pointer_focus_free (GtkPointerFocus *focus) +GtkPointerFocus * +gtk_pointer_focus_ref (GtkPointerFocus *focus) { - gtk_pointer_focus_set_target (focus, NULL); - gtk_pointer_focus_set_implicit_grab (focus, NULL); - g_free (focus); + focus->ref_count++; + return focus; +} + +void +gtk_pointer_focus_unref (GtkPointerFocus *focus) +{ + focus->ref_count--; + + if (focus->ref_count == 0) + { + gtk_pointer_focus_set_target (focus, NULL); + gtk_pointer_focus_set_implicit_grab (focus, NULL); + g_free (focus); + } } void diff --git a/gtk/gtkpointerfocusprivate.h b/gtk/gtkpointerfocusprivate.h index 5d5be955e0..c7ffd90f97 100644 --- a/gtk/gtkpointerfocusprivate.h +++ b/gtk/gtkpointerfocusprivate.h @@ -24,6 +24,7 @@ typedef struct _GtkPointerFocus GtkPointerFocus; struct _GtkPointerFocus { + gint ref_count; GdkDevice *device; GdkEventSequence *sequence; GtkWindow *toplevel; @@ -38,7 +39,8 @@ GtkPointerFocus * gtk_pointer_focus_new (GtkWindow *toplevel, GdkEventSequence *sequence, gdouble x, gdouble y); -void gtk_pointer_focus_free (GtkPointerFocus *focus); +GtkPointerFocus * gtk_pointer_focus_ref (GtkPointerFocus *focus); +void gtk_pointer_focus_unref (GtkPointerFocus *focus); void gtk_pointer_focus_set_coordinates (GtkPointerFocus *focus, gdouble x, diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 03046731cb..8e711004bb 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1689,9 +1689,9 @@ device_removed_cb (GdkSeat *seat, if (focus->device == device) { - gtk_pointer_focus_free (focus); window->priv->foci = g_list_delete_link (window->priv->foci, cur); + gtk_pointer_focus_unref (focus); } } } @@ -11275,7 +11275,7 @@ gtk_window_add_pointer_focus (GtkWindow *window, { GtkWindowPrivate *priv = window->priv; - priv->foci = g_list_prepend (priv->foci, focus); + priv->foci = g_list_prepend (priv->foci, gtk_pointer_focus_ref (focus)); } static void @@ -11283,8 +11283,14 @@ gtk_window_remove_pointer_focus (GtkWindow *window, GtkPointerFocus *focus) { GtkWindowPrivate *priv = window->priv; + GList *pos; + + pos = g_list_find (priv->foci, focus); + if (!pos) + return; priv->foci = g_list_remove (priv->foci, focus); + gtk_pointer_focus_unref (focus); } static GtkPointerFocus * @@ -11351,6 +11357,8 @@ gtk_window_update_pointer_focus (GtkWindow *window, focus = gtk_window_lookup_pointer_focus (window, device, sequence); if (focus) { + gtk_pointer_focus_ref (focus); + if (target) { gtk_pointer_focus_set_target (focus, target); @@ -11359,8 +11367,9 @@ gtk_window_update_pointer_focus (GtkWindow *window, else { gtk_window_remove_pointer_focus (window, focus); - gtk_pointer_focus_free (focus); } + + gtk_pointer_focus_unref (focus); } else if (target) { @@ -11383,17 +11392,20 @@ gtk_window_update_pointer_focus_on_state_change (GtkWindow *window, focus = cur->data; l = cur->next; + gtk_pointer_focus_ref (focus); + if (GTK_WIDGET (focus->toplevel) == widget) { /* Unmapping the toplevel, remove pointer focus */ gtk_window_remove_pointer_focus (window, focus); - gtk_pointer_focus_free (focus); } else if (focus->target == widget || gtk_widget_is_ancestor (focus->target, widget)) { gtk_pointer_focus_repick_target (focus); } + + gtk_pointer_focus_unref (focus); } }