[gtk/stack-fixes] stack switcher: Allow alternative models



commit 0a77f5436be074cde01bde3f3b7f7e00153855a5
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Feb 10 13:18:11 2019 -0500

    stack switcher: Allow alternative models

 gtk/gtkstackswitcher.c | 176 +++++++++++++++++++++++++++++--------------------
 gtk/gtkstackswitcher.h |  13 ++++
 2 files changed, 118 insertions(+), 71 deletions(-)
---
diff --git a/gtk/gtkstackswitcher.c b/gtk/gtkstackswitcher.c
index 354983cf71..8f6eda7f7c 100644
--- a/gtk/gtkstackswitcher.c
+++ b/gtk/gtkstackswitcher.c
@@ -66,8 +66,10 @@
 typedef struct _GtkStackSwitcherPrivate GtkStackSwitcherPrivate;
 struct _GtkStackSwitcherPrivate
 {
-  GtkStack *stack;
   GtkSelectionModel *pages;
+  GtkStackSwitcherDataFunc data_func;
+  gpointer user_data;
+  GDestroyNotify destroy_notify;
   GHashTable *buttons;
   GtkWidget *switch_button;
   guint switch_timer;
@@ -167,24 +169,22 @@ rebuild_child (GtkWidget   *self,
 
 static void
 update_button (GtkStackSwitcher *self,
-               GtkWidget        *widget,
+               GObject          *item,
                GtkWidget        *button)
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (self);
+  gboolean visible;
   gchar *title;
   gchar *icon_name;
   gboolean needs_attention;
   GtkStyleContext *context;
 
-  g_object_get (gtk_stack_get_page (priv->stack, widget),
-                "title", &title,
-                "icon-name", &icon_name,
-                "needs-attention", &needs_attention,
-                NULL);
+  priv->data_func (item, priv->user_data, &visible, &title, &icon_name, &needs_attention);
 
+g_print ("update button: visible %d title %s\n", visible, title);
   rebuild_child (button, icon_name, title);
 
-  gtk_widget_set_visible (button, gtk_widget_get_visible (widget) && (title != NULL || icon_name != NULL));
+  gtk_widget_set_visible (button, visible && (title != NULL || icon_name != NULL));
 
   context = gtk_widget_get_style_context (button);
   if (needs_attention)
@@ -197,29 +197,15 @@ update_button (GtkStackSwitcher *self,
 }
 
 static void
-on_visible_updated (GtkWidget        *widget,
-                    GParamSpec       *pspec,
-                    GtkStackSwitcher *self)
-{
-  GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (self);
-  GtkWidget *button;
-
-  button = g_hash_table_lookup (priv->buttons, widget);
-  update_button (self, widget, button);
-}
-
-static void
-on_page_updated (GtkStackPage     *page,
+on_item_changed (GObject          *item,
                  GParamSpec       *pspec,
                  GtkStackSwitcher *self)
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (self);
-  GtkWidget *widget;
   GtkWidget *button;
 
-  widget = gtk_stack_page_get_child (page);
-  button = g_hash_table_lookup (priv->buttons, widget);
-  update_button (self, widget, button);
+  button = g_hash_table_lookup (priv->buttons, item);
+  update_button (self, item, button);
 }
 
 static void
@@ -308,15 +294,15 @@ add_child (guint             position,
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (self);
   GtkWidget *button;
-  GtkWidget *widget;
+  GObject *item;
   gboolean selected;
-  GtkStackPage *page;
 
+g_print ("add child\n");
   button = gtk_toggle_button_new ();
   gtk_widget_set_focus_on_click (button, FALSE);
 
-  widget = g_list_model_get_item (G_LIST_MODEL (priv->pages), position);
-  update_button (self, widget, button);
+  item = g_list_model_get_item (G_LIST_MODEL (priv->pages), position);
+  update_button (self, item, button);
 
   gtk_container_add (GTK_CONTAINER (self), button);
 
@@ -324,14 +310,12 @@ add_child (guint             position,
   selected = gtk_selection_model_is_selected (priv->pages, position);
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), selected);
 
-  page = gtk_stack_get_page (GTK_STACK (priv->stack), widget);
   g_signal_connect (button, "notify::active", G_CALLBACK (on_button_toggled), self);
-  g_signal_connect (widget, "notify::visible", G_CALLBACK (on_visible_updated), self);
-  g_signal_connect (page, "notify", G_CALLBACK (on_page_updated), self);
+  g_signal_connect (item, "notify", G_CALLBACK (on_item_changed), self);
 
-  g_hash_table_insert (priv->buttons, widget, button);
+  g_hash_table_insert (priv->buttons, item, button);
 
-  g_object_unref (widget);
+  g_object_unref (item);
 }
 
 static void
@@ -349,21 +333,15 @@ clear_switcher (GtkStackSwitcher *self)
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (self);
   GHashTableIter iter;
-  GtkWidget *widget;
   GtkWidget *button;
+  GObject *item;
 
   g_hash_table_iter_init (&iter, priv->buttons);
-  while (g_hash_table_iter_next (&iter, (gpointer *)&widget, (gpointer *)&button))
+  while (g_hash_table_iter_next (&iter, (gpointer *)&item, (gpointer *)&button))
     {
       gtk_container_remove (GTK_CONTAINER (self), button);
       g_hash_table_iter_remove (&iter);
-      if (priv->stack)
-        {
-          GtkStackPage *page = gtk_stack_get_page (priv->stack, widget);
-          if (page)
-            g_signal_handlers_disconnect_by_func (page, on_page_updated, self);
-          g_signal_handlers_disconnect_by_func (widget, on_visible_updated, self);
-        }
+      g_signal_handlers_disconnect_by_func (item, on_item_changed, self);
     }
 }
 
