X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=tests%2Ftestgmenu.c;h=2f0512896b64c7c8135164ef7656036201c597cb;hb=HEAD;hp=61df703df388b8aa4d24fca096bed1b86778bb0d;hpb=1aec8e22b6da6e39034acfff74f6c8ebf34d4520;p=~andy%2Fgtk diff --git a/tests/testgmenu.c b/tests/testgmenu.c index 61df703df..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 @@ -27,10 +25,7 @@ * * - Labeled sections * - * - More dynamic changes. Add/Remove sections, submenus. - * - * - Focus changes. Verify that stopping subscriptions works - * as intended. + * - Focus changes. Verify that stopping subscriptions works. * * - Other attributes. What about icons ? */ @@ -93,6 +88,7 @@ typedef struct { gchar *target; gulong enabled_changed_id; gulong state_changed_id; + gulong activate_handler; } ActionData; static void @@ -128,7 +124,12 @@ toggle_state_changed (GActionGroup *group, GVariant *state, GtkCheckMenuItem *w) { + ActionData *a; + + 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 @@ -141,9 +142,10 @@ radio_state_changed (GActionGroup *group, gboolean b; 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 */ @@ -153,51 +155,22 @@ item_activated (GtkWidget *w, gpointer data) { ActionData *a; + GVariant *parameter; a = g_object_get_data (G_OBJECT (w), "action"); - g_action_group_activate_action (a->group, a->name, NULL); -} - -static void -toggle_item_toggled (GtkCheckMenuItem *w, - gpointer data) -{ - ActionData *a; - gboolean b; - - a = g_object_get_data (G_OBJECT (w), "action"); - b = gtk_check_menu_item_get_active (w); - g_action_group_change_action_state (a->group, a->name, - g_variant_new_boolean (b)); -} - -static void -radio_item_toggled (GtkCheckMenuItem *w, - gpointer data) -{ - ActionData *a; - GVariant *v; - - a = g_object_get_data (G_OBJECT (w), "action"); - if (gtk_check_menu_item_get_active (w)) - { - g_action_group_change_action_state (a->group, a->name, - g_variant_new_string (a->target)); - } + if (a->target) + parameter = 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); - } + 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; @@ -208,10 +181,11 @@ create_menuitem_from_model (GMenuModelItem *item, 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); @@ -245,11 +219,14 @@ create_menuitem_from_model (GMenuModelItem *item, G_CALLBACK (enabled_changed), w); g_free (s); + a->activate_handler = g_signal_connect (w, "activate", G_CALLBACK (item_activated), NULL); + if (type == NULL) - g_signal_connect (w, "activate", G_CALLBACK (item_activated), 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); a->state_changed_id = g_signal_connect (group, s, G_CALLBACK (toggle_state_changed), w); @@ -261,12 +238,11 @@ 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); 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); + 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), @@ -291,15 +267,16 @@ 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; GtkWidget *submenu; - GMenuModelItem item; GMenuModel *m; + gchar *label; n = g_menu_model_get_n_items (model); @@ -308,24 +285,46 @@ append_items_from_model (GtkWidget *menu, w = gtk_separator_menu_item_new (); gtk_widget_show (w); gtk_menu_shell_append (GTK_MENU_SHELL (menu), w); - *need_separator = FALSE; } - for (i = 0; i < n; i++) + if (heading != NULL) { - g_menu_model_get_item (model, i, &item); + 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 + } - if ((m = g_menu_model_item_get_link (&item, G_MENU_LINK_SECTION))) + for (i = 0; i < n; i++) + { + 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))) + 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); @@ -348,7 +347,7 @@ 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; } @@ -388,72 +387,76 @@ menu_holder_get_menu (MenuHolder *holder) /* 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 */ @@ -465,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[] = { @@ -490,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 * @@ -544,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); @@ -553,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); @@ -562,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 @@ -753,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) { @@ -763,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"); @@ -777,23 +823,70 @@ toggle_italic (GtkToggleButton *button, gpointer data) { 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_signal_connect (action, "change-state", G_CALLBACK (toggle_changed), NULL); + 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, @@ -822,6 +915,14 @@ 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; } @@ -837,6 +938,18 @@ button_clicked (GtkButton *button, gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, 0); } +#define BUS_NAME "org.gtk.TestMenus" +#define OBJ_PATH "/org/gtk/TestMenus" + +static gboolean +on_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + gtk_main_quit (); + return TRUE; +} + int main (int argc, char *argv[]) { @@ -867,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); @@ -875,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 { @@ -893,19 +1007,18 @@ 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 {