[rhythmbox] button-bar: watch for model changes properly



commit bf2a1bec0b48b8a0c77f6a5d9877e2bfc872eb4b
Author: Jonathan Matthew <jonathan d14n org>
Date:   Wed Jun 26 23:24:33 2013 +1000

    button-bar: watch for model changes properly
    
    The top level GMenu doesn't notify of changes to its nested children, so we
    need to watch all of the GMenu instances that make up the button bar.  On
    changes we disconnect and reconnect all the signal handlers.
    
    The buttons and separators added to the grid need to be shown, otherwise items
    added after the bar is shown initially don't appear.
    
    Adding a separator at the start of the bar creates an ugly effect that sort of
    looks like an extension of the GtkPaned handle, so we don't do that.

 widgets/rb-button-bar.c |   60 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 45 insertions(+), 15 deletions(-)
---
diff --git a/widgets/rb-button-bar.c b/widgets/rb-button-bar.c
index b8578e0..6bf73d2 100644
--- a/widgets/rb-button-bar.c
+++ b/widgets/rb-button-bar.c
@@ -35,12 +35,14 @@
 static void rb_button_bar_class_init (RBButtonBarClass *klass);
 static void rb_button_bar_init (RBButtonBar *bar);
 
+static void build_button_bar (RBButtonBar *bar);
+
 struct _RBButtonBarPrivate
 {
        GObject *target;
        GtkSizeGroup *size_group;
        GMenuModel *model;
-       guint item_change_id;
+       GHashTable *handlers;
 
        int position;
 };
@@ -54,12 +56,30 @@ enum {
 };
 
 static void
+clear_handlers (RBButtonBar *bar)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_hash_table_iter_init (&iter, bar->priv->handlers);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               gulong id = (gulong)key;
+               g_signal_handler_disconnect (value, id);
+       }
+
+       g_hash_table_remove_all (bar->priv->handlers);
+}
+
+static void
 clear_button_bar (RBButtonBar *bar)
 {
        GList *c, *l;
 
        c = gtk_container_get_children (GTK_CONTAINER (bar));
        for (l = c; l != NULL; l = l->next) {
+               if (GTK_IS_LABEL (l->data))
+                       continue;
+
                gtk_size_group_remove_widget (bar->priv->size_group, l->data);
                gtk_container_remove (GTK_CONTAINER (bar), l->data);
        }
@@ -76,10 +96,22 @@ signal_button_clicked_cb (GtkButton *button, RBButtonBar *bar)
        g_signal_emit (bar->priv->target, signal_id, 0);
 }
 
+static void
+items_changed_cb (GMenuModel *model, int position, int added, int removed, RBButtonBar *bar)
+{
+       clear_handlers (bar);
+       clear_button_bar (bar);
+       build_button_bar (bar);
+}
+
 static gboolean
 append_menu (RBButtonBar *bar, GMenuModel *menu, gboolean need_separator)
 {
        int i;
+       gulong id;
+
+       id = g_signal_connect (menu, "items-changed", G_CALLBACK (items_changed_cb), bar);
+       g_hash_table_insert (bar->priv->handlers, (gpointer)id, g_object_ref (menu));
 
        for (i = 0; i < g_menu_model_get_n_items (menu); i++) {
                char *label_text;
@@ -101,8 +133,11 @@ append_menu (RBButtonBar *bar, GMenuModel *menu, gboolean need_separator)
                if (need_separator) {
                        GtkWidget *sep;
 
-                       sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
-                       gtk_grid_attach (GTK_GRID (bar), sep, bar->priv->position++, 0, 1, 1);
+                       if (bar->priv->position > 0) {
+                               sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+                               gtk_widget_show (sep);
+                               gtk_grid_attach (GTK_GRID (bar), sep, bar->priv->position++, 0, 1, 1);
+                       }
 
                        need_separator = FALSE;
                }
@@ -180,6 +215,7 @@ append_menu (RBButtonBar *bar, GMenuModel *menu, gboolean need_separator)
                        g_object_set_data_full (G_OBJECT (button), "rb-accel", accel, (GDestroyNotify) 
g_free);
                }
 
+               gtk_widget_show_all (button);
                gtk_size_group_add_widget (bar->priv->size_group, button);
                gtk_grid_attach (GTK_GRID (bar), button, bar->priv->position++, 0, 1, 1);
 
@@ -198,15 +234,10 @@ build_button_bar (RBButtonBar *bar)
 
        waste = gtk_label_new ("");
        gtk_widget_set_hexpand (waste, TRUE);
+       gtk_widget_show (waste);
        gtk_grid_attach (GTK_GRID (bar), waste, bar->priv->position++, 0, 1, 1);
 }
 
-static void
-items_changed_cb (GMenuModel *model, int position, int added, int removed, RBButtonBar *bar)
-{
-       clear_button_bar (bar);
-       build_button_bar (bar);
-}
 
 static void
 impl_constructed (GObject *object)
@@ -222,7 +253,8 @@ impl_constructed (GObject *object)
 
        bar->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 
-       bar->priv->item_change_id = g_signal_connect (bar->priv->model, "items-changed", G_CALLBACK 
(items_changed_cb), bar);
+       bar->priv->handlers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+
        build_button_bar (bar);
 }
 
@@ -230,11 +262,9 @@ static void
 impl_dispose (GObject *object)
 {
        RBButtonBar *bar = RB_BUTTON_BAR (object);
-       
-       if (bar->priv->model != NULL) {
-               g_signal_handler_disconnect (bar->priv->model, bar->priv->item_change_id);
-               g_clear_object (&bar->priv->model);
-       }
+
+       clear_handlers (bar);
+       g_clear_object (&bar->priv->model);
        G_OBJECT_CLASS (rb_button_bar_parent_class)->dispose (object);
 }
 


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