gtkmenutracker: Update from GTK+
This commit is contained in:
parent
f2912bad95
commit
9d683f4767
@ -69,12 +69,14 @@ struct _GtkMenuTracker
|
|||||||
|
|
||||||
struct _GtkMenuTrackerSection
|
struct _GtkMenuTrackerSection
|
||||||
{
|
{
|
||||||
GMenuModel *model;
|
gpointer model; /* may be a GtkMenuTrackerItem or a GMenuModel */
|
||||||
GSList *items;
|
GSList *items;
|
||||||
gchar *action_namespace;
|
gchar *action_namespace;
|
||||||
|
|
||||||
|
guint separator_label : 1;
|
||||||
guint with_separators : 1;
|
guint with_separators : 1;
|
||||||
guint has_separator : 1;
|
guint has_separator : 1;
|
||||||
|
guint is_fake : 1;
|
||||||
|
|
||||||
gulong handler;
|
gulong handler;
|
||||||
};
|
};
|
||||||
@ -82,13 +84,14 @@ struct _GtkMenuTrackerSection
|
|||||||
static GtkMenuTrackerSection * gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
|
static GtkMenuTrackerSection * gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
|
||||||
GMenuModel *model,
|
GMenuModel *model,
|
||||||
gboolean with_separators,
|
gboolean with_separators,
|
||||||
|
gboolean separator_label,
|
||||||
gint offset,
|
gint offset,
|
||||||
const gchar *action_namespace);
|
const gchar *action_namespace);
|
||||||
static void gtk_menu_tracker_section_free (GtkMenuTrackerSection *section);
|
static void gtk_menu_tracker_section_free (GtkMenuTrackerSection *section);
|
||||||
|
|
||||||
static GtkMenuTrackerSection *
|
static GtkMenuTrackerSection *
|
||||||
gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section,
|
gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section,
|
||||||
GMenuModel *model,
|
gpointer model,
|
||||||
gint *offset)
|
gint *offset)
|
||||||
{
|
{
|
||||||
GSList *item;
|
GSList *item;
|
||||||
@ -139,8 +142,8 @@ gtk_menu_tracker_section_find_model (GtkMenuTrackerSection *section,
|
|||||||
*
|
*
|
||||||
* could_have_separator is true in two situations:
|
* could_have_separator is true in two situations:
|
||||||
*
|
*
|
||||||
* - our parent section had with_separators defined and we are not the
|
* - our parent section had with_separators defined and there are items
|
||||||
* first section (ie: we should add a separator if we have content in
|
* before us (ie: we should add a separator if we have content in
|
||||||
* order to divide us from the items above)
|
* order to divide us from the items above)
|
||||||
*
|
*
|
||||||
* - if we had a 'label' attribute set for this section
|
* - if we had a 'label' attribute set for this section
|
||||||
@ -175,11 +178,13 @@ gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
|
|||||||
{
|
{
|
||||||
gboolean could_have_separator;
|
gboolean could_have_separator;
|
||||||
|
|
||||||
could_have_separator = (section->with_separators && i > 0) ||
|
could_have_separator = (section->with_separators && n_items > 0) || subsection->separator_label;
|
||||||
g_menu_model_get_item_attribute (section->model, i, "label", "s", NULL);
|
|
||||||
|
|
||||||
|
/* Only pass the parent_model and parent_index in case they may be used to create the separator. */
|
||||||
n_items += gtk_menu_tracker_section_sync_separators (subsection, tracker, offset + n_items,
|
n_items += gtk_menu_tracker_section_sync_separators (subsection, tracker, offset + n_items,
|
||||||
could_have_separator, section->model, i);
|
could_have_separator,
|
||||||
|
could_have_separator ? section->model : NULL,
|
||||||
|
could_have_separator ? i : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
n_items++;
|
n_items++;
|
||||||
@ -187,7 +192,7 @@ gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
should_have_separator = could_have_separator && n_items != 0;
|
should_have_separator = !section->is_fake && could_have_separator && n_items != 0;
|
||||||
|
|
||||||
if (should_have_separator > section->has_separator)
|
if (should_have_separator > section->has_separator)
|
||||||
{
|
{
|
||||||
@ -212,6 +217,38 @@ gtk_menu_tracker_section_sync_separators (GtkMenuTrackerSection *section,
|
|||||||
return n_items;
|
return n_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_menu_tracker_item_visibility_changed (GtkMenuTrackerItem *item,
|
||||||
|
gboolean is_now_visible,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkMenuTracker *tracker = user_data;
|
||||||
|
GtkMenuTrackerSection *section;
|
||||||
|
gboolean was_visible;
|
||||||
|
gint offset = 0;
|
||||||
|
|
||||||
|
/* remember: the item is our model */
|
||||||
|
section = gtk_menu_tracker_section_find_model (tracker->toplevel, item, &offset);
|
||||||
|
|
||||||
|
was_visible = section->items != NULL;
|
||||||
|
|
||||||
|
if (is_now_visible == was_visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_now_visible)
|
||||||
|
{
|
||||||
|
section->items = g_slist_prepend (NULL, NULL);
|
||||||
|
(* tracker->insert_func) (section->model, offset, tracker->user_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
section->items = g_slist_delete_link (section->items, section->items);
|
||||||
|
(* tracker->remove_func) (offset, tracker->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
gtk_menu_tracker_section_measure (GtkMenuTrackerSection *section)
|
gtk_menu_tracker_section_measure (GtkMenuTrackerSection *section)
|
||||||
{
|
{
|
||||||
@ -275,6 +312,10 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
|
|||||||
{
|
{
|
||||||
GtkMenuTrackerSection *subsection;
|
GtkMenuTrackerSection *subsection;
|
||||||
gchar *action_namespace = NULL;
|
gchar *action_namespace = NULL;
|
||||||
|
gboolean has_label;
|
||||||
|
|
||||||
|
has_label = g_menu_model_get_item_attribute (model, position + n_items,
|
||||||
|
G_MENU_ATTRIBUTE_LABEL, "s", NULL);
|
||||||
|
|
||||||
g_menu_model_get_item_attribute (model, position + n_items,
|
g_menu_model_get_item_attribute (model, position + n_items,
|
||||||
G_MENU_ATTRIBUTE_ACTION_NAMESPACE, "s", &action_namespace);
|
G_MENU_ATTRIBUTE_ACTION_NAMESPACE, "s", &action_namespace);
|
||||||
@ -284,11 +325,11 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
|
|||||||
gchar *namespace;
|
gchar *namespace;
|
||||||
|
|
||||||
namespace = g_strjoin (".", section->action_namespace, action_namespace, NULL);
|
namespace = g_strjoin (".", section->action_namespace, action_namespace, NULL);
|
||||||
subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, namespace);
|
subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, has_label, offset, namespace);
|
||||||
g_free (namespace);
|
g_free (namespace);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, offset, section->action_namespace);
|
subsection = gtk_menu_tracker_section_new (tracker, submenu, FALSE, has_label, offset, action_namespace);
|
||||||
|
|
||||||
*change_point = g_slist_prepend (*change_point, subsection);
|
*change_point = g_slist_prepend (*change_point, subsection);
|
||||||
g_free (action_namespace);
|
g_free (action_namespace);
|
||||||
@ -300,10 +341,61 @@ gtk_menu_tracker_add_items (GtkMenuTracker *tracker,
|
|||||||
|
|
||||||
item = _gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
|
item = _gtk_menu_tracker_item_new (tracker->observable, model, position + n_items,
|
||||||
section->action_namespace, FALSE);
|
section->action_namespace, FALSE);
|
||||||
(* tracker->insert_func) (item, offset, tracker->user_data);
|
|
||||||
g_object_unref (item);
|
|
||||||
|
|
||||||
*change_point = g_slist_prepend (*change_point, NULL);
|
/* In the case that the item may disappear we handle that by
|
||||||
|
* treating the item that we just created as being its own
|
||||||
|
* subsection. This happens as so:
|
||||||
|
*
|
||||||
|
* - the subsection is created without the possibility of
|
||||||
|
* showing a separator
|
||||||
|
*
|
||||||
|
* - the subsection will have either 0 or 1 item in it at all
|
||||||
|
* times: either the shown item or not (in the case it is
|
||||||
|
* hidden)
|
||||||
|
*
|
||||||
|
* - the created item acts as the "model" for this section
|
||||||
|
* and we use its "visiblity-changed" signal in the same
|
||||||
|
* way that we use the "items-changed" signal from a real
|
||||||
|
* GMenuModel
|
||||||
|
*
|
||||||
|
* We almost never use the '->model' stored in the section for
|
||||||
|
* anything other than lookups and for dropped the ref and
|
||||||
|
* disconnecting the signal when we destroy the menu, and we
|
||||||
|
* need to do exactly those things in this case as well.
|
||||||
|
*
|
||||||
|
* The only other thing that '->model' is used for is in the
|
||||||
|
* case that we want to show a separator, but we will never do
|
||||||
|
* that because separators are not shown for this fake section.
|
||||||
|
*/
|
||||||
|
if (_gtk_menu_tracker_item_may_disappear (item))
|
||||||
|
{
|
||||||
|
GtkMenuTrackerSection *fake_section;
|
||||||
|
|
||||||
|
fake_section = g_slice_new0 (GtkMenuTrackerSection);
|
||||||
|
fake_section->is_fake = TRUE;
|
||||||
|
fake_section->model = g_object_ref (item);
|
||||||
|
fake_section->handler = g_signal_connect (item, "visibility-changed",
|
||||||
|
G_CALLBACK (gtk_menu_tracker_item_visibility_changed),
|
||||||
|
tracker);
|
||||||
|
*change_point = g_slist_prepend (*change_point, fake_section);
|
||||||
|
|
||||||
|
if (_gtk_menu_tracker_item_is_visible (item))
|
||||||
|
{
|
||||||
|
(* tracker->insert_func) (item, offset, tracker->user_data);
|
||||||
|
fake_section->items = g_slist_prepend (NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* In the normal case, we store NULL in the linked list.
|
||||||
|
* The measurement and lookup code count NULL always as
|
||||||
|
* exactly 1: an item that will always be there.
|
||||||
|
*/
|
||||||
|
(* tracker->insert_func) (item, offset, tracker->user_data);
|
||||||
|
*change_point = g_slist_prepend (*change_point, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,6 +467,7 @@ static GtkMenuTrackerSection *
|
|||||||
gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
|
gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
|
||||||
GMenuModel *model,
|
GMenuModel *model,
|
||||||
gboolean with_separators,
|
gboolean with_separators,
|
||||||
|
gboolean separator_label,
|
||||||
gint offset,
|
gint offset,
|
||||||
const gchar *action_namespace)
|
const gchar *action_namespace)
|
||||||
{
|
{
|
||||||
@ -384,6 +477,7 @@ gtk_menu_tracker_section_new (GtkMenuTracker *tracker,
|
|||||||
section->model = g_object_ref (model);
|
section->model = g_object_ref (model);
|
||||||
section->with_separators = with_separators;
|
section->with_separators = with_separators;
|
||||||
section->action_namespace = g_strdup (action_namespace);
|
section->action_namespace = g_strdup (action_namespace);
|
||||||
|
section->separator_label = separator_label;
|
||||||
|
|
||||||
gtk_menu_tracker_add_items (tracker, section, §ion->items, offset, model, 0, g_menu_model_get_n_items (model));
|
gtk_menu_tracker_add_items (tracker, section, §ion->items, offset, model, 0, g_menu_model_get_n_items (model));
|
||||||
section->handler = g_signal_connect (model, "items-changed", G_CALLBACK (gtk_menu_tracker_model_changed), tracker);
|
section->handler = g_signal_connect (model, "items-changed", G_CALLBACK (gtk_menu_tracker_model_changed), tracker);
|
||||||
@ -459,7 +553,7 @@ gtk_menu_tracker_new (GtkActionObservable *observable,
|
|||||||
tracker->remove_func = remove_func;
|
tracker->remove_func = remove_func;
|
||||||
tracker->user_data = user_data;
|
tracker->user_data = user_data;
|
||||||
|
|
||||||
tracker->toplevel = gtk_menu_tracker_section_new (tracker, model, with_separators, 0, action_namespace);
|
tracker->toplevel = gtk_menu_tracker_section_new (tracker, model, with_separators, FALSE, 0, action_namespace);
|
||||||
gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
|
gtk_menu_tracker_section_sync_separators (tracker->toplevel, tracker, 0, FALSE, NULL, 0);
|
||||||
|
|
||||||
return tracker;
|
return tracker;
|
||||||
@ -471,11 +565,20 @@ gtk_menu_tracker_new_for_item_submenu (GtkMenuTrackerItem *item,
|
|||||||
GtkMenuTrackerRemoveFunc remove_func,
|
GtkMenuTrackerRemoveFunc remove_func,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
return gtk_menu_tracker_new (_gtk_menu_tracker_item_get_observable (item),
|
GtkMenuTracker *tracker;
|
||||||
_gtk_menu_tracker_item_get_submenu (item),
|
GMenuModel *submenu;
|
||||||
TRUE,
|
gchar *namespace;
|
||||||
_gtk_menu_tracker_item_get_submenu_namespace (item),
|
|
||||||
insert_func, remove_func, user_data);
|
submenu = _gtk_menu_tracker_item_get_submenu (item);
|
||||||
|
namespace = _gtk_menu_tracker_item_get_submenu_namespace (item);
|
||||||
|
|
||||||
|
tracker = gtk_menu_tracker_new (_gtk_menu_tracker_item_get_observable (item), submenu,
|
||||||
|
TRUE, namespace, insert_func, remove_func, user_data);
|
||||||
|
|
||||||
|
g_object_unref (submenu);
|
||||||
|
g_free (namespace);
|
||||||
|
|
||||||
|
return tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*< private >
|
/*< private >
|
||||||
|
@ -20,6 +20,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "gtkmenutrackeritem.h"
|
#include "gtkmenutrackeritem.h"
|
||||||
|
#include "gtkactionmuxer.h"
|
||||||
|
|
||||||
|
#include "gtkactionmuxer.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:gtkmenutrackeritem
|
* SECTION:gtkmenutrackeritem
|
||||||
@ -81,6 +86,7 @@ struct _GtkMenuTrackerItem
|
|||||||
|
|
||||||
GtkActionObservable *observable;
|
GtkActionObservable *observable;
|
||||||
gchar *action_namespace;
|
gchar *action_namespace;
|
||||||
|
gchar *action_and_target;
|
||||||
GMenuItem *item;
|
GMenuItem *item;
|
||||||
GtkMenuTrackerItemRole role : 4;
|
GtkMenuTrackerItemRole role : 4;
|
||||||
guint is_separator : 1;
|
guint is_separator : 1;
|
||||||
@ -89,8 +95,14 @@ struct _GtkMenuTrackerItem
|
|||||||
guint toggled : 1;
|
guint toggled : 1;
|
||||||
guint submenu_shown : 1;
|
guint submenu_shown : 1;
|
||||||
guint submenu_requested : 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 {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_IS_SEPARATOR,
|
PROP_IS_SEPARATOR,
|
||||||
@ -107,6 +119,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static GParamSpec *gtk_menu_tracker_item_pspecs[N_PROPS];
|
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);
|
static void gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface);
|
||||||
G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
|
G_DEFINE_TYPE_WITH_CODE (GtkMenuTrackerItem, gtk_menu_tracker_item, G_TYPE_OBJECT,
|
||||||
@ -231,6 +244,46 @@ gtk_menu_tracker_item_class_init (GtkMenuTrackerItemClass *class)
|
|||||||
g_param_spec_boolean ("submenu-shown", "", "", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
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);
|
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
|
static void
|
||||||
@ -286,6 +339,12 @@ gtk_menu_tracker_item_action_added (GtkActionObserver *observer,
|
|||||||
|
|
||||||
if (action_target)
|
if (action_target)
|
||||||
g_variant_unref (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
|
static void
|
||||||
@ -305,6 +364,8 @@ gtk_menu_tracker_item_action_enabled_changed (GtkActionObserver *observer,
|
|||||||
self->sensitive = enabled;
|
self->sensitive = enabled;
|
||||||
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
|
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
|
||||||
|
|
||||||
|
gtk_menu_tracker_item_update_visibility (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -345,33 +406,52 @@ gtk_menu_tracker_item_action_removed (GtkActionObserver *observer,
|
|||||||
const gchar *action_name)
|
const gchar *action_name)
|
||||||
{
|
{
|
||||||
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
|
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
|
||||||
|
gboolean was_sensitive, was_toggled;
|
||||||
|
GtkMenuTrackerItemRole old_role;
|
||||||
|
|
||||||
if (!self->can_activate)
|
if (!self->can_activate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
was_sensitive = self->sensitive;
|
||||||
|
was_toggled = self->toggled;
|
||||||
|
old_role = self->role;
|
||||||
|
|
||||||
|
self->can_activate = FALSE;
|
||||||
|
self->sensitive = FALSE;
|
||||||
|
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));
|
g_object_freeze_notify (G_OBJECT (self));
|
||||||
|
|
||||||
if (self->sensitive)
|
if (was_sensitive)
|
||||||
{
|
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
|
||||||
self->sensitive = FALSE;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->toggled)
|
if (was_toggled)
|
||||||
{
|
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
|
||||||
self->toggled = FALSE;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
|
if (old_role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
|
||||||
{
|
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
|
||||||
self->role = GTK_MENU_TRACKER_ITEM_ROLE_NORMAL;
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_thaw_notify (G_OBJECT (self));
|
g_object_thaw_notify (G_OBJECT (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_menu_tracker_item_primary_accel_changed (GtkActionObserver *observer,
|
||||||
|
GtkActionObservable *observable,
|
||||||
|
const gchar *action_name,
|
||||||
|
const gchar *action_and_target)
|
||||||
|
{
|
||||||
|
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
|
||||||
|
|
||||||
|
if (g_str_equal (action_and_target, self->action_and_target))
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ACCEL]);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface)
|
gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface)
|
||||||
{
|
{
|
||||||
@ -379,6 +459,7 @@ gtk_menu_tracker_item_init_observer_iface (GtkActionObserverInterface *iface)
|
|||||||
iface->action_enabled_changed = gtk_menu_tracker_item_action_enabled_changed;
|
iface->action_enabled_changed = gtk_menu_tracker_item_action_enabled_changed;
|
||||||
iface->action_state_changed = gtk_menu_tracker_item_action_state_changed;
|
iface->action_state_changed = gtk_menu_tracker_item_action_state_changed;
|
||||||
iface->action_removed = gtk_menu_tracker_item_action_removed;
|
iface->action_removed = gtk_menu_tracker_item_action_removed;
|
||||||
|
iface->primary_accel_changed = gtk_menu_tracker_item_primary_accel_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkMenuTrackerItem *
|
GtkMenuTrackerItem *
|
||||||
@ -390,6 +471,7 @@ _gtk_menu_tracker_item_new (GtkActionObservable *observable,
|
|||||||
{
|
{
|
||||||
GtkMenuTrackerItem *self;
|
GtkMenuTrackerItem *self;
|
||||||
const gchar *action_name;
|
const gchar *action_name;
|
||||||
|
const gchar *hidden_when;
|
||||||
|
|
||||||
g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL);
|
g_return_val_if_fail (GTK_IS_ACTION_OBSERVABLE (observable), NULL);
|
||||||
g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
|
g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
|
||||||
@ -400,30 +482,45 @@ _gtk_menu_tracker_item_new (GtkActionObservable *observable,
|
|||||||
self->observable = g_object_ref (observable);
|
self->observable = g_object_ref (observable);
|
||||||
self->is_separator = is_separator;
|
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))
|
if (!is_separator && g_menu_item_get_attribute (self->item, "action", "&s", &action_name))
|
||||||
{
|
{
|
||||||
GActionGroup *group = G_ACTION_GROUP (observable);
|
GActionGroup *group = G_ACTION_GROUP (observable);
|
||||||
const GVariantType *parameter_type;
|
const GVariantType *parameter_type;
|
||||||
|
GVariant *target;
|
||||||
gboolean enabled;
|
gboolean enabled;
|
||||||
GVariant *state;
|
GVariant *state;
|
||||||
gboolean found;
|
gboolean found;
|
||||||
|
|
||||||
|
target = g_menu_item_get_attribute_value (self->item, "target", NULL);
|
||||||
|
|
||||||
|
self->action_and_target = gtk_print_action_and_target (action_namespace, action_name, target);
|
||||||
|
|
||||||
|
if (target)
|
||||||
|
g_variant_unref (target);
|
||||||
|
|
||||||
|
action_name = strrchr (self->action_and_target, '|') + 1;
|
||||||
|
|
||||||
state = NULL;
|
state = NULL;
|
||||||
|
|
||||||
if (action_namespace)
|
gtk_action_observable_register_observer (self->observable, action_name, GTK_ACTION_OBSERVER (self));
|
||||||
{
|
found = g_action_group_query_action (group, action_name, &enabled, ¶meter_type, NULL, NULL, &state);
|
||||||
gchar *full_action;
|
|
||||||
|
|
||||||
full_action = g_strjoin (".", action_namespace, action_name, NULL);
|
|
||||||
gtk_action_observable_register_observer (self->observable, full_action, GTK_ACTION_OBSERVER (self));
|
|
||||||
found = g_action_group_query_action (group, full_action, &enabled, ¶meter_type, NULL, NULL, &state);
|
|
||||||
g_free (full_action);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gtk_action_observable_register_observer (self->observable, action_name, GTK_ACTION_OBSERVER (self));
|
|
||||||
found = g_action_group_query_action (group, action_name, &enabled, ¶meter_type, NULL, NULL, &state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
gtk_menu_tracker_item_action_added (GTK_ACTION_OBSERVER (self), observable, NULL, parameter_type, enabled, state);
|
gtk_menu_tracker_item_action_added (GTK_ACTION_OBSERVER (self), observable, NULL, parameter_type, enabled, state);
|
||||||
@ -542,11 +639,18 @@ gtk_menu_tracker_item_get_toggled (GtkMenuTrackerItem *self)
|
|||||||
const gchar *
|
const gchar *
|
||||||
gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self)
|
gtk_menu_tracker_item_get_accel (GtkMenuTrackerItem *self)
|
||||||
{
|
{
|
||||||
const gchar *accel = NULL;
|
const gchar *accel;
|
||||||
|
|
||||||
g_menu_item_get_attribute (self->item, "accel", "&s", &accel);
|
if (!self->action_and_target)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return accel;
|
if (g_menu_item_get_attribute (self->item, "accel", "&s", &accel))
|
||||||
|
return accel;
|
||||||
|
|
||||||
|
if (!GTK_IS_ACTION_MUXER (self->observable))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return gtk_action_muxer_get_primary_accel (GTK_ACTION_MUXER (self->observable), self->action_and_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
GMenuModel *
|
GMenuModel *
|
||||||
@ -605,19 +709,10 @@ gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self)
|
|||||||
if (!self->can_activate)
|
if (!self->can_activate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_menu_item_get_attribute (self->item, G_MENU_ATTRIBUTE_ACTION, "&s", &action_name);
|
action_name = strrchr (self->action_and_target, '|') + 1;
|
||||||
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
|
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
|
||||||
|
|
||||||
if (self->action_namespace)
|
g_action_group_activate_action (G_ACTION_GROUP (self->observable), action_name, action_target);
|
||||||
{
|
|
||||||
gchar *full_action;
|
|
||||||
|
|
||||||
full_action = g_strjoin (".", self->action_namespace, action_name, NULL);
|
|
||||||
g_action_group_activate_action (G_ACTION_GROUP (self->observable), full_action, action_target);
|
|
||||||
g_free (full_action);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
g_action_group_activate_action (G_ACTION_GROUP (self->observable), action_name, action_target);
|
|
||||||
|
|
||||||
if (action_target)
|
if (action_target)
|
||||||
g_variant_unref (action_target);
|
g_variant_unref (action_target);
|
||||||
@ -784,3 +879,15 @@ gtk_menu_tracker_item_request_submenu_shown (GtkMenuTrackerItem *self,
|
|||||||
else
|
else
|
||||||
gtk_menu_tracker_item_set_submenu_shown (self, shown);
|
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;
|
||||||
|
}
|
||||||
|
@ -72,6 +72,10 @@ GMenuModel * _gtk_menu_tracker_item_get_submenu (GtkMenu
|
|||||||
|
|
||||||
gchar * _gtk_menu_tracker_item_get_submenu_namespace (GtkMenuTrackerItem *self);
|
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);
|
gboolean gtk_menu_tracker_item_get_should_request_show (GtkMenuTrackerItem *self);
|
||||||
|
|
||||||
void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self);
|
void gtk_menu_tracker_item_activated (GtkMenuTrackerItem *self);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user