[gtk+/wip/gtkmenutrackeritem: 3/12] GtkMenuTracker: become a proper GObject



commit ee4178e89e79fd6db4a5393b46cbe5b4d5dd0e6c
Author: Ryan Lortie <desrt desrt ca>
Date:   Wed May 8 10:20:34 2013 -0400

    GtkMenuTracker: become a proper GObject
    
    Turn GtkMenuTracker into a GObject with "insert" and "remove" signals
    for the sake of accessibility from language bindings.

 gtk/gtkmenushell.c   |    4 +-
 gtk/gtkmenutracker.c |  120 ++++++++++++++++++++++++++++++++++++++++----------
 gtk/gtkmenutracker.h |   15 ++++++-
 3 files changed, 113 insertions(+), 26 deletions(-)
---
diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c
index 6c1d386..1778e16 100644
--- a/gtk/gtkmenushell.c
+++ b/gtk/gtkmenushell.c
@@ -533,7 +533,7 @@ gtk_menu_shell_dispose (GObject *object)
 {
   GtkMenuShell *menu_shell = GTK_MENU_SHELL (object);
 
-  g_clear_pointer (&menu_shell->priv->tracker, gtk_menu_tracker_free);
+  g_clear_object (&menu_shell->priv->tracker);
   gtk_menu_shell_deactivate (menu_shell);
 
   G_OBJECT_CLASS (gtk_menu_shell_parent_class)->dispose (object);
@@ -2225,7 +2225,7 @@ gtk_menu_shell_bind_model (GtkMenuShell *menu_shell,
 
   muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (menu_shell));
 
-  g_clear_pointer (&menu_shell->priv->tracker, gtk_menu_tracker_free);
+  g_clear_object (&menu_shell->priv->tracker);
 
   while (menu_shell->priv->children)
     gtk_container_remove (GTK_CONTAINER (menu_shell), menu_shell->priv->children->data);
diff --git a/gtk/gtkmenutracker.c b/gtk/gtkmenutracker.c
index 764b93c..d5f55f0 100644
--- a/gtk/gtkmenutracker.c
+++ b/gtk/gtkmenutracker.c
@@ -27,6 +27,8 @@ typedef struct _GtkMenuTrackerSection GtkMenuTrackerSection;
 
 struct _GtkMenuTracker
 {
+  GObject                   parent_instance;
+
   GActionObservable        *observable;
   GtkMenuTrackerInsertFunc  insert_func;
   GtkMenuTrackerRemoveFunc  remove_func;
@@ -35,6 +37,8 @@ struct _GtkMenuTracker
   GtkMenuTrackerSection    *toplevel;
 };
 
+typedef GObjectClass GtkMenuTrackerClass;
+
 struct _GtkMenuTrackerSection
 {
   GMenuModel *model;
@@ -47,6 +51,8 @@ struct _GtkMenuTrackerSection
   gulong      handler;
 };
 
+G_DEFINE_TYPE (GtkMenuTracker, gtk_menu_tracker, G_TYPE_OBJECT)
+
 static GtkMenuTrackerSection *  gtk_menu_tracker_section_new    (GtkMenuTracker        *tracker,
                                                                  GMenuModel            *model,
                                                                  gboolean               with_separators,
@@ -54,6 +60,38 @@ static GtkMenuTrackerSection *  gtk_menu_tracker_section_new    (GtkMenuTracker
                                                                  const gchar           *action_namespace);
 static void                    gtk_menu_tracker_section_free    (GtkMenuTrackerSection *section);
 
+static guint insert_signal, remove_signal;
+
+static void
+gtk_menu_tracker_emit_insert (GtkMenuTracker *tracker,
+                              GMenuModel     *model,
+                              gint            model_index,
+                              const gchar    *action_namespace,
+                              gboolean        is_separator,
+                              gint            offset)
+{
+  GtkMenuTrackerItem *item;
+
+  item = gtk_menu_tracker_item_new (tracker->observable, model, model_index, action_namespace, is_separator);
+
+  if (tracker->insert_func)
+    (* tracker->insert_func) (item, offset, tracker->user_data);
+  else
+    g_signal_emit (tracker, insert_signal, 0, item, offset);
+
+  g_object_unref (item);
+}
+
+static void
+gtk_menu_tracker_emit_remove (GtkMenuTracker     *tracker,
+                              gint                offset)
+{
+  if (tracker->remove_func)
+    (* tracker->remove_func) (offset, tracker->user_data);
+  else
+    g_signal_emit (tracker, remove_signal, 0, offset);
+}
+
 static GtkMenuTrackerSection *
 gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section,
                                      GMenuModel            *model,
@@ -159,19 +197,13 @@ gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
 
   if (should_have_separator > section->has_separator)
     {
-      /* Add a separator */
-      GtkMenuTrackerItem *item;
-
-      item = gtk_menu_tracker_item_new (tracker->observable, parent_model, parent_index, NULL, TRUE);
-      (* tracker->insert_func) (item, offset, tracker->user_data);
-      g_object_unref (item);
-
+      gtk_menu_tracker_emit_insert (tracker, parent_model, parent_index, NULL, TRUE, offset);
       section->has_separator = TRUE;
     }
   else if (should_have_separator < section->has_separator)
     {
       /* Remove a separator */
-      (* tracker->remove_func) (offset, tracker->user_data);
+      gtk_menu_tracker_emit_remove (tracker, offset);
       section->has_separator = FALSE;
     }
 
@@ -220,7 +252,7 @@ gtk_menu_tracker_remove_items (GtkMenuTracker  *tracker,
       gtk_menu_tracker_section_free (subsection);
 
       while (n--)
-        (* tracker->remove_func) (offset, tracker->user_data);
+        gtk_menu_tracker_emit_remove (tracker, offset);
     }
 }
 
@@ -264,13 +296,7 @@ gtk_menu_tracker_add_items (GtkMenuTracker         *tracker,
         }
       else
         {
-          GtkMenuTrackerItem *item;
-
-          item = gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
-                                            section->action_namespace, FALSE);
-          (* tracker->insert_func) (item, offset, tracker->user_data);
-          g_object_unref (item);
-
+          gtk_menu_tracker_emit_insert (tracker, model, position + n_items, section->action_namespace, 
FALSE, offset);
           *change_point = g_slist_prepend (*change_point, NULL);
         }
     }
