static GVariant * g_menu_exporter_menu_describe_item (GMenuExporterMenu *menu, gint position) { GMenuAttributeIter *attr_iter; GVariantBuilder builder; GSequenceIter *iter; GMenuExporterLink *link; const char *name; GVariant *value; g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); attr_iter = g_menu_model_iterate_item_attributes (menu->model, position); while (g_menu_attribute_iter_get_next (attr_iter, &name, &value)) { g_variant_builder_add (&builder, "{sv}", name, value); g_variant_unref (value); } g_object_unref (attr_iter); iter = g_sequence_get_iter_at_pos (menu->item_links, position); for (link = g_sequence_get (iter); link; link = link->next) g_variant_builder_add (&builder, "{sv}", link->name, g_variant_new ("(uu)", g_menu_exporter_group_get_id (link->menu->group), link->menu->id)); return g_variant_builder_end (&builder); }
static void add_accelerators_from_menu_item (GtkWindow *window, GtkAccelGroup *accel_group, GMenuModel *model, int item) { GMenuAttributeIter *iter; const char *key; GVariant *value; const char *accel = NULL; const char *action = NULL; GVariant *target = NULL; iter = g_menu_model_iterate_item_attributes (model, item); while (g_menu_attribute_iter_get_next (iter, &key, &value)) { if (g_str_equal (key, "action") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) action = g_variant_get_string (value, NULL); else if (g_str_equal (key, "accel") && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) accel = g_variant_get_string (value, NULL); else if (g_str_equal (key, "target")) target = g_variant_ref (value); g_variant_unref (value); } g_object_unref (iter); _gtk_window_add_accelerator_for_action (window, accel_group, action, accel, target); if (target != NULL) g_variant_unref (target); }
static void extract_accel_from_menu_item(GMenuModel * model, gint item, GActionMap * action_map, GtkAccelGroup * accel_group) { GMenuAttributeIter *iter; const gchar *key; GVariant *value; const gchar *accel = NULL; const gchar *action = NULL; GVariant *target = NULL; iter = g_menu_model_iterate_item_attributes(model, item); while (g_menu_attribute_iter_get_next(iter, &key, &value)) { if (g_str_equal(key, "action") && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) action = g_variant_get_string(value, NULL); else if (g_str_equal(key, "accel") && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) accel = g_variant_get_string(value, NULL); else if (g_str_equal(key, "target")) target = g_variant_ref(value); g_variant_unref(value); } g_object_unref(iter); if (accel && action) { guint accel_key; GdkModifierType accel_mods; AccelInfo *info; const gchar *basename; GClosure *closure; gtk_accelerator_parse(accel, &accel_key, &accel_mods); basename = strchr(action, '.'); basename = basename ? basename + 1 : action; info = g_new(AccelInfo, 1); info->action = g_action_map_lookup_action(action_map, basename); info->parameter = target ? g_variant_ref(target) : NULL; closure = g_cclosure_new(G_CALLBACK(accel_activate), info, (GClosureNotify) accel_info_free); gtk_accel_group_connect(accel_group, accel_key, accel_mods, 0, closure); } if (target) g_variant_unref(target); }
static gboolean append_menu (RBButtonBar *bar, GMenuModel *menu, gboolean need_separator) { int i; gulong id; id = g_signal_connect (menu, "items-changed", G_CALLBACK (items_changed_cb), bar); g_hash_table_insert (bar->priv->handlers, (gpointer)id, g_object_ref (menu)); for (i = 0; i < g_menu_model_get_n_items (menu); i++) { char *label_text; char *accel; GtkWidget *button; GtkWidget *label; GMenuModel *submenu; /* recurse into sections */ submenu = g_menu_model_get_item_link (menu, i, G_MENU_LINK_SECTION); if (submenu != NULL) { need_separator = append_menu (bar, submenu, TRUE); continue; } /* if this item and the previous item are in different sections, add * a separator between them. this may not be a good idea. */ if (need_separator) { GtkWidget *sep; if (bar->priv->position > 0) { sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL); gtk_widget_show (sep); g_object_set (sep, "margin-start", 6, "margin-end", 6, NULL); gtk_grid_attach (GTK_GRID (bar), sep, bar->priv->position++, 0, 1, 1); } need_separator = FALSE; } button = NULL; /* submenus become menu buttons, normal items become buttons */ submenu = g_menu_model_get_item_link (menu, i, G_MENU_LINK_SUBMENU); if (submenu != NULL) { button = gtk_menu_button_new (); gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), submenu); g_object_set_data_full (G_OBJECT (button), "rb-menu-model", g_object_ref (submenu), (GDestroyNotify)g_object_unref); } else { GMenuAttributeIter *iter; const char *name; GVariant *value; char *str; guint signal_id; /* we can't do more than one of action and rb-property-bind * and rb-signal-bind, so just do whichever turns up first * in the iterator */ iter = g_menu_model_iterate_item_attributes (menu, i); while (g_menu_attribute_iter_get_next (iter, &name, &value)) { if (g_str_equal (name, "action")) { button = gtk_button_new (); g_variant_get (value, "s", &str, NULL); gtk_actionable_set_action_name (GTK_ACTIONABLE (button), str); /* action target too somehow? */ g_free (str); break; } else if (g_str_equal (name, "rb-property-bind")) { /* property has to be a boolean, can't do inverts, etc. etc. */ button = gtk_toggle_button_new (); g_variant_get (value, "s", &str, NULL); g_object_bind_property (bar->priv->target, str, button, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); g_free (str); break; } else if (g_str_equal (name, "rb-signal-bind")) { button = gtk_button_new (); g_variant_get (value, "s", &str, NULL); signal_id = g_signal_lookup (str, G_OBJECT_TYPE (bar->priv->target)); if (signal_id != 0) { g_object_set_data (G_OBJECT (button), "rb-signal-bind-id", GUINT_TO_POINTER (signal_id)); g_signal_connect (button, "clicked", G_CALLBACK (signal_button_clicked_cb), bar); } g_free (str); break; } } g_object_unref (iter); } if (button == NULL) { g_warning ("no idea what's going on here"); continue; } gtk_widget_set_hexpand (button, FALSE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); label_text = NULL; g_menu_model_get_item_attribute (menu, i, "label", "s", &label_text); label = gtk_label_new (g_dgettext (NULL, label_text)); g_object_set (label, "margin-left", 6, "margin-right", 6, NULL); gtk_container_add (GTK_CONTAINER (button), label); if (g_menu_model_get_item_attribute (menu, i, "accel", "s", &accel)) { g_object_set_data_full (G_OBJECT (button), "rb-accel", accel, (GDestroyNotify) g_free); } gtk_widget_show_all (button); gtk_size_group_add_widget (bar->priv->size_group, button); gtk_grid_attach (GTK_GRID (bar), button, bar->priv->position++, 0, 1, 1); g_free (label_text); } return need_separator; }