X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmodelmenuitem.c;h=6d902c2352d3502f97678f872be62120c2aaf60d;hb=3c04597306a918317cb96d6c267fc73a798c04e4;hp=d07f4d258447c2e8bc93303a61cc086ad09764ea;hpb=9d0febc9a64a5bfb0fcfc3a88de4757f6c1ff090;p=~andy%2Fgtk diff --git a/gtk/gtkmodelmenuitem.c b/gtk/gtkmodelmenuitem.c index d07f4d258..6d902c235 100644 --- a/gtk/gtkmodelmenuitem.c +++ b/gtk/gtkmodelmenuitem.c @@ -22,33 +22,22 @@ #include "gtkmodelmenuitem.h" #include "gtkaccelmapprivate.h" -#include "gtkmodelmenu.h" +#include "gtkactionhelper.h" +#include "gtkwidgetprivate.h" +#include "gtkaccellabel.h" struct _GtkModelMenuItem { GtkCheckMenuItem parent_instance; - - GActionGroup *actions; - const gchar *action_name; + GtkActionHelperRole role; gboolean has_indicator; - gboolean can_activate; - GVariant *target; }; typedef GtkCheckMenuItemClass GtkModelMenuItemClass; -static void gtk_model_menu_item_observer_iface_init (GActionObserverInterface *iface); -G_DEFINE_TYPE_WITH_CODE (GtkModelMenuItem, gtk_model_menu_item, GTK_TYPE_CHECK_MENU_ITEM, - G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVER, gtk_model_menu_item_observer_iface_init)) - -static void -gtk_model_menu_item_activate (GtkMenuItem *menu_item) -{ - GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (menu_item); +G_DEFINE_TYPE (GtkModelMenuItem, gtk_model_menu_item, GTK_TYPE_CHECK_MENU_ITEM) - if (item->can_activate) - g_action_group_activate_action (item->actions, item->action_name, item->target); -} +#define PROP_ACTION_ROLE 1 static void gtk_model_menu_item_toggle_size_request (GtkMenuItem *menu_item, @@ -76,123 +65,49 @@ gtk_model_menu_item_draw_indicator (GtkCheckMenuItem *check_item, } static void -gtk_model_menu_item_set_active (GtkModelMenuItem *item, - gboolean active) +gtk_actionable_set_namespaced_action_name (GtkActionable *actionable, + const gchar *namespace, + const gchar *action_name) { - GtkCheckMenuItem *checkitem = GTK_CHECK_MENU_ITEM (item); - - if (gtk_check_menu_item_get_active (checkitem) != active) + if (namespace) { - _gtk_check_menu_item_set_active (checkitem, active); - g_object_notify (G_OBJECT (checkitem), "active"); - gtk_check_menu_item_toggled (checkitem); - gtk_widget_queue_draw (GTK_WIDGET (item)); + gchar *name = g_strdup_printf ("%s.%s", namespace, action_name); + gtk_actionable_set_action_name (actionable, name); + g_free (name); } -} - -static void -gtk_model_menu_item_action_added (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name, - const GVariantType *parameter_type, - gboolean enabled, - GVariant *state) -{ - GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer); - - /* we can only activate the item if we have the correct type of parameter */ - item->can_activate = (item->target == NULL && parameter_type == NULL) || - (item->target != NULL && parameter_type != NULL && - g_variant_is_of_type (item->target, parameter_type)); - - if (item->can_activate) + else { - if (item->target != NULL && state != NULL) - { - /* actions with states and targets are radios */ - gboolean selected; - - selected = g_variant_equal (state, item->target); - gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), TRUE); - gtk_model_menu_item_set_active (item, selected); - item->has_indicator = TRUE; - } - - else if (state != NULL && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) - { - /* boolean state actions without target are checks */ - gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (item), FALSE); - gtk_model_menu_item_set_active (item, g_variant_get_boolean (state)); - item->has_indicator = TRUE; - } - - else - { - /* stateless items are just plain actions */ - gtk_model_menu_item_set_active (item, FALSE); - item->has_indicator = FALSE; - } - - gtk_widget_set_sensitive (GTK_WIDGET (item), enabled); - gtk_widget_queue_resize (GTK_WIDGET (item)); + gtk_actionable_set_action_name (actionable, action_name); } } static void -gtk_model_menu_item_action_enabled_changed (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name, - gboolean enabled) +gtk_model_menu_item_submenu_shown (GtkWidget *widget, + gpointer user_data) { - GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer); - - if (!item->can_activate) - return; - - gtk_widget_set_sensitive (GTK_WIDGET (item), item->can_activate && enabled); -} - -static void -gtk_model_menu_item_action_state_changed (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name, - GVariant *state) -{ - GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer); - - if (!item->can_activate) - return; - - if (item->target) - gtk_model_menu_item_set_active (item, g_variant_equal (state, item->target)); + const gchar *action_name = user_data; + GActionMuxer *muxer; - else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) - gtk_model_menu_item_set_active (item, g_variant_get_boolean (state)); + muxer = _gtk_widget_get_action_muxer (widget); + g_action_group_change_action_state (G_ACTION_GROUP (muxer), action_name, g_variant_new_boolean (TRUE)); } static void -gtk_model_menu_item_action_removed (GActionObserver *observer, - GActionObservable *observable, - const gchar *action_name) +gtk_model_menu_item_submenu_hidden (GtkWidget *widget, + gpointer user_data) { - GtkModelMenuItem *item = GTK_MODEL_MENU_ITEM (observer); - - if (!item->can_activate) - return; - - gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); - gtk_model_menu_item_set_active (item, FALSE); - item->has_indicator = FALSE; + const gchar *action_name = user_data; + GActionMuxer *muxer; - gtk_widget_queue_resize (GTK_WIDGET (item)); + muxer = _gtk_widget_get_action_muxer (widget); + g_action_group_change_action_state (G_ACTION_GROUP (muxer), action_name, g_variant_new_boolean (FALSE)); } static void gtk_model_menu_item_setup (GtkModelMenuItem *item, GMenuModel *model, gint item_index, - GActionObservable *actions, - GtkAccelGroup *accels) + const gchar *action_namespace) { GMenuAttributeIter *iter; GMenuModel *submenu; @@ -201,7 +116,24 @@ gtk_model_menu_item_setup (GtkModelMenuItem *item, if ((submenu = g_menu_model_get_item_link (model, item_index, "submenu"))) { - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), gtk_model_menu_create_menu (submenu, actions, accels)); + gchar *section_namespace = NULL; + GtkWidget *menu; + + g_menu_model_get_item_attribute (model, item_index, "action-namespace", "s", §ion_namespace); + menu = gtk_menu_new (); + + 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); + + gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu); + + g_free (section_namespace); g_object_unref (submenu); } @@ -211,69 +143,118 @@ gtk_model_menu_item_setup (GtkModelMenuItem *item, if (g_str_equal (key, "label") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) gtk_menu_item_set_label (GTK_MENU_ITEM (item), g_variant_get_string (value, NULL)); - else if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) - item->action_name = g_variant_get_string (value, NULL); + else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) + { + GdkModifierType modifiers; + guint key; - else if (g_str_equal (key, "target")) - item->target = g_variant_ref (value); + gtk_accelerator_parse (g_variant_get_string (value, NULL), &key, &modifiers); - g_variant_unref (value); - } - g_object_unref (iter); + if (key) + { + GtkAccelLabel *accel_label; - gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item), TRUE); + /* Ensure that the GtkAccelLabel has been created... */ + (void) gtk_menu_item_get_label (GTK_MENU_ITEM (item)); + accel_label = GTK_ACCEL_LABEL (gtk_bin_get_child (GTK_BIN (item))); + g_assert (accel_label); - if (item->action_name) - { - const GVariantType *type; - gboolean enabled; - GVariant *state; - gchar *path; + gtk_accel_label_set_accel (accel_label, key, modifiers); + } + } + + 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)); - /* observer already causes us to hold a hard ref on the group */ - item->actions = G_ACTION_GROUP (actions); + else if (g_str_equal (key, "target")) + gtk_actionable_set_action_target_value (GTK_ACTIONABLE (item), value); - if (actions) + else if (g_str_equal (key, "submenu-action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) { - g_action_observable_register_observer (actions, item->action_name, G_ACTION_OBSERVER (item)); + GtkWidget *submenu; + + submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)); - if (g_action_group_query_action (G_ACTION_GROUP (actions), item->action_name, &enabled, &type, NULL, NULL, &state)) + if (submenu != NULL) { - gtk_model_menu_item_action_added (G_ACTION_OBSERVER (item), actions, item->action_name, type, enabled, state); - if (state != NULL) - g_variant_unref (state); + const gchar *action = g_variant_get_string (value, NULL); + gchar *full_action; + + if (action_namespace) + full_action = g_strjoin (".", action_namespace, action, NULL); + else + full_action = g_strdup (action); + + 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); } - else - gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); } - else - gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); - path = _gtk_accel_path_for_action (item->action_name, item->target); - gtk_menu_item_set_accel_path (GTK_MENU_ITEM (item), path); - g_free (path); + g_variant_unref (value); } + g_object_unref (iter); + + gtk_menu_item_set_use_underline (GTK_MENU_ITEM (item), TRUE); } static void -gtk_model_menu_item_finalize (GObject *object) +gtk_model_menu_item_set_has_indicator (GtkModelMenuItem *item, + gboolean has_indicator) { - G_OBJECT_CLASS (gtk_model_menu_item_parent_class) - ->finalize (object); + if (has_indicator == item->has_indicator) + return; + + item->has_indicator = has_indicator; + + gtk_widget_queue_resize (GTK_WIDGET (item)); } static void -gtk_model_menu_item_init (GtkModelMenuItem *item) +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; + + 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); + + accessible = gtk_widget_get_accessible (GTK_WIDGET (item)); + switch (role) + { + case GTK_ACTION_HELPER_ROLE_NORMAL: + a11y_role = ATK_ROLE_MENU_ITEM; + break; + + case GTK_ACTION_HELPER_ROLE_TOGGLE: + a11y_role = ATK_ROLE_CHECK_MENU_ITEM; + break; + + case GTK_ACTION_HELPER_ROLE_RADIO: + a11y_role = ATK_ROLE_RADIO_MENU_ITEM; + break; + + default: + g_assert_not_reached (); + } + + atk_object_set_role (accessible, a11y_role); } static void -gtk_model_menu_item_observer_iface_init (GActionObserverInterface *iface) +gtk_model_menu_item_init (GtkModelMenuItem *item) { - iface->action_added = gtk_model_menu_item_action_added; - iface->action_enabled_changed = gtk_model_menu_item_action_enabled_changed; - iface->action_state_changed = gtk_model_menu_item_action_state_changed; - iface->action_removed = gtk_model_menu_item_action_removed; } static void @@ -285,23 +266,25 @@ gtk_model_menu_item_class_init (GtkModelMenuItemClass *class) check_class->draw_indicator = gtk_model_menu_item_draw_indicator; - item_class->activate = gtk_model_menu_item_activate; item_class->toggle_size_request = gtk_model_menu_item_toggle_size_request; - object_class->finalize = gtk_model_menu_item_finalize; + 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)); } GtkMenuItem * gtk_model_menu_item_new (GMenuModel *model, gint item_index, - GActionObservable *actions, - GtkAccelGroup *accels) + const gchar *action_namespace) { GtkModelMenuItem *item; item = g_object_new (GTK_TYPE_MODEL_MENU_ITEM, NULL); - gtk_model_menu_item_setup (item, model, item_index, actions, accels); + gtk_model_menu_item_setup (item, model, item_index, action_namespace); return GTK_MENU_ITEM (item); }