@@ -359,6 +385,33 @@ gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
   return section;
 }
 
+static void
+gtk_menu_tracker_finalize (GObject *object)
+{
+  GtkMenuTracker *tracker = GTK_MENU_TRACKER (object);
+
+  gtk_menu_tracker_section_free (tracker->toplevel);
+  g_object_unref (tracker->observable);
+
+  G_OBJECT_CLASS (gtk_menu_tracker_parent_class)->finalize (object);
+}
+
+static void
+gtk_menu_tracker_init (GtkMenuTracker *tracker)
+{
+}
+
+static void
+gtk_menu_tracker_class_init (GtkMenuTrackerClass *class)
+{
+  class->finalize = gtk_menu_tracker_finalize;
+
+  insert_signal = g_signal_new ("insert", GTK_TYPE_MENU_TRACKER, G_SIGNAL_RUN_FIRST,
+                                0, NULL, NULL, NULL, G_TYPE_NONE, 2, GTK_TYPE_MENU_TRACKER_ITEM, G_TYPE_INT);
+  remove_signal = g_signal_new ("remove", GTK_TYPE_MENU_TRACKER, G_SIGNAL_RUN_FIRST,
+                                0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
 /*< private >
  * gtk_menu_tracker_new:
  * @model: the model to flatten
@@ -409,6 +462,10 @@ gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
  * When using #GtkMenuTracker there is no need to hold onto @model or
  * monitor it for changes.  The model will be unreffed when
  * gtk_menu_tracker_free() is called.
+ *
+ * As a bindings-friendly alternative to using this function, you can
+ * create the tracker with g_object_new(), connect to the "insert" and
+ * "remove" signals and then call gtk_menu_tracker_setup().
  */
 GtkMenuTracker *
 gtk_menu_tracker_new (GActionObservable        *observable,
@@ -421,7 +478,7 @@ gtk_menu_tracker_new (GActionObservable        *observable,
 {
   GtkMenuTracker *tracker;
 
-  tracker = g_slice_new (GtkMenuTracker);
+  tracker = g_object_new (GTK_TYPE_MENU_TRACKER, NULL);
   tracker->observable = g_object_ref (observable);
   tracker->insert_func = insert_func;
   tracker->remove_func = remove_func;
@@ -434,15 +491,32 @@ gtk_menu_tracker_new (GActionObservable        *observable,
 }
 
 /*< private >
- * gtk_menu_tracker_free:
+ * gtk_menu_tracker_setup:
  * @tracker: a #GtkMenuTracker
+ * @observable: the #GActionObservable to use
+ * @model: the model to flatten
+ * @with_separators: if the toplevel should have separators (ie: TRUE
+ *   for menus, FALSE for menubars)
+ * @action_namespace: the passed-in action namespace
+ *
+ * Sets up the tracker.
+ *
+ * This will typically cause many 'insert' signals to be emitted.
  *
- * Frees the tracker, ...
+ * You can only call this once and you may not call this after using
+ * gtk_menu_tracker_new().
  */
 void
-gtk_menu_tracker_free (GtkMenuTracker *tracker)
+gtk_menu_tracker_setup (GtkMenuTracker    *tracker,
+                        GActionObservable *observable,
+                        GMenuModel        *model,
+                        gboolean           with_separators,
+                        const gchar       *action_namespace)
 {
-  gtk_menu_tracker_section_free (tracker->toplevel);
-  g_object_unref (tracker->observable);
-  g_slice_free (GtkMenuTracker, tracker);
+  g_return_if_fail (GTK_IS_MENU_TRACKER (tracker));
+  g_return_if_fail (tracker->toplevel == NULL);
+
+  tracker->observable = g_object_ref (observable);
+  tracker->toplevel = gtk_menu_tracker_section_new (tracker, model, with_separators, 0, action_namespace);
+  gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
 }
diff --git a/gtk/gtkmenutracker.h b/gtk/gtkmenutracker.h
index 51c5a7b..c679fa8 100644
--- a/gtk/gtkmenutracker.h
+++ b/gtk/gtkmenutracker.h
@@ -24,8 +24,17 @@
 
 #include <gtk/gtkmenutrackeritem.h>
 
+#define GTK_TYPE_MENU_TRACKER                               (gtk_menu_tracker_get_type ())
+#define GTK_MENU_TRACKER(inst)                              (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+                                                             GTK_TYPE_MENU_TRACKER, GtkMenuTracker))
+#define GTK_IS_MENU_TRACKER(inst)                           (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+                                                             GTK_TYPE_MENU_TRACKER))
+
 typedef struct _GtkMenuTracker GtkMenuTracker;
 
+G_GNUC_INTERNAL
+GType                   gtk_menu_tracker_get_type                       (void) G_GNUC_CONST;
+
 typedef void         (* GtkMenuTrackerInsertFunc)       (GtkMenuTrackerItem       *item,
                                                          gint                      position,
                                                          gpointer                  user_data);
@@ -44,6 +53,10 @@ GtkMenuTracker *        gtk_menu_tracker_new            (GActionObservable
                                                          gpointer                  user_data);
 
 G_GNUC_INTERNAL
-void                    gtk_menu_tracker_free           (GtkMenuTracker           *tracker);
+void                    gtk_menu_tracker_setup          (GtkMenuTracker           *tracker,
+                                                         GActionObservable        *observer,
+                                                         GMenuModel               *model,
+                                                         gboolean                  with_separators,
+                                                         const gchar              *action_namespace);
 
 #endif /* __GTK_MENU_TRACKER_H__ */


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