summaryrefslogtreecommitdiff
path: root/gtk/gtkmenuitem.c
diff options
context:
space:
mode:
authorMatthias Clasen <matthiasc@src.gnome.org>2009-01-23 15:15:28 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2009-01-23 15:15:28 +0000
commitbb72b647f6a40831a46fb731a5929831d95c2b29 (patch)
tree5bd4a577f50fe360a0cd9a06ada7adc65c3c5508 /gtk/gtkmenuitem.c
parentacd40c45f781a84c297be34d5d18f7681e78d46e (diff)
downloadgtk+-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.c238
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 &&