[gtk+] GtkMenuTrackerItem: add an internal 'visible' flag



commit 2b1aa12f01f382652a3b6b9c7e51959dde194143
Author: Ryan Lortie <desrt desrt ca>
Date:   Sat Jan 4 02:25:43 2014 -0500

    GtkMenuTrackerItem: add an internal 'visible' flag
    
    Add an internal API for checking if a GtkMenuTrackerItem is visible,
    along with a signal for reporting changes in that flag.  The item will
    become invisible in situations according to the new hidden-when=''
    attribute, which can be set to 'action-disabled' or 'action-missing'.
    
    This new flag doesn't actually do anything yet, and none of the
    consumers of GtkMenuTracker do anything with it (nor should they).  A
    followup patch will address the issue.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=688421

 gtk/gtkmenutrackeritem.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkmenutrackeritem.h |    4 ++
 2 files changed, 94 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c
index d81c9de..fdda28f 100644
--- a/gtk/gtkmenutrackeritem.c
+++ b/gtk/gtkmenutrackeritem.c
@@ -97,8 +97,14 @@ struct _GtkMenuTrackerItem
   guint toggled : 1;
   guint submenu_shown : 1;
   guint submenu_requested : 1;
+  guint hidden_when : 2;
+  guint is_visible : 1;
 };
 
+#define HIDDEN_NEVER         0
+#define HIDDEN_WHEN_MISSING  1
+#define HIDDEN_WHEN_DISABLED 2
+
 enum {
   PROP_0,
   PROP_IS_SEPARATOR,
@@ -115,6 +121,7 @@ enum {
 };
 
 static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS];
+static guint gtk_menu_tracker_visibility_changed_signal;
 
 static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface);
 G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
@@ -239,6 +246,46 @@ gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
     g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
 
   g_object_class_install_properties (class, N_PROPS, gtk_menu_tracker_item_pspecs);
+
+  gtk_menu_tracker_visibility_changed_signal = g_signal_new ("visibility-changed", 
GTK_TYPE_MENU_TRACKER_ITEM,
+                                                             G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
+                                                             g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE,
+                                                             1, G_TYPE_BOOLEAN);
+}
+
+/* This syncs up the visibility for the hidden-when='' case.  We call it
+ * from the action observer functions on changes to the action group and
+ * on initialisation (via the action observer functions that are invoked
+ * at that time).
+ */
+static void
+gtk_menu_tracker_item_update_visibility (GtkMenuTrackerItem *self)
+{
+  gboolean visible;
+
+  switch (self->hidden_when)
+    {
+    case HIDDEN_NEVER:
+      visible = TRUE;
+      break;
+
+    case HIDDEN_WHEN_MISSING:
+      visible = self->can_activate;
+      break;
+
+    case HIDDEN_WHEN_DISABLED:
+      visible = self->sensitive;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  if (visible != self->is_visible)
+    {
+      self->is_visible = visible;
+      g_signal_emit (self, gtk_menu_tracker_visibility_changed_signal, 0, visible);
+    }
 }
 
 static void
@@ -294,6 +341,12 @@ gtk_menu_tracker_item_action_added (GtkActionObserver   *observer,
 
   if (action_target)
     g_variant_unref (action_target);
+
+  /* In case of hidden-when='', we want to Wait until after refreshing
+   * all of the properties to emit the signal that will cause the
+   * tracker to expose us (to prevent too much thrashing).
+   */
+  gtk_menu_tracker_item_update_visibility (self);
 }
 
 static void
@@ -313,6 +366,8 @@ gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver   *observer,
   self->sensitive = enabled;
 
   g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
+
+  gtk_menu_tracker_item_update_visibility (self);
 }
 
 static void
@@ -368,6 +423,11 @@ gtk_menu_tracker_item_action_removed (GtkActionObserver   *observer,
   self->toggled = FALSE;
   self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL;
 
+  /* Backwards from adding: we want to remove ourselves from the menu
+   * -before- thrashing the properties.
+   */
+  gtk_menu_tracker_item_update_visibility (self);
+
   g_object_freeze_notify (G_OBJECT (self));
 
   if (was_sensitive)
@@ -413,6 +473,7 @@ _gtk_menu_tracker_item_new (GtkActionObservable *observable,
 {
   GtkMenuTrackerItem *self;
   const gchar *action_name;
+  const gchar *hidden_when;
 
   g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL);
   g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
@@ -423,6 +484,23 @@ _gtk_menu_tracker_item_new (GtkActionObservable *observable,
   self->observable = g_object_ref (observable);
   self->is_separator = is_separator;
 
+  if (!is_separator && g_menu_item_get_attribute (self->item, "hidden-when", "&s", &hidden_when))
+    {
+      if (g_str_equal (hidden_when, "action-disabled"))
+        self->hidden_when = HIDDEN_WHEN_DISABLED;
+      else if (g_str_equal (hidden_when, "action-missing"))
+        self->hidden_when = HIDDEN_WHEN_MISSING;
+
+      /* Ignore other values -- this code may be running in context of a
+       * desktop shell or the like and should not spew criticals due to
+       * application bugs...
+       *
+       * Note: if we just set a hidden-when state, but don't get the
+       * action_name below then our visibility will be FALSE forever.
+       * That's to be expected since the action is missing...
+       */
+    }
+
   if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name))
     {
       GActionGroup *group = G_ACTION_GROUP (observable);
@@ -803,3 +881,15 @@ gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
   else
     gtk_menu_tracker_item_set_submenu_shown (self, shown);
 }
+
+gboolean
+_gtk_menu_tracker_item_is_visible (GtkMenuTrackerItem *self)
+{
+  return self->is_visible;
+}
+
+gboolean
+_gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self)
+{
+  return self->hidden_when != HIDDEN_NEVER;
+}
diff --git a/gtk/gtkmenutrackeritem.h b/gtk/gtkmenutrackeritem.h
index 9db30eb..03709d6 100644
--- a/gtk/gtkmenutrackeritem.h
+++ b/gtk/gtkmenutrackeritem.h
@@ -72,6 +72,10 @@ GMenuModel *           _gtk_menu_tracker_item_get_submenu               (GtkMenu
 
 gchar *                _gtk_menu_tracker_item_get_submenu_namespace     (GtkMenuTrackerItem *self);
 
+gboolean               _gtk_menu_tracker_item_may_disappear             (GtkMenuTrackerItem *self);
+
+gboolean               _gtk_menu_tracker_item_is_visible                (GtkMenuTrackerItem *self);
+
 gboolean                gtk_menu_tracker_item_get_should_request_show   (GtkMenuTrackerItem *self);
 
 void                    gtk_menu_tracker_item_activated                 (GtkMenuTrackerItem *self);


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