X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=tests%2Ftestgmenu.c;h=2f0512896b64c7c8135164ef7656036201c597cb;hb=9d0febc9a64a5bfb0fcfc3a88de4757f6c1ff090;hp=566ae7ce94c2100fefb7c7461aabc562cbf92f6e;hpb=519c75a606f775e1bac65a2f7ff591d156f1d844;p=~andy%2Fgtk diff --git a/tests/testgmenu.c b/tests/testgmenu.c index 566ae7ce9..2f0512896 100644 --- a/tests/testgmenu.c +++ b/tests/testgmenu.c @@ -13,9 +13,7 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include @@ -25,54 +23,99 @@ /* TODO * - * - Debug initial click problem. + * - Labeled sections * - * - Dynamic changes. Add/Remove items, sections, submenus and - * reconstruct the widgetry. - * - * - Focus changes. Verify that stopping subscriptions works - * as intended. + * - Focus changes. Verify that stopping subscriptions works. * * - Other attributes. What about icons ? */ -/* GtkMenu construction {{{1 */ +/* MenuHolder {{{1 */ + +typedef struct { + GMenuModel *model; + GActionGroup *group; + GtkWidget *menu; + gboolean items_changed; +} MenuHolder; + +/* Menumodel callbacks {{{2 */ static void -enabled_changed (GActionGroup *group, - const gchar *action_name, - gboolean enabled, - GtkWidget *widget) +connect_to_items_changed (GMenuModel *model, + GCallback callback, + gpointer data) { - gtk_widget_set_sensitive (widget, enabled); + gint i; + GMenuModel *m; + GMenuLinkIter *iter; + + if (!g_object_get_data (G_OBJECT (model), "handler-connected")) + { + g_signal_connect (model, "items-changed", callback, data); + g_object_set_data (G_OBJECT (model), "handler-connected", GINT_TO_POINTER (1)); + } + for (i = 0; i < g_menu_model_get_n_items (model); i++) + { + iter = g_menu_model_iterate_item_links (model, i); + while (g_menu_link_iter_next (iter)) + { + m = g_menu_link_iter_get_value (iter); + connect_to_items_changed (m, callback, data); + g_object_unref (m); + } + g_object_unref (iter); + } } +static void +items_changed (GMenuModel *model, + gint position, + gint removed, + gint added, + MenuHolder *holder) +{ + g_print ("Received GMenuModel::items-changed\n"); + holder->items_changed = TRUE; + connect_to_items_changed (model, G_CALLBACK (items_changed), holder); +} + + /* Actiongroup callbacks {{{2 */ + typedef struct { GActionGroup *group; - const gchar *name; - const gchar *target; -} Activation; + gchar *name; + gchar *target; + gulong enabled_changed_id; + gulong state_changed_id; + gulong activate_handler; +} ActionData; static void -activate_item (GtkWidget *w, gpointer data) +action_data_free (gpointer data) { - Activation *a; + ActionData *a = data; + + if (a->enabled_changed_id) + g_signal_handler_disconnect (a->group, a->enabled_changed_id); - a = g_object_get_data (G_OBJECT (w), "activation"); + if (a->state_changed_id) + g_signal_handler_disconnect (a->group, a->state_changed_id); - g_action_group_activate_action (a->group, a->name, NULL); + g_object_unref (a->group); + g_free (a->name); + g_free (a->target); + + g_free (a); } static void -toggle_item_toggled (GtkCheckMenuItem *w, gpointer data) +enabled_changed (GActionGroup *group, + const gchar *action_name, + gboolean enabled, + GtkWidget *widget) { - Activation *a; - gboolean b; - - a = g_object_get_data (G_OBJECT (w), "activation"); - b = gtk_check_menu_item_get_active (w); - g_action_group_change_action_state (a->group, a->name, - g_variant_new_boolean (b)); + gtk_widget_set_sensitive (widget, enabled); } static void @@ -81,27 +124,12 @@ toggle_state_changed (GActionGroup *group, GVariant *state, GtkCheckMenuItem *w) { - gtk_check_menu_item_set_active (w, g_variant_get_boolean (state)); -} + ActionData *a; -static void -radio_item_toggled (GtkCheckMenuItem *w, gpointer data) -{ - Activation *a; - GVariant *v; - - a = g_object_get_data (G_OBJECT (w), "activation"); - /*g_print ("Radio item %s toggled\n", a->name);*/ - if (gtk_check_menu_item_get_active (w)) - g_action_group_change_action_state (a->group, a->name, - g_variant_new_string (a->target)); - else - { - v = g_action_group_get_action_state (a->group, a->name); - if (g_strcmp0 (g_variant_get_string (v, NULL), a->target) == 0) - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), TRUE); - g_variant_unref (v); - } + a = g_object_get_data (G_OBJECT (w), "action"); + g_signal_handler_block (w, a->activate_handler); + gtk_check_menu_item_set_active (w, g_variant_get_boolean (state)); + g_signal_handler_unblock (w, a->activate_handler); } static void @@ -110,33 +138,54 @@ radio_state_changed (GActionGroup *group, GVariant *state, GtkCheckMenuItem *w) { - Activation *a; + ActionData *a; gboolean b; - /*g_print ("Radio state changed %s\n", name);*/ - a = g_object_get_data (G_OBJECT (w), "activation"); + a = g_object_get_data (G_OBJECT (w), "action"); + g_signal_handler_block (w, a->activate_handler); b = g_strcmp0 (a->target, g_variant_get_string (state, NULL)) == 0; - gtk_check_menu_item_set_active (w, b); + g_signal_handler_unblock (w, a->activate_handler); +} + +/* Menuitem callbacks {{{2 */ + +static void +item_activated (GtkWidget *w, + gpointer data) +{ + ActionData *a; + GVariant *parameter; + + a = g_object_get_data (G_OBJECT (w), "action"); + if (a->target) + parameter = g_variant_new_string (a->target); + else + parameter = NULL; + g_action_group_activate_action (a->group, a->name, parameter); } +/* GtkMenu construction {{{2 */ + static GtkWidget * -create_menuitem_from_model (GMenuModelItem *item, - GActionGroup *group) +create_menuitem_from_model (GMenuModel *model, + gint item, + GActionGroup *group) { GtkWidget *w; gchar *label; gchar *action; gchar *target; gchar *s; - Activation *a; + ActionData *a; const GVariantType *type; GVariant *v; - g_menu_model_item_get_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", &label); + label = NULL; + g_menu_model_get_item_attribute (model, item, G_MENU_ATTRIBUTE_LABEL, "s", &label); action = NULL; - g_menu_model_item_get_attribute (item, G_MENU_ATTRIBUTE_ACTION, "s", &action); + g_menu_model_get_item_attribute (model, item, G_MENU_ATTRIBUTE_ACTION, "s", &action); if (action != NULL) type = g_action_group_get_action_state_type (group, action); @@ -157,25 +206,30 @@ create_menuitem_from_model (GMenuModelItem *item, if (action != NULL) { + a = g_new0 (ActionData, 1); + a->group = g_object_ref (group); + a->name = g_strdup (action); + g_object_set_data_full (G_OBJECT (w), "action", a, action_data_free); + if (!g_action_group_get_action_enabled (group, action)) gtk_widget_set_sensitive (w, FALSE); s = g_strconcat ("action-enabled-changed::", action, NULL); - g_signal_connect (group, s, G_CALLBACK (enabled_changed), w); + a->enabled_changed_id = g_signal_connect (group, s, + G_CALLBACK (enabled_changed), w); g_free (s); - a = g_new0 (Activation, 1); - a->group = group; - a->name = action; - g_object_set_data_full (G_OBJECT (w), "activation", a, g_free); + a->activate_handler = g_signal_connect (w, "activate", G_CALLBACK (item_activated), NULL); if (type == NULL) - g_signal_connect (w, "activate", G_CALLBACK (activate_item), NULL); + { + /* all set */ + } else if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) { - g_signal_connect (w, "toggled", G_CALLBACK (toggle_item_toggled), NULL); s = g_strconcat ("action-state-changed::", action, NULL); - g_signal_connect (group, s, G_CALLBACK (toggle_state_changed), w); + a->state_changed_id = g_signal_connect (group, s, + G_CALLBACK (toggle_state_changed), w); g_free (s); v = g_action_group_get_action_state (group, action); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), @@ -184,20 +238,24 @@ create_menuitem_from_model (GMenuModelItem *item, } else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)) { - g_signal_connect (w, "toggled", G_CALLBACK (radio_item_toggled), NULL); s = g_strconcat ("action-state-changed::", action, NULL); - g_signal_connect (group, s, G_CALLBACK (radio_state_changed), w); + a->state_changed_id = g_signal_connect (group, s, + G_CALLBACK (radio_state_changed), w); g_free (s); - g_menu_model_item_get_attribute (item, G_MENU_ATTRIBUTE_TARGET, "s", &target); - a->target = target; + g_menu_model_get_item_attribute (model, item, G_MENU_ATTRIBUTE_TARGET, "s", &target); + a->target = g_strdup (target); v = g_action_group_get_action_state (group, action); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (w), g_strcmp0 (g_variant_get_string (v, NULL), target) == 0); g_variant_unref (v); + g_free (target); } + else + g_assert_not_reached (); } g_free (label); + g_free (action); return w; } @@ -209,40 +267,69 @@ static void append_items_from_model (GtkWidget *menu, GMenuModel *model, GActionGroup *group, - gboolean *need_separator) + gboolean *need_separator, + const gchar *heading) { gint n; gint i; GtkWidget *w; GtkWidget *menuitem; - GMenuModelItem item; + GtkWidget *submenu; GMenuModel *m; + gchar *label; n = g_menu_model_get_n_items (model); if (*need_separator && n > 0) { - /* TODO section heading */ w = gtk_separator_menu_item_new (); gtk_widget_show (w); gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); - *need_separator = FALSE; } + if (heading != NULL) + { + w = gtk_menu_item_new_with_label (heading); + gtk_widget_show (w); + gtk_widget_set_sensitive (w, FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); +#if 0 + /* FIXME: this interferes with toggle spacing */ + w = gtk_bin_get_child (GTK_BIN (w)); + gtk_misc_set_alignment (GTK_MISC (w), 0.5, 0.5); +#endif + } + for (i = 0; i < n; i++) { - g_menu_model_get_item (model, i, &item); - if ((m = g_menu_model_item_get_link (&item, G_MENU_LINK_SECTION))) + if ((m = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION))) { - append_items_from_model (menu, m, group, need_separator); + label = NULL; + g_menu_model_get_item_attribute (model, i, G_MENU_ATTRIBUTE_LABEL, "s", &label); + append_items_from_model (menu, m, group, need_separator, label); + g_object_unref (m); + g_free (label); + + if (*need_separator) + { + w = gtk_separator_menu_item_new (); + gtk_widget_show (w); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); + *need_separator = FALSE; + } + continue; } - menuitem = create_menuitem_from_model (&item, group); + menuitem = create_menuitem_from_model (model, i, group); - if ((m = g_menu_model_item_get_link (&item, G_MENU_LINK_SUBMENU))) - gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), create_menu_from_model (m, group)); + if ((m = g_menu_model_get_item_link (model, i, G_MENU_LINK_SUBMENU))) + { + submenu = create_menu_from_model (m, group); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + g_object_unref (m); + } gtk_widget_show (menuitem); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); @@ -260,80 +347,116 @@ create_menu_from_model (GMenuModel *model, w = gtk_menu_new (); need_separator = FALSE; - append_items_from_model (w, model, group, &need_separator); + append_items_from_model (w, model, group, &need_separator, NULL); return w; } +/* }}}2 */ + +MenuHolder * +menu_holder_new (GMenuModel *model, + GActionGroup *group) +{ + MenuHolder *holder; + + holder = g_new (MenuHolder, 1); + holder->model = g_object_ref (model); + holder->group = g_object_ref (group); + holder->menu = create_menu_from_model (model, group); + holder->items_changed = FALSE; + + connect_to_items_changed (model, G_CALLBACK (items_changed), holder); + + return holder; +} + +GtkWidget * +menu_holder_get_menu (MenuHolder *holder) +{ + if (holder->items_changed) + { + holder->items_changed = FALSE; + gtk_widget_destroy (holder->menu); + holder->menu = create_menu_from_model (holder->model, holder->group); + } + + return holder->menu; +} + /* The example menu {{{1 */ static const gchar menu_markup[] = + "\n" "\n" "
\n" - " \n" - " \n" + " \n" + " undo\n" + " _Undo\n" + " \n" + " \n" + " Redo\n" + " redo\n" + " \n" "
\n" - "
\n" - "
\n" - " \n" - " \n" - " \n" + "
\n" + "
\n" + " Copy & Paste\n" + " \n" + " Cut\n" + " cut\n" + " \n" + " \n" + " Copy\n" + " copy\n" + " \n" + " \n" + " Paste\n" + " paste\n" + " \n" "
\n" "
\n" - " \n" - " \n" - " \n" - " \n" - " \n" + " \n" + " Bold\n" + " bold\n" + " \n" + " \n" + " Language\n" + " \n" + " Latin\n" + " lang\n" + " latin\n" + " \n" + " \n" + " Greek\n" + " lang\n" + " greek\n" + " \n" + " \n" + " Urdu\n" + " lang\n" + " urdu\n" + " \n" " \n" "
\n" - "
\n"; - -static void -start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) -{ - if (strcmp (element_name, "menu") == 0) - g_menu_markup_parser_start_menu (context, NULL); -} - -static void -end_element (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) -{ - GMenu **menu = user_data; - - if (strcmp (element_name, "menu") == 0) - *menu = g_menu_markup_parser_end_menu (context); -} - -static const GMarkupParser parser = { - start_element, end_element, NULL, NULL, NULL -}; + "\n" + "
\n"; static GMenuModel * get_model (void) { - GMarkupParseContext *context; - GMenu *menu = NULL; GError *error = NULL; + GtkBuilder *builder; + GMenuModel *menu; - context = g_markup_parse_context_new (&parser, 0, &menu, NULL); - if (!g_markup_parse_context_parse (context, menu_markup, -1, &error)) - { - g_warning ("menu parsing failed: %s\n", error->message); - exit (1); - } - g_markup_parse_context_free (context); - g_assert (menu); + builder = gtk_builder_new (); + gtk_builder_add_from_string (builder, menu_markup, -1, &error); + g_assert_no_error (error); - return G_MENU_MODEL (menu); + menu = g_object_ref (gtk_builder_get_object (builder, "edit-menu")); + g_object_unref (builder); + + return menu; } /* The example actions {{{1 */ @@ -345,23 +468,37 @@ activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) } static void -toggle_changed (GSimpleAction *action, GVariant *value, gpointer user_data) +activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data) { - g_print ("Toggle action %s state changed to %d\n", + GVariant *old_state, *new_state; + + old_state = g_action_get_state (G_ACTION (action)); + new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state)); + + g_print ("Toggle action %s activated, state changes from %d to %d\n", g_action_get_name (G_ACTION (action)), - g_variant_get_boolean (value)); + g_variant_get_boolean (old_state), + g_variant_get_boolean (new_state)); - g_simple_action_set_state (action, value); + g_simple_action_set_state (action, new_state); + g_variant_unref (old_state); } static void -radio_changed (GSimpleAction *action, GVariant *value, gpointer user_data) +activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data) { - g_print ("Radio action %s state changed to %s\n", + GVariant *old_state, *new_state; + + old_state = g_action_get_state (G_ACTION (action)); + new_state = g_variant_new_string (g_variant_get_string (parameter, NULL)); + + g_print ("Radio action %s activated, state changes from %s to %s\n", g_action_get_name (G_ACTION (action)), - g_variant_get_string (value, NULL)); + g_variant_get_string (old_state, NULL), + g_variant_get_string (new_state, NULL)); - g_simple_action_set_state (action, value); + g_simple_action_set_state (action, new_state); + g_variant_unref (old_state); } static GActionEntry actions[] = { @@ -370,8 +507,8 @@ static GActionEntry actions[] = { { "cut", activate_action, NULL, NULL, NULL }, { "copy", activate_action, NULL, NULL, NULL }, { "paste", activate_action, NULL, NULL, NULL }, - { "bold", NULL, NULL, "true", toggle_changed }, - { "lang", NULL, NULL, "'latin'", radio_changed }, + { "bold", activate_toggle, NULL, "true", NULL }, + { "lang", activate_radio, "s", "'latin'", NULL }, }; static GActionGroup * @@ -424,8 +561,10 @@ state_cell_func (GtkTreeViewColumn *column, gtk_cell_renderer_set_visible (cell, FALSE); g_object_set (cell, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); - if (state && - g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN) && + if (state == NULL) + return; + + if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN) && GTK_IS_CELL_RENDERER_TOGGLE (cell)) { gtk_cell_renderer_set_visible (cell, TRUE); @@ -433,8 +572,7 @@ state_cell_func (GtkTreeViewColumn *column, gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (cell), g_variant_get_boolean (state)); } - else if (state && - g_variant_is_of_type (state, G_VARIANT_TYPE_STRING) && + else if (g_variant_is_of_type (state, G_VARIANT_TYPE_STRING) && GTK_IS_CELL_RENDERER_COMBO (cell)) { gtk_cell_renderer_set_visible (cell, TRUE); @@ -442,8 +580,7 @@ state_cell_func (GtkTreeViewColumn *column, g_object_set (cell, "text", g_variant_get_string (state, NULL), NULL); } - if (state) - g_variant_unref (state); + g_variant_unref (state); } static void @@ -633,6 +770,36 @@ toggle_sumerian (GtkToggleButton *button, gpointer data) g_menu_remove (G_MENU (m), g_menu_model_get_n_items (m) - 1); } +static void +action_list_add (GtkTreeModel *store, + const gchar *action) +{ + GtkTreeIter iter; + + gtk_list_store_append (GTK_LIST_STORE (store), &iter); + gtk_list_store_set (GTK_LIST_STORE (store), &iter, 0, action, -1); +} + +static void +action_list_remove (GtkTreeModel *store, + const gchar *action) +{ + GtkTreeIter iter; + gchar *text; + + gtk_tree_model_get_iter_first (store, &iter); + do { + gtk_tree_model_get (store, &iter, 0, &text, -1); + if (g_strcmp0 (action, text) == 0) + { + g_free (text); + gtk_list_store_remove (GTK_LIST_STORE (store), &iter); + break; + } + g_free (text); + } while (gtk_tree_model_iter_next (store, &iter)); +} + static void toggle_italic (GtkToggleButton *button, gpointer data) { @@ -643,7 +810,6 @@ toggle_italic (GtkToggleButton *button, gpointer data) GMenuModel *m; GtkTreeView *tv = data; GtkTreeModel *store; - GtkTreeIter iter; model = g_object_get_data (G_OBJECT (button), "model"); group = g_object_get_data (G_OBJECT (button), "group"); @@ -656,24 +822,71 @@ toggle_italic (GtkToggleButton *button, gpointer data) if (adding) { action = g_simple_action_new_stateful ("italic", NULL, g_variant_new_boolean (FALSE)); - g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (group), - G_ACTION (action)); + g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (group), G_ACTION (action)); + g_signal_connect (action, "activate", G_CALLBACK (activate_toggle), NULL); g_object_unref (action); + action_list_add (store, "italic"); g_menu_insert (G_MENU (m), 1, "Italic", "italic"); - gtk_list_store_prepend (GTK_LIST_STORE (store), &iter); - gtk_list_store_set (GTK_LIST_STORE (store), &iter, - 0, "italic", - -1); } else { g_simple_action_group_remove (G_SIMPLE_ACTION_GROUP (group), "italic"); + action_list_remove (store, "italic"); g_menu_remove (G_MENU (m), 1); - gtk_tree_model_get_iter_first (store, &iter); - gtk_list_store_remove (GTK_LIST_STORE (store), &iter); } } +static void +toggle_speed (GtkToggleButton *button, gpointer data) +{ + GMenuModel *model; + GActionGroup *group; + GSimpleAction *action; + gboolean adding; + GMenuModel *m; + GMenu *submenu; + GtkTreeView *tv = data; + GtkTreeModel *store; + + model = g_object_get_data (G_OBJECT (button), "model"); + group = g_object_get_data (G_OBJECT (button), "group"); + + store = gtk_tree_view_get_model (tv); + + adding = gtk_toggle_button_get_active (button); + + m = g_menu_model_get_item_link (model, 1, G_MENU_LINK_SECTION); + if (adding) + { + action = g_simple_action_new ("faster", NULL); + g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (group), G_ACTION (action)); + g_signal_connect (action, "activate", G_CALLBACK (activate_action), NULL); + g_object_unref (action); + + action = g_simple_action_new ("slower", NULL); + g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (group), G_ACTION (action)); + g_signal_connect (action, "activate", G_CALLBACK (activate_action), NULL); + g_object_unref (action); + + action_list_add (store, "faster"); + action_list_add (store, "slower"); + + submenu = g_menu_new (); + g_menu_append (submenu, "Faster", "faster"); + g_menu_append (submenu, "Slower", "slower"); + g_menu_append_submenu (G_MENU (m), "Speed", G_MENU_MODEL (submenu)); + } + else + { + g_simple_action_group_remove (G_SIMPLE_ACTION_GROUP (group), "faster"); + g_simple_action_group_remove (G_SIMPLE_ACTION_GROUP (group), "slower"); + + action_list_remove (store, "faster"); + action_list_remove (store, "slower"); + + g_menu_remove (G_MENU (m), g_menu_model_get_n_items (m) - 1); + } +} static GtkWidget * create_add_remove_buttons (GActionGroup *group, GMenuModel *model, @@ -702,99 +915,41 @@ create_add_remove_buttons (GActionGroup *group, g_signal_connect (button, "toggled", G_CALLBACK (toggle_sumerian), NULL); + button = gtk_check_button_new_with_label ("Add Speed"); + gtk_container_add (GTK_CONTAINER (box), button); + + g_object_set_data (G_OBJECT (button), "group", group); + g_object_set_data (G_OBJECT (button), "model", model); + + g_signal_connect (button, "toggled", + G_CALLBACK (toggle_speed), treeview); return box; } -/* The menu button {{{1 */ +/* main {{{1 */ static void -button_clicked (GtkButton *button, gpointer data) +button_clicked (GtkButton *button, + MenuHolder *holder) { - GMenuModel *model; - GActionGroup *group; GtkWidget *menu; - menu = g_object_get_data (G_OBJECT (button), "menu"); - if (!menu) - { - model = g_object_get_data (G_OBJECT (button), "model"); - group = g_object_get_data (G_OBJECT (button), "group"); - menu = create_menu_from_model (model, group); - g_object_set_data_full (G_OBJECT (button), "menu", menu, (GDestroyNotify)gtk_widget_destroy); - } - + menu = menu_holder_get_menu (holder); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, 0); } -static void -items_changed (GMenuModel *model, - gint position, - gint removed, - gint added, - GtkButton *button) -{ - g_print ("Received GMenuModel::items-changed\n"); - g_object_set_data (G_OBJECT (button), "menu", NULL); -} +#define BUS_NAME "org.gtk.TestMenus" +#define OBJ_PATH "/org/gtk/TestMenus" -static void -action_added (GActionGroup *group, - const gchar *name, - gpointer data) +static gboolean +on_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) { - g_print ("Received GActionGroup::action-added\n"); + gtk_main_quit (); + return TRUE; } -static void -action_removed (GActionGroup *group, - const gchar *name, - gpointer data) -{ - g_print ("Received GActionGroup::action-removed\n"); -} - -static void -recursively_connect_to_items_changed (GMenuModel *model, - GCallback callback, - gpointer data) -{ - gint i; - GMenuModel *m; - GMenuLinkIter *iter; - - g_signal_connect (model, "items-changed", callback, data); - for (i = 0; i < g_menu_model_get_n_items (model); i++) - { - iter = g_menu_model_iterate_item_links (model, i); - while (g_menu_link_iter_next (iter)) - { - m = g_menu_link_iter_get_value (iter); - recursively_connect_to_items_changed (m, callback, data); - g_object_unref (m); - } - g_object_unref (iter); - } -} - -static GtkWidget * -create_menu_button (GMenuModel *model, GActionGroup *group) -{ - GtkWidget *button; - - button = gtk_button_new_with_label ("Click here"); - g_object_set_data (G_OBJECT (button), "model", model); - g_object_set_data (G_OBJECT (button), "group", group); - - g_signal_connect (button, "clicked", G_CALLBACK (button_clicked), NULL); - recursively_connect_to_items_changed (model, G_CALLBACK (items_changed), button); - g_signal_connect (group, "action-added", G_CALLBACK (action_added), NULL); - g_signal_connect (group, "action-removed", G_CALLBACK (action_removed), NULL); - - return button; -} - -/* main {{{1 */ - int main (int argc, char *argv[]) { @@ -803,6 +958,7 @@ main (int argc, char *argv[]) GtkWidget *button; GtkWidget *tv; GtkWidget *buttons; + MenuHolder *holder; GMenuModel *model; GActionGroup *group; GDBusConnection *bus; @@ -824,6 +980,7 @@ main (int argc, char *argv[]) } window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", G_CALLBACK(on_delete_event), NULL); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_add (GTK_CONTAINER (window), box); @@ -832,9 +989,9 @@ main (int argc, char *argv[]) if (do_import) { g_print ("Getting menus from the bus...\n"); - model = (GMenuModel*)g_menu_proxy_get (bus, "org.gtk.TestMenus", "/path"); + model = (GMenuModel*)g_dbus_menu_model_get (bus, BUS_NAME, OBJ_PATH); g_print ("Getting actions from the bus...\n"); - group = (GActionGroup*)g_dbus_action_group_new_sync (bus, "org.gtk.TestMenus", "/path", 0, NULL, NULL); + group = (GActionGroup*)g_dbus_action_group_get (bus, BUS_NAME, OBJ_PATH); } else { @@ -850,23 +1007,25 @@ main (int argc, char *argv[]) if (do_export) { g_print ("Exporting menus on the bus...\n"); - if (!g_menu_exporter_export (bus, "/path", model, &error)) + if (!g_dbus_connection_export_menu_model (bus, OBJ_PATH, model, &error)) { g_warning ("Menu export failed: %s", error->message); exit (1); } g_print ("Exporting actions on the bus...\n"); - if (!g_action_group_exporter_export (bus, "/path", group, &error)) + if (!g_dbus_connection_export_action_group (bus, OBJ_PATH, group, &error)) { g_warning ("Action export failed: %s", error->message); exit (1); } - g_bus_own_name_on_connection (bus, "org.gtk.TestMenus", - 0, NULL, NULL, NULL, NULL); + g_bus_own_name_on_connection (bus, BUS_NAME, 0, NULL, NULL, NULL, NULL); } else { - button = create_menu_button (model, group); + holder = menu_holder_new (model, group); + button = gtk_button_new_with_label ("Click here"); + g_signal_connect (button, "clicked", + G_CALLBACK (button_clicked), holder); gtk_container_add (GTK_CONTAINER (box), button); }