diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2009-01-23 15:15:28 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2009-01-23 15:15:28 +0000 |
commit | bb72b647f6a40831a46fb731a5929831d95c2b29 (patch) | |
tree | 5bd4a577f50fe360a0cd9a06ada7adc65c3c5508 /gtk/gtkmenuitem.c | |
parent | acd40c45f781a84c297be34d5d18f7681e78d46e (diff) | |
download | gtk+-bb72b647f6a40831a46fb731a5929831d95c2b29.tar.gz |
i Bug 560228 – Add "action-controller" property to GtkWidgetClass
Rework the way actions and proxies interact, to make the
interaction less ad hoc, more extensible, and better suited
for support in GUI builders like glade.
To be used as a proxy, a widget must now implement the
GtkActivatable interface, and GtkActivatable implementations
are responsible for syncing their appearance with the action
and for activating the action.
All the widgets that are commonly used as proxies implement
GtkActivatable now.
Patch by Tristan van Berkom.
* gtk/gtkactivatable.[hc]: The GtkActivatable interface.
* gtk/gtkbutton.c:
* gtk/gtktogglebutton.c:
* gtk/gtktoolitem.c:
* gtk/gtktoolbutton.c:
* gtk/gtktoggletoolbutton.c:
* gtk/gtkmenuitem.c:
* gtk/gtkcheckmenuitem.c:
* gtk/gtkimagemenuitem.c:
* gtk/gtkradiomenuitem.c:
* gtk/gtkrecentchooserprivate.h:
* gtk/gtkrecentchooser.c:
* gtk/gtkrecentchooserdefault.c:
* gtk/gtkrecentchoosermenu.c: Implement GtkActivatable.
* gtk/gtkaction.[hc]: Move appearance synchronization to
GtkActivatable implementations.
* gtk/gtkradioaction.c:
* gtk/gtkrecentaction.c:
* gtk/gtktoggleaction.c:
* gtk/gtkactiongroup.c: Adapt.
* gtk/gtk.h: Include gtkactivatable.h
* gtk/gtk.symbols: Add new functions
svn path=/trunk/; revision=22195
Diffstat (limited to 'gtk/gtkmenuitem.c')
-rw-r--r-- | gtk/gtkmenuitem.c | 238 |
1 files changed, 226 insertions, 12 deletions
diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index 9d8b33523f..03eca0bf59 100644 --- a/gtk/gtkmenuitem.c +++ b/gtk/gtkmenuitem.c @@ -37,9 +37,16 @@ #include "gtkseparatormenuitem.h" #include "gtkprivate.h" #include "gtkbuildable.h" +#include "gtkactivatable.h" #include "gtkintl.h" #include "gtkalias.h" + +typedef struct { + GtkAction *action; + gboolean use_action_appearance; +} GtkMenuItemPrivate; + enum { ACTIVATE, ACTIVATE_ITEM, @@ -54,10 +61,15 @@ enum { PROP_SUBMENU, PROP_ACCEL_PATH, PROP_LABEL, - PROP_USE_UNDERLINE + PROP_USE_UNDERLINE, + + /* activatable properties */ + PROP_ACTIVATABLE_RELATED_ACTION, + PROP_ACTIVATABLE_USE_ACTION_APPEARANCE }; +static void gtk_menu_item_dispose (GObject *object); static void gtk_menu_item_set_property (GObject *object, guint prop_id, const GValue *value, @@ -85,6 +97,7 @@ static void gtk_menu_item_parent_set (GtkWidget *widget, static void gtk_real_menu_item_select (GtkItem *item); static void gtk_real_menu_item_deselect (GtkItem *item); +static void gtk_real_menu_item_activate (GtkMenuItem *item); static void gtk_real_menu_item_activate_item (GtkMenuItem *item); static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item, gint *requisition); @@ -120,13 +133,30 @@ static void gtk_menu_item_buildable_add_child (GtkBuildable *buildab GObject *child, const gchar *type); +static void gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface); +static void gtk_menu_item_activatable_update (GtkActivatable *activatable, + GtkAction *action, + const gchar *property_name); +static void gtk_menu_item_activatable_reset (GtkActivatable *activatable, + GtkAction *action); +static void gtk_menu_item_set_related_action (GtkMenuItem *menu_item, + GtkAction *action); +static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item, + gboolean use_appearance); + + static guint menu_item_signals[LAST_SIGNAL] = { 0 }; static GtkBuildableIface *parent_buildable_iface; G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gtk_menu_item_buildable_interface_init)) + gtk_menu_item_buildable_interface_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, + gtk_menu_item_activatable_interface_init)) + +#define GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_MENU_ITEM, GtkMenuItemPrivate)) static void gtk_menu_item_class_init (GtkMenuItemClass *klass) @@ -137,6 +167,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); GtkItemClass *item_class = GTK_ITEM_CLASS (klass); + gobject_class->dispose = gtk_menu_item_dispose; gobject_class->set_property = gtk_menu_item_set_property; gobject_class->get_property = gtk_menu_item_get_property; @@ -157,15 +188,15 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) container_class->forall = gtk_menu_item_forall; - item_class->select = gtk_real_menu_item_select; - item_class->deselect = gtk_real_menu_item_deselect; + item_class->select = gtk_real_menu_item_select; + item_class->deselect = gtk_real_menu_item_deselect; - klass->activate = NULL; - klass->activate_item = gtk_real_menu_item_activate_item; - klass->toggle_size_request = gtk_real_menu_item_toggle_size_request; + klass->activate = gtk_real_menu_item_activate; + klass->activate_item = gtk_real_menu_item_activate_item; + klass->toggle_size_request = gtk_real_menu_item_toggle_size_request; klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate; - klass->set_label = gtk_real_menu_item_set_label; - klass->get_label = gtk_real_menu_item_get_label; + klass->set_label = gtk_real_menu_item_set_label; + klass->get_label = gtk_real_menu_item_get_label; klass->hide_on_activate = TRUE; @@ -288,6 +319,9 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) FALSE, GTK_PARAM_READWRITE)); + g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action"); + g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance"); + gtk_widget_class_install_style_property_parser (widget_class, g_param_spec_enum ("selected-shadow-type", "Selected Shadow Type", @@ -344,12 +378,19 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) P_("The minimum desired width of the menu item in characters"), 0, G_MAXINT, 12, GTK_PARAM_READABLE)); + + g_type_class_add_private (object_class, sizeof (GtkMenuItemPrivate)); } static void gtk_menu_item_init (GtkMenuItem *menu_item) { + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GTK_WIDGET_SET_FLAGS (menu_item, GTK_NO_WINDOW); + + priv->action = NULL; + priv->use_action_appearance = TRUE; menu_item->submenu = NULL; menu_item->toggle_size = 0; @@ -399,6 +440,22 @@ gtk_menu_item_new_with_mnemonic (const gchar *label) NULL); } +static void +gtk_menu_item_dispose (GObject *object) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (object); + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + + if (priv->action) + { + gtk_action_disconnect_accelerator (priv->action); + gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), NULL); + + priv->action = NULL; + } + G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object); +} + static void gtk_menu_item_set_property (GObject *object, guint prop_id, @@ -424,7 +481,12 @@ gtk_menu_item_set_property (GObject *object, case PROP_USE_UNDERLINE: gtk_menu_item_set_use_underline (menu_item, g_value_get_boolean (value)); break; - + case PROP_ACTIVATABLE_RELATED_ACTION: + gtk_menu_item_set_related_action (menu_item, g_value_get_object (value)); + break; + case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: + gtk_menu_item_set_use_action_appearance (menu_item, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -438,6 +500,7 @@ gtk_menu_item_get_property (GObject *object, GParamSpec *pspec) { GtkMenuItem *menu_item = GTK_MENU_ITEM (object); + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); switch (prop_id) { @@ -456,7 +519,12 @@ gtk_menu_item_get_property (GObject *object, case PROP_USE_UNDERLINE: g_value_set_boolean (value, gtk_menu_item_get_use_underline (menu_item)); break; - + case PROP_ACTIVATABLE_RELATED_ACTION: + g_value_set_object (value, priv->action); + break; + case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: + g_value_set_boolean (value, priv->use_action_appearance); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -505,6 +573,138 @@ gtk_menu_item_buildable_add_child (GtkBuildable *buildable, parent_buildable_iface->add_child (buildable, builder, child, type); } +static void +gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface) +{ + iface->update = gtk_menu_item_activatable_update; + iface->reset = gtk_menu_item_activatable_reset; +} + +static void +activatable_update_label (GtkMenuItem *menu_item, GtkAction *action) +{ + GtkWidget *child = GTK_BIN (menu_item)->child; + + if (GTK_IS_LABEL (child)) + { + const gchar *label; + + label = gtk_action_get_label (action); + gtk_label_set_label (GTK_LABEL (child), label ? label : ""); + } +} + +gboolean _gtk_menu_is_empty (GtkWidget *menu); + +static void +gtk_menu_item_activatable_update (GtkActivatable *activatable, + GtkAction *action, + const gchar *property_name) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable); + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + + if (strcmp (property_name, "visible") == 0) + _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item), + _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item))); + else if (strcmp (property_name, "sensitive") == 0) + gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action)); + else if (priv->use_action_appearance) + { + if (strcmp (property_name, "label") == 0) + activatable_update_label (menu_item, action); + } +} + +static void +gtk_menu_item_activatable_reset (GtkActivatable *activatable, + GtkAction *action) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable); + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + + if (!action) + return; + + _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item), + _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item))); + + gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action)); + + if (priv->use_action_appearance) + { + GtkWidget *label = GTK_BIN (menu_item)->child; + + /* make sure label is a label */ + if (label && !GTK_IS_LABEL (label)) + { + gtk_container_remove (GTK_CONTAINER (menu_item), label); + label = NULL; + } + + if (!label) + label = g_object_new (GTK_TYPE_ACCEL_LABEL, + "use-underline", TRUE, + "xalign", 0.0, + "visible", TRUE, + "parent", menu_item, + NULL); + + if (GTK_IS_ACCEL_LABEL (label) && gtk_action_get_accel_path (action)) + g_object_set (label, + "accel-closure", gtk_action_get_accel_closure (action), + NULL); + + activatable_update_label (menu_item, action); + } +} + +static void +gtk_menu_item_set_related_action (GtkMenuItem *menu_item, + GtkAction *action) +{ + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + + if (priv->action == action) + return; + + if (priv->action) + { + gtk_action_disconnect_accelerator (priv->action); + } + + if (action) + { + const gchar *accel_path; + + accel_path = gtk_action_get_accel_path (action); + if (accel_path) + { + gtk_action_connect_accelerator (action); + gtk_menu_item_set_accel_path (menu_item, accel_path); + } + } + + gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), action); + + priv->action = action; +} + +static void +gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item, + gboolean use_appearance) +{ + GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + + if (priv->use_action_appearance != use_appearance) + { + priv->use_action_appearance = use_appearance; + + gtk_activatable_reset (GTK_ACTIVATABLE (menu_item), priv->action); + } +} + + /** * gtk_menu_item_set_submenu: * @menu_item: a #GtkMenuItem @@ -629,7 +829,7 @@ void gtk_menu_item_activate (GtkMenuItem *menu_item) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); - + g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0); } @@ -1142,13 +1342,27 @@ gtk_menu_item_mnemonic_activate (GtkWidget *widget, return TRUE; } +static void +gtk_real_menu_item_activate (GtkMenuItem *menu_item) +{ + GtkMenuItemPrivate *priv; + + priv = GET_PRIVATE (menu_item); + + if (priv->action) + gtk_action_activate (priv->action); +} + + static void gtk_real_menu_item_activate_item (GtkMenuItem *menu_item) { + GtkMenuItemPrivate *priv; GtkWidget *widget; g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + priv = GET_PRIVATE (menu_item); widget = GTK_WIDGET (menu_item); if (widget->parent && |