[gtk+/gestures] Be careful about the list of event controllers



commit f97f1113bf0895fadffc9bcc9fc0fd1322a37ed6
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri May 9 15:53:27 2014 -0400

    Be careful about the list of event controllers
    
    We can end up with _gtk_widget_remove_controller getting called
    while we are iterating over the list in _gtk_widget_run_controllers.
    To avoid trouble, only mark the event controller as dead by
    setting data->controller to NULL, and defer the actual freeing
    and list manipulation to the loop in _gtk_widget_run_controllers.
    Update other places that operate on controllers to handle
    data->controller being NULL.

 gtk/gtkwidget.c |   32 +++++++++++++++++++++-----------
 1 files changed, 21 insertions(+), 11 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 99cacca..35dfd94 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -7223,7 +7223,8 @@ _gtk_widget_get_controllers_evmask (GtkWidget *widget)
   for (l = priv->event_controllers; l; l = l->next)
     {
       data = l->data;
-      evmask |= gtk_event_controller_get_event_mask (GTK_EVENT_CONTROLLER (data->controller));
+      if (data->controller)
+        evmask |= gtk_event_controller_get_event_mask (GTK_EVENT_CONTROLLER (data->controller));
     }
 
   return evmask;
@@ -7242,12 +7243,21 @@ _gtk_widget_run_controllers (GtkWidget           *widget,
   priv = widget->priv;
   g_object_ref (widget);
 
-  for (l = priv->event_controllers; l; l = l->next)
+  l = priv->event_controllers;
+  while (l != NULL)
     {
+      GList *next = l->next;
       data = l->data;
 
-      if (phase == data->phase)
+      if (data->controller == NULL)
+        {
+          priv->event_controllers = g_list_delete_link (priv->event_controllers, l);
+          g_free (data);
+        }
+      else if (data->phase == phase)
         handled |= gtk_event_controller_handle_event (data->controller, event);
+
+      l = next;
     }
 
   g_object_unref (widget);
@@ -11714,6 +11724,7 @@ gtk_widget_dispose (GObject *object)
 {
   GtkWidget *widget = GTK_WIDGET (object);
   GtkWidgetPrivate *priv = widget->priv;
+  GList *l;
 
   if (priv->parent)
     gtk_container_remove (GTK_CONTAINER (priv->parent), widget);
@@ -11736,11 +11747,14 @@ gtk_widget_dispose (GObject *object)
   while (priv->attached_windows)
     gtk_window_set_attached_to (priv->attached_windows->data, NULL);
 
-  while (priv->event_controllers)
+  for (l = priv->event_controllers; l; l = l->next)
     {
-      EventControllerData *data = priv->event_controllers->data;
-      _gtk_widget_remove_controller (widget, data->controller);
+      EventControllerData *data = l->data;
+      if (data->controller)
+        _gtk_widget_remove_controller (widget, data->controller);
     }
+  g_list_free_full (priv->event_controllers, g_free);
+  priv->event_controllers = NULL;
 
   G_OBJECT_CLASS (gtk_widget_parent_class)->dispose (object);
 }
@@ -16771,19 +16785,15 @@ _gtk_widget_remove_controller (GtkWidget          *widget,
                                GtkEventController *controller)
 {
   EventControllerData *data;
-  GtkWidgetPrivate *priv;
 
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
 
-  priv = widget->priv;
   data = _gtk_widget_has_controller (widget, controller);
 
   if (!data)
     return;
 
-  priv->event_controllers = g_list_remove (priv->event_controllers, data);
-
   if (g_signal_handler_is_connected (widget, data->grab_notify_id))
     g_signal_handler_disconnect (widget, data->grab_notify_id);
 
@@ -16791,5 +16801,5 @@ _gtk_widget_remove_controller (GtkWidget          *widget,
   g_signal_handler_disconnect (data->controller, data->sequence_state_changed_id);
   gtk_event_controller_reset (GTK_EVENT_CONTROLLER (data->controller));
   g_object_unref (data->controller);
-  g_free (data);
+  data->controller = NULL;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]