@@ -389,21 +367,15 @@ selection_changed_cb (GtkSelectionModel *model,
 
   for (i = position; i < position + n_items; i++)
     {
-      GtkWidget *child;
+      GObject *item;
       GtkWidget *button;
       gboolean selected;
 
-      child = g_list_model_get_item (G_LIST_MODEL (priv->pages), i);
-      if (child == NULL)
-        continue;
-
-      button = g_hash_table_lookup (priv->buttons, child);
-      if (button)
-        {
-          selected = gtk_selection_model_is_selected (priv->pages, i);
-          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), selected);
-        }
-      g_object_unref (child);
+      item = g_list_model_get_item (G_LIST_MODEL (priv->pages), i);
+      button = g_hash_table_lookup (priv->buttons, item);
+      selected = gtk_selection_model_is_selected (priv->pages, i);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), selected);
+      g_object_unref (item);
     }
 }
 
@@ -426,34 +398,91 @@ connect_stack_signals (GtkStackSwitcher *switcher)
 }
 
 static void
-set_stack (GtkStackSwitcher *switcher,
-           GtkStack         *stack)
+stack_data_func (GObject *item,
+                 gpointer data,
+                 gboolean *visible,
+                 char    **title,
+                 char    **icon_name,
+                 gboolean *needs_attention)
+{
+  GtkStack *stack = data;
+  GtkWidget *widget = GTK_WIDGET (item);
+  GtkStackPage *page = gtk_stack_get_page (stack, widget);
+
+  if (page)
+    {
+      *visible = gtk_widget_get_visible (widget);
+      g_object_get (page,
+                    "title", title,
+                    "icon-name", icon_name,
+                    "needs-attention", needs_attention,
+                    NULL);
+    }
+  else
+    {
+      *visible = FALSE;
+      *title = g_strdup ("*deceased*");
+      *icon_name = NULL;
+      *needs_attention = FALSE;
+    }
+}
+
+static void
+set_model (GtkStackSwitcher *switcher,
+           GtkSelectionModel *model,
+           GtkStackSwitcherDataFunc data_func,
+           gpointer                 data,
+           GDestroyNotify           destroy_notify)
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (switcher);
 
-  if (stack)
+  if (model)
     {
-      priv->stack = g_object_ref (stack);
-      priv->pages = gtk_stack_get_pages (stack);
+      priv->pages = g_object_ref (model),
+      priv->data_func = data_func;
+      priv->user_data = data;
+      priv->destroy_notify = destroy_notify;
       populate_switcher (switcher);
       connect_stack_signals (switcher);
     }
 }
 
 static void
-unset_stack (GtkStackSwitcher *switcher)
+unset_model (GtkStackSwitcher *switcher)
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (switcher);
 
-  if (priv->stack)
+  if (priv->pages)
     {
       disconnect_stack_signals (switcher);
       clear_switcher (switcher);
-      g_clear_object (&priv->stack);
+      priv->data_func = NULL;
+      if (priv->destroy_notify)
+        priv->destroy_notify (priv->user_data);
+      priv->destroy_notify = NULL;
+      priv->user_data = NULL;
       g_clear_object (&priv->pages);
     }
 }
 
+void
+gtk_stack_switcher_set_model (GtkStackSwitcher         *switcher,
+                              GtkSelectionModel        *model,
+                              GtkStackSwitcherDataFunc  data_func,
+                              gpointer                  data,
+                              GDestroyNotify            destroy)
+{
+  GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (switcher);
+
+  if (priv->pages == model)
+    return;
+
+  unset_model (switcher);
+  set_model (switcher, model, data_func, data, destroy);
+
+  gtk_widget_queue_resize (GTK_WIDGET (switcher));
+}
+
 /**
  * gtk_stack_switcher_set_stack:
  * @switcher: a #GtkStackSwitcher
@@ -466,15 +495,19 @@ gtk_stack_switcher_set_stack (GtkStackSwitcher *switcher,
                               GtkStack         *stack)
 {
   GtkStackSwitcherPrivate *priv = gtk_stack_switcher_get_instance_private (switcher);
+  GtkSelectionModel *model;
 
   g_return_if_fail (GTK_IS_STACK_SWITCHER (switcher));
   g_return_if_fail (GTK_IS_STACK (stack) || stack == NULL);
 
-  if (priv->stack == stack)
+  if (priv->user_data == (gpointer) stack)
     return;
 
-  unset_stack (switcher);
-  set_stack (switcher, stack);
+  unset_model (switcher);
+
+  model = gtk_stack_get_pages (stack);
+  set_model (switcher, model, stack_data_func, g_object_ref (stack), g_object_unref);
+  g_object_unref (model);
 
   gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
@@ -498,7 +531,10 @@ gtk_stack_switcher_get_stack (GtkStackSwitcher *switcher)
   g_return_val_if_fail (GTK_IS_STACK_SWITCHER (switcher), NULL);
 
   priv = gtk_stack_switcher_get_instance_private (switcher);
-  return priv->stack;
+  if (priv->data_func == stack_data_func)
+    return GTK_STACK (priv->user_data);
+
+  return NULL;
 }
 
 static void
@@ -508,13 +544,11 @@ gtk_stack_switcher_get_property (GObject      *object,
                                  GParamSpec   *pspec)
 {
   GtkStackSwitcher *switcher = GTK_STACK_SWITCHER (object);
-  GtkStackSwitcherPrivate *priv;
 
-  priv = gtk_stack_switcher_get_instance_private (switcher);
   switch (prop_id)
     {
     case PROP_STACK:
-      g_value_set_object (value, priv->stack);
+      g_value_set_object (value, gtk_stack_switcher_get_stack (switcher));
       break;
 
     default:
@@ -549,7 +583,7 @@ gtk_stack_switcher_dispose (GObject *object)
   GtkStackSwitcher *switcher = GTK_STACK_SWITCHER (object);
 
   remove_switch_timer (switcher);
-  unset_stack (switcher);
+  unset_model (switcher);
 
   G_OBJECT_CLASS (gtk_stack_switcher_parent_class)->dispose (object);
 }
diff --git a/gtk/gtkstackswitcher.h b/gtk/gtkstackswitcher.h
index d11ed46bb6..78b609bddf 100644
--- a/gtk/gtkstackswitcher.h
+++ b/gtk/gtkstackswitcher.h
@@ -55,6 +55,13 @@ struct _GtkStackSwitcherClass
   void (*_gtk_reserved4) (void);
 };
 
+typedef void (* GtkStackSwitcherDataFunc) (GObject    *item,
+                                           gpointer    data,
+                                           gboolean   *visible,
+                                           char      **title,
+                                           char      **icon_name,
+                                           gboolean   *needs_attention);
+
 GDK_AVAILABLE_IN_ALL
 GType        gtk_stack_switcher_get_type          (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_ALL
@@ -65,6 +72,12 @@ void         gtk_stack_switcher_set_stack         (GtkStackSwitcher *switcher,
 GDK_AVAILABLE_IN_ALL
 GtkStack *   gtk_stack_switcher_get_stack         (GtkStackSwitcher *switcher);
 
+GDK_AVAILABLE_IN_ALL
+void         gtk_stack_switcher_set_model         (GtkStackSwitcher         *switcher,
+                                                   GtkSelectionModel        *model,
+                                                   GtkStackSwitcherDataFunc  data_func,
+                                                   gpointer                  data,
+                                                   GDestroyNotify            destroy);
 G_END_DECLS
 
 #endif /* __GTK_STACK_SWITCHER_H__ */


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