summaryrefslogtreecommitdiff
path: root/gtk/gtkmodelmenuitem.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/gtkmodelmenuitem.c')
-rw-r--r--gtk/gtkmodelmenuitem.c380
1 files changed, 208 insertions, 172 deletions
diff --git a/gtk/gtkmodelmenuitem.c b/gtk/gtkmodelmenuitem.c
index 1d30d3804d..c698a52e4e 100644
--- a/gtk/gtkmodelmenuitem.c
+++ b/gtk/gtkmodelmenuitem.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2011 Canonical Limited
+ * Copyright © 2011, 2013 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,9 +21,6 @@
#include "gtkmodelmenuitem.h"
-#include "gtkaccelmapprivate.h"
-#include "gtkactionhelper.h"
-#include "gtkwidgetprivate.h"
#include "gtkaccellabel.h"
#include "gtkimage.h"
#include "gtkbox.h"
@@ -31,7 +28,7 @@
struct _GtkModelMenuItem
{
GtkCheckMenuItem parent_instance;
- GtkActionHelperRole role;
+ GtkMenuTrackerItemRole role;
gboolean has_indicator;
};
@@ -39,7 +36,15 @@ typedef GtkCheckMenuItemClass GtkModelMenuItemClass;
G_DEFINE_TYPE (GtkModelMenuItem, gtk_model_menu_item, GTK_TYPE_CHECK_MENU_ITEM)
-#define PROP_ACTION_ROLE 1
+enum
+{
+ PROP_0,
+ PROP_ACTION_ROLE,
+ PROP_ICON,
+ PROP_TEXT,
+ PROP_TOGGLED,
+ PROP_ACCEL
+};
static void
gtk_model_menu_item_toggle_size_request (GtkMenuItem *menu_item,
@@ -56,6 +61,12 @@ gtk_model_menu_item_toggle_size_request (GtkMenuItem *menu_item,
}
static void
+gtk_model_menu_item_activate (GtkMenuItem *item)
+{
+ /* block the automatic toggle behaviour -- just do nothing */
+}
+
+static void
gtk_model_menu_item_draw_indicator (GtkCheckMenuItem *check_item,
cairo_t *cr)
{
@@ -67,227 +78,245 @@ gtk_model_menu_item_draw_indicator (GtkCheckMenuItem *check_item,
}
static void
-gtk_actionable_set_namespaced_action_name (GtkActionable *actionable,
- const gchar *namespace,
- const gchar *action_name)
+gtk_model_menu_item_set_has_indicator (GtkModelMenuItem *item,
+ gboolean has_indicator)
{
- if (namespace)
- {
- gchar *name = g_strdup_printf ("%s.%s", namespace, action_name);
- gtk_actionable_set_action_name (actionable, name);
- g_free (name);
- }
- else
- {
- gtk_actionable_set_action_name (actionable, action_name);
- }
-}
+ if (has_indicator == item->has_indicator)
+ return;
-static void
-gtk_model_menu_item_submenu_shown (GtkWidget *widget,
- gpointer user_data)
-{
- const gchar *action_name = user_data;
- GActionMuxer *muxer;
+ item->has_indicator = has_indicator;
- muxer = _gtk_widget_get_action_muxer (widget);
- g_action_group_change_action_state (G_ACTION_GROUP (muxer), action_name, g_variant_new_boolean (TRUE));
+ gtk_widget_queue_resize (GTK_WIDGET (item));
}
static void
-gtk_model_menu_item_submenu_hidden (GtkWidget *widget,
- gpointer user_data)
+gtk_model_menu_item_set_action_role (GtkModelMenuItem *item,
+ GtkMenuTrackerItemRole role)
{
- const gchar *action_name = user_data;
- GActionMuxer *muxer;
-
- muxer = _gtk_widget_get_action_muxer (widget);
- g_action_group_change_action_state (G_ACTION_GROUP (muxer), action_name, g_variant_new_boolean (FALSE));
-}
+ AtkObject *accessible;
+ AtkRole a11y_role;
-static void
-gtk_model_menu_item_setup (GtkModelMenuItem *item,
- GMenuModel *model,
- gint item_index,
- const gchar *action_namespace)
-{
- GMenuAttributeIter *iter;
- GMenuModel *submenu;
- const gchar *key;
- GVariant *value;
- GtkWidget *label;
+ if (role == item->role)
+ return;
- label = NULL;
+ gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), role == GTK_MENU_TRACKER_ITEM_ROLE_RADIO);
+ gtk_model_menu_item_set_has_indicator (item, role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL);
- /* In the case that we have an icon, make an HBox and put it beside
- * the label. Otherwise, we just have a label directly.
- */
- if ((value = g_menu_model_get_item_attribute_value (model, item_index, "icon", NULL)))
+ accessible = gtk_widget_get_accessible (GTK_WIDGET (item));
+ switch (role)
{
- GIcon *icon;
+ case GTK_MENU_TRACKER_ITEM_ROLE_NORMAL:
+ a11y_role = ATK_ROLE_MENU_ITEM;
+ break;
- icon = g_icon_deserialize (value);
+ case GTK_MENU_TRACKER_ITEM_ROLE_CHECK:
+ a11y_role = ATK_ROLE_CHECK_MENU_ITEM;
+ break;
- if (icon != NULL)
- {
- GtkWidget *image;
- GtkWidget *box;
+ case GTK_MENU_TRACKER_ITEM_ROLE_RADIO:
+ a11y_role = ATK_ROLE_RADIO_MENU_ITEM;
+ break;
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ default:
+ g_assert_not_reached ();
+ }
- image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
- gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
- g_object_unref (icon);
+ atk_object_set_role (accessible, a11y_role);
+}
- label = gtk_accel_label_new ("");
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), GTK_WIDGET (item));
- gtk_box_pack_end (GTK_BOX (box), label, TRUE, TRUE, 0);
+static void
+gtk_model_menu_item_set_icon (GtkModelMenuItem *item,
+ GIcon *icon)
+{
+ GtkWidget *child;
- gtk_container_add (GTK_CONTAINER (item), box);
+ g_return_if_fail (GTK_IS_MODEL_MENU_ITEM (item));
+ g_return_if_fail (icon == NULL || G_IS_ICON (icon));
- gtk_widget_show_all (box);
- }
+ child = gtk_bin_get_child (GTK_BIN (item));
- g_variant_unref (value);
+ /* There are only three possibilities here:
+ *
+ * - no child
+ * - accel label child
+ * - already a box
+ *
+ * Handle the no-child case by having GtkMenuItem create the accel
+ * label, then we will only have two possible cases.
+ */
+ if (child == NULL)
+ {
+ gtk_menu_item_get_label (GTK_MENU_ITEM (item));
+ child = gtk_bin_get_child (GTK_BIN (item));
+ g_assert (GTK_IS_LABEL (child));
}
- if (label == NULL)
+ /* If it is a box, make sure there are no images inside of it already.
+ */
+ if (GTK_IS_BOX (child))
{
- /* Ensure that the GtkAccelLabel has been created... */
- (void) gtk_menu_item_get_label (GTK_MENU_ITEM (item));
- label = gtk_bin_get_child (GTK_BIN (item));
- }
+ GList *children;
+
+ children = gtk_container_get_children (GTK_CONTAINER (child));
+ while (children)
+ {
+ if (GTK_IS_IMAGE (children->data))
+ gtk_widget_destroy (children->data);
- g_assert (label != NULL);
+ children = g_list_delete_link (children, children);
+ }
+ }
- if ((submenu = g_menu_model_get_item_link (model, item_index, "submenu")))
+ /* If it is not a box, put it into a box, at the end */
+ if (!GTK_IS_BOX (child))
{
- gchar *section_namespace = NULL;
- GtkWidget *menu;
+ GtkWidget *box;
- g_menu_model_get_item_attribute (model, item_index, "action-namespace", "s", &section_namespace);
- menu = gtk_menu_new ();
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
- if (action_namespace)
- {
- gchar *namespace = g_strjoin (".", action_namespace, section_namespace, NULL);
- gtk_menu_shell_bind_model (GTK_MENU_SHELL (menu), submenu, namespace, TRUE);
- g_free (namespace);
- }
- else
- gtk_menu_shell_bind_model (GTK_MENU_SHELL (menu), submenu, section_namespace, TRUE);
+ /* Reparent the child without destroying it */
+ g_object_ref (child);
+ gtk_container_remove (GTK_CONTAINER (item), child);
+ gtk_box_pack_end (GTK_BOX (box), child, TRUE, TRUE, 0);
+ g_object_unref (child);
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
+ gtk_container_add (GTK_CONTAINER (item), box);
+ gtk_widget_show (box);
- g_free (section_namespace);
- g_object_unref (submenu);
+ /* Now we have a box */
+ child = box;
}
- iter = g_menu_model_iterate_item_attributes (model, item_index);
- while (g_menu_attribute_iter_get_next (iter, &key, &value))
+ g_assert (GTK_IS_BOX (child));
+
+ /* child is now a box containing a label and no image. Add the icon,
+ * if appropriate.
+ */
+ if (icon != NULL)
{
- if (g_str_equal (key, "label") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- gtk_label_set_text_with_mnemonic (GTK_LABEL (label), g_variant_get_string (value, NULL));
+ GtkWidget *image;
- else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- GdkModifierType modifiers;
- guint key;
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (child), image, FALSE, FALSE, 0);
+ gtk_widget_show (image);
+ }
+}
- gtk_accelerator_parse (g_variant_get_string (value, NULL), &key, &modifiers);
+static void
+gtk_model_menu_item_set_text (GtkModelMenuItem *item,
+ const gchar *text)
+{
+ GtkWidget *child;
+ GList *children;
- if (key)
- gtk_accel_label_set_accel (GTK_ACCEL_LABEL (label), key, modifiers);
- }
+ child = gtk_bin_get_child (GTK_BIN (item));
+ if (child == NULL)
+ {
+ gtk_menu_item_get_label (GTK_MENU_ITEM (item));
+ child = gtk_bin_get_child (GTK_BIN (item));
+ g_assert (GTK_IS_LABEL (child));
+ }
- else if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- gtk_actionable_set_namespaced_action_name (GTK_ACTIONABLE (item), action_namespace,
- g_variant_get_string (value, NULL));
+ if (GTK_IS_LABEL (child))
+ {
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (child), text);
+ return;
+ }
- else if (g_str_equal (key, "target"))
- gtk_actionable_set_action_target_value (GTK_ACTIONABLE (item), value);
+ if (!GTK_IS_CONTAINER (child))
+ return;
- else if (g_str_equal (key, "submenu-action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
- {
- GtkWidget *submenu;
+ children = gtk_container_get_children (GTK_CONTAINER (child));
- submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
+ while (children)
+ {
+ if (GTK_IS_LABEL (children->data))
+ gtk_label_set_label (GTK_LABEL (children->data), text);
- if (submenu != NULL)
- {
- const gchar *action = g_variant_get_string (value, NULL);
- gchar *full_action;
+ children = g_list_delete_link (children, children);
+ }
+}
- if (action_namespace)
- full_action = g_strjoin (".", action_namespace, action, NULL);
- else
- full_action = g_strdup (action);
+static void
+gtk_model_menu_item_set_accel (GtkModelMenuItem *item,
+ const gchar *accel)
+{
+ GtkWidget *child;
+ GList *children;
+ GdkModifierType modifiers;
+ guint key;
- g_object_set_data_full (G_OBJECT (submenu), "gtkmodelmenu-visibility-action", full_action, g_free);
- g_signal_connect (submenu, "show", G_CALLBACK (gtk_model_menu_item_submenu_shown), full_action);
- g_signal_connect (submenu, "hide", G_CALLBACK (gtk_model_menu_item_submenu_hidden), full_action);
- }
- }
+ if (accel)
+ {
+ gtk_accelerator_parse (accel, &key, &modifiers);
+ if (!key)
+ modifiers = 0;
+ }
+ else
+ {
+ key = 0;
+ modifiers = 0;
+ }
- g_variant_unref (value);
+ child = gtk_bin_get_child (GTK_BIN (item));
+ if (child == NULL)
+ {
+ gtk_menu_item_get_label (GTK_MENU_ITEM (item));
+ child = gtk_bin_get_child (GTK_BIN (item));
+ g_assert (GTK_IS_LABEL (child));
}
- g_object_unref (iter);
- gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item), TRUE);
-}
+ if (GTK_IS_LABEL (child))
+ {
+ gtk_accel_label_set_accel (GTK_ACCEL_LABEL (child), key, modifiers);
+ return;
+ }
-static void
-gtk_model_menu_item_set_has_indicator (GtkModelMenuItem *item,
- gboolean has_indicator)
-{
- if (has_indicator == item->has_indicator)
+ if (!GTK_IS_CONTAINER (child))
return;
- item->has_indicator = has_indicator;
+ children = gtk_container_get_children (GTK_CONTAINER (child));
- gtk_widget_queue_resize (GTK_WIDGET (item));
+ while (children)
+ {
+ if (GTK_IS_ACCEL_LABEL (children->data))
+ gtk_accel_label_set_accel (children->data, key, modifiers);
+
+ children = g_list_delete_link (children, children);
+ }
}
-static void
+void
gtk_model_menu_item_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (object);
- GtkActionHelperRole role;
- AtkObject *accessible;
- AtkRole a11y_role;
-
- g_assert (prop_id == PROP_ACTION_ROLE);
- role = g_value_get_uint (value);
-
- if (role == item->role)
- return;
+ switch (prop_id)
+ {
+ case PROP_ACTION_ROLE:
+ gtk_model_menu_item_set_action_role (item, g_value_get_enum (value));
+ break;
- gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), role == GTK_ACTION_HELPER_ROLE_RADIO);
- gtk_model_menu_item_set_has_indicator (item, role != GTK_ACTION_HELPER_ROLE_NORMAL);
+ case PROP_ICON:
+ gtk_model_menu_item_set_icon (item, g_value_get_object (value));
+ break;
- accessible = gtk_widget_get_accessible (GTK_WIDGET (item));
- switch (role)
- {
- case GTK_ACTION_HELPER_ROLE_NORMAL:
- a11y_role = ATK_ROLE_MENU_ITEM;
+ case PROP_TEXT:
+ gtk_model_menu_item_set_text (item, g_value_get_string (value));
break;
- case GTK_ACTION_HELPER_ROLE_TOGGLE:
- a11y_role = ATK_ROLE_CHECK_MENU_ITEM;
+ case PROP_TOGGLED:
+ _gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_value_get_boolean (value));
break;
- case GTK_ACTION_HELPER_ROLE_RADIO:
- a11y_role = ATK_ROLE_RADIO_MENU_ITEM;
+ case PROP_ACCEL:
+ gtk_model_menu_item_set_accel (item, g_value_get_string (value));
break;
default:
g_assert_not_reached ();
}
-
- atk_object_set_role (accessible, a11y_role);
}
static void
@@ -305,24 +334,31 @@ gtk_model_menu_item_class_init (GtkModelMenuItemClass *class)
check_class->draw_indicator = gtk_model_menu_item_draw_indicator;
item_class->toggle_size_request = gtk_model_menu_item_toggle_size_request;
+ item_class->activate = gtk_model_menu_item_activate;
object_class->set_property = gtk_model_menu_item_set_property;
g_object_class_install_property (object_class, PROP_ACTION_ROLE,
- g_param_spec_uint ("action-role", "action role", "action role",
- 0, 2, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_param_spec_enum ("action-role", "action role", "action role",
+ GTK_TYPE_MENU_TRACKER_ITEM_ROLE,
+ GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_ICON,
+ g_param_spec_object ("icon", "icon", "icon", G_TYPE_ICON,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_TEXT,
+ g_param_spec_string ("text", "text", "text", NULL,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_TOGGLED,
+ g_param_spec_boolean ("toggled", "toggled", "toggled", FALSE,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_ACCEL,
+ g_param_spec_string ("accel", "accel", "accel", NULL,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
}
GtkWidget *
-gtk_model_menu_item_new (GMenuModel *model,
- gint item_index,
- const gchar *action_namespace)
+gtk_model_menu_item_new (void)
{
- GtkModelMenuItem *item;
-
- item = g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL);
-
- gtk_model_menu_item_setup (item, model, item_index, action_namespace);
-
- return GTK_WIDGET (item);
+ return g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL);
}