From 65a2962733f0157c3a86d19fb839554e9c8d66e5 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 1 Dec 2011 16:46:36 -0500 Subject: [PATCH 1/1] GtkApplication: Merge app menu and menubar Change bloatpad to have both an app menu and a menubar. --- examples/bloatpad.c | 148 ++++++++++++++++++------------------- gtk/gtk.symbols | 1 - gtk/gtkapplicationwindow.c | 104 +++++++++++++------------- 3 files changed, 125 insertions(+), 128 deletions(-) diff --git a/examples/bloatpad.c b/examples/bloatpad.c index 5ec5f3935..161d33e1a 100644 --- a/examples/bloatpad.c +++ b/examples/bloatpad.c @@ -1,48 +1,42 @@ #include #include -static void -show_about (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +static GtkClipboard * +get_clipboard (GtkWidget *widget) { - GtkWindow *window = user_data; - - gtk_show_about_dialog (window, - "program-name", "Bloatpad", - "title", "About Bloatpad", - "comments", "Not much to say, really.", - NULL); + return gtk_widget_get_clipboard (widget, gdk_atom_intern_static_string ("CLIPBOARD")); } static void -activate_toggle (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +window_copy (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) { - GVariant *state; + GtkWindow *window = GTK_WINDOW (user_data); + GtkTextView *text = g_object_get_data ((GObject*)window, "bloatpad-text"); - state = g_action_get_state (G_ACTION (action)); - g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state))); - g_variant_unref (state); + gtk_text_buffer_copy_clipboard (gtk_text_view_get_buffer (text), + get_clipboard ((GtkWidget*) text)); } static void -change_fullscreen_state (GSimpleAction *action, - GVariant *state, - gpointer user_data) +window_paste (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) { - if (g_variant_get_boolean (state)) - gtk_window_fullscreen (user_data); - else - gtk_window_unfullscreen (user_data); + GtkWindow *window = GTK_WINDOW (user_data); + GtkTextView *text = g_object_get_data ((GObject*)window, "bloatpad-text"); + + gtk_text_buffer_paste_clipboard (gtk_text_view_get_buffer (text), + get_clipboard ((GtkWidget*) text), + NULL, + TRUE); - g_simple_action_set_state (action, state); } static GActionEntry win_entries[] = { - { "about", show_about }, - { "fullscreen", activate_toggle, NULL, "false", change_fullscreen_state } + { "copy", window_copy, NULL, NULL, NULL }, + { "paste", window_paste, NULL, NULL, NULL }, }; static void @@ -63,6 +57,8 @@ new_window (GApplication *app, gtk_widget_set_vexpand (scrolled, TRUE); view = gtk_text_view_new (); + g_object_set_data ((GObject*)window, "bloatpad-text", view); + gtk_container_add (GTK_CONTAINER (scrolled), view); gtk_grid_attach (GTK_GRID (grid), scrolled, 0, 0, 1, 1); @@ -115,13 +111,20 @@ bloat_pad_finalize (GObject *object) } static void -show_help (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +show_about (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) { - g_print ("Want help, eh ?!\n"); + GtkWindow *window = user_data; + + gtk_show_about_dialog (window, + "program-name", "Bloatpad", + "title", "About Bloatpad", + "comments", "Not much to say, really.", + NULL); } + static void quit_app (GSimpleAction *action, GVariant *parameter, @@ -144,46 +147,15 @@ quit_app (GSimpleAction *action, } } -static GSimpleActionGroup *actions = NULL; -static GMenu *menu = NULL; - -static void -remove_action (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) -{ - GAction *add; - - g_menu_remove (menu, g_menu_model_get_n_items (G_MENU_MODEL (menu)) - 1); - g_simple_action_set_enabled (action, FALSE); - add = g_simple_action_group_lookup (actions, "add"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (add), TRUE); -} - -static void -add_action (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) -{ - GAction *remove; - - g_menu_append (menu, "Remove", "app.remove"); - g_simple_action_set_enabled (action, FALSE); - remove = g_simple_action_group_lookup (actions, "remove"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (remove), TRUE); -} - static GActionEntry app_entries[] = { - { "help", show_help, NULL, NULL, NULL }, + { "about", show_about, NULL, NULL, NULL }, { "quit", quit_app, NULL, NULL, NULL }, - { "add", add_action, NULL, NULL, NULL }, - { "remove", remove_action, NULL, NULL, NULL } }; static GActionGroup * -get_actions (void) +create_app_actions (void) { - actions = g_simple_action_group_new (); + GSimpleActionGroup *actions = g_simple_action_group_new (); g_simple_action_group_add_entries (actions, app_entries, G_N_ELEMENTS (app_entries), NULL); @@ -192,14 +164,29 @@ get_actions (void) } static GMenuModel * -get_menu (void) +create_app_menu (void) { - menu = g_menu_new (); - g_menu_append (menu, "_Help", "app.help"); - g_menu_append (menu, "_About Bloatpad", "win.about"); - g_menu_append (menu, "_Fullscreen", "win.fullscreen"); + GMenu *menu = g_menu_new (); + g_menu_append (menu, "_About Bloatpad", "app.about"); g_menu_append (menu, "_Quit", "app.quit"); - g_menu_append (menu, "Add", "app.add"); + + return G_MENU_MODEL (menu); +} + +static GMenuModel * +create_window_menu (void) +{ + GMenu *menu; + GMenu *edit_menu; + + edit_menu = g_menu_new (); + g_menu_append (edit_menu, "_Copy", "win.copy"); + g_menu_append (edit_menu, "_Paste", "win.paste"); + + g_menu_append (edit_menu, "_Fullscreen", "win.fullscreen"); + + menu = g_menu_new (); + g_menu_append_section (menu, "_Edit", (GMenuModel*)edit_menu); return G_MENU_MODEL (menu); } @@ -207,8 +194,21 @@ get_menu (void) static void bloat_pad_init (BloatPad *app) { - g_application_set_action_group (G_APPLICATION (app), get_actions ()); - g_application_set_app_menu (G_APPLICATION (app), get_menu ()); + GActionGroup *actions; + GMenuModel *app_menu; + GMenuModel *window_menu; + + actions = create_app_actions (); + g_application_set_action_group (G_APPLICATION (app), actions); + g_object_unref (actions); + + app_menu = create_app_menu (); + g_application_set_app_menu (G_APPLICATION (app), app_menu); + g_object_unref (app_menu); + + window_menu = create_window_menu (); + g_application_set_menubar (G_APPLICATION (app), window_menu); + g_object_unref (window_menu); } static void diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index b4fcf741c..56816c4d9 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -222,7 +222,6 @@ gtk_application_get_type gtk_application_get_windows gtk_application_new gtk_application_remove_window -gtk_application_window_get_app_menu gtk_application_window_get_show_app_menu gtk_application_window_get_type gtk_application_window_new diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c index 807caa3e5..d2cb2646b 100644 --- a/gtk/gtkapplicationwindow.c +++ b/gtk/gtkapplicationwindow.c @@ -64,6 +64,8 @@ struct _GtkApplicationWindowPrivate static void recalculate_app_menu_state (GtkApplicationWindow *window); +static GtkWidget * +gtk_application_window_create_menubar (GtkApplicationWindow *window); static void on_shell_shows_app_menu_changed (GtkSettings *settings, @@ -478,15 +480,8 @@ recalculate_app_menu_state (GtkApplicationWindow *window) && window->priv->override_show_app_menu) || window->priv->default_show_app_menu) { - GtkWidget *menubar; - GtkWidget *item; - - item = gtk_menu_item_new_with_label (_("Application")); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), gtk_application_window_get_app_menu (window)); - - menubar = gtk_menu_bar_new (); + GtkWidget *menubar = gtk_application_window_create_menubar (window); window->priv->menubar = g_object_ref_sink (menubar); - gtk_menu_shell_append (GTK_MENU_SHELL (menubar), item); gtk_widget_set_parent (menubar, GTK_WIDGET (window)); gtk_widget_show_all (menubar); } @@ -768,8 +763,8 @@ append_items_from_model (GtkMenuShell *menu, static void populate_menu_from_model (GtkMenuShell *menu, - GMenuModel *model, - GActionGroup *group) + GMenuModel *model, + GActionGroup *group) { gboolean need_separator; @@ -778,7 +773,9 @@ populate_menu_from_model (GtkMenuShell *menu, } typedef struct { + GActionMuxer *muxer; GtkApplication *application; + GtkApplicationWindow *window; GtkMenuShell *menu; guint update_idle; GHashTable *connected; @@ -789,6 +786,8 @@ free_items_changed_data (gpointer data) { ItemsChangedData *d = data; + g_object_unref (d->muxer); + g_object_unref (d->window); g_object_unref (d->application); if (d->update_idle != 0) @@ -805,7 +804,9 @@ repopulate_menu (gpointer data) ItemsChangedData *d = data; GList *children, *l; GtkWidget *child; - GMenuModel *model; + GtkMenuShell *app_shell; + GMenuModel *app_model; + GMenuModel *window_model; /* remove current children */ children = gtk_container_get_children (GTK_CONTAINER (d->menu)); @@ -816,9 +817,23 @@ repopulate_menu (gpointer data) } g_list_free (children); - /* repopulate */ - model = g_application_get_app_menu (G_APPLICATION (d->application)); - populate_menu_from_model (d->menu, model, G_ACTION_GROUP (d->application)); + app_model = g_application_get_app_menu (G_APPLICATION (d->application)); + + if (app_model) + { + child = gtk_menu_item_new_with_label (_("Application")); + app_shell = (GtkMenuShell*)gtk_menu_new (); + gtk_menu_item_set_submenu ((GtkMenuItem*)child, (GtkWidget*)app_shell); + /* repopulate */ + populate_menu_from_model (app_shell, app_model, (GActionGroup*)d->muxer); + gtk_menu_shell_append ((GtkMenuShell*)d->menu, child); + } + + window_model = g_application_get_menubar (G_APPLICATION (d->application)); + if (window_model) + { + populate_menu_from_model (d->menu, window_model, (GActionGroup*)d->muxer); + } d->update_idle = 0; @@ -868,60 +883,43 @@ items_changed (GMenuModel *model, connect_to_items_changed (model, G_CALLBACK (items_changed), data); } -/** - * gtk_application_window_get_app_menu: - * @window: a #GtkApplicationWindow - * - * Populates a menu widget from a menu model that is - * associated with @window. See g_application_set_menu(). - * The menu items will be connected to actions of @window or - * its associated #GtkApplication, as indicated by the menu model. - * The menus contents will be updated automatically in response - * to menu model changes. - * - * It is the callers responsibility to add the menu at a - * suitable place in the widget hierarchy. - * - * This function returns %NULL if @window has no associated - * menu model. - * - * Returns: A #GtkMenu that has been populated from the - * #GMenuModel that is associated with @window, or %NULL - */ -GtkWidget * -gtk_application_window_get_app_menu (GtkApplicationWindow *window) +static GtkWidget * +gtk_application_window_create_menubar (GtkApplicationWindow *window) { GtkApplication *application; - GtkWidget *menu; - GMenuModel *model; + GMenuModel *app_model; + GMenuModel *win_model; ItemsChangedData *data; - GActionMuxer *muxer; + GtkWidget *menubar; application = gtk_window_get_application (GTK_WINDOW (window)); + app_model = g_application_get_app_menu (G_APPLICATION (application)); + win_model = g_application_get_menubar (G_APPLICATION (application)); - model = g_application_get_app_menu (G_APPLICATION (application)); - - if (!model) + if (!(app_model || win_model)) return NULL; - menu = gtk_menu_new (); - - muxer = g_action_muxer_new (); - g_action_muxer_insert (muxer, "app", G_ACTION_GROUP (application)); - g_action_muxer_insert (muxer, "win", G_ACTION_GROUP (window)); - populate_menu_from_model (GTK_MENU_SHELL (menu), model, G_ACTION_GROUP (muxer)); - g_object_unref (muxer); + menubar = gtk_menu_bar_new (); data = g_new (ItemsChangedData, 1); + data->muxer = g_action_muxer_new (); + g_action_muxer_insert (data->muxer, "app", G_ACTION_GROUP (application)); + g_action_muxer_insert (data->muxer, "win", G_ACTION_GROUP (window)); + data->window = g_object_ref (window); data->application = g_object_ref (application); - data->menu = GTK_MENU_SHELL (menu); + data->menu = GTK_MENU_SHELL (menubar); data->update_idle = 0; data->connected = g_hash_table_new (NULL, NULL); - g_object_set_data_full (G_OBJECT (menu), "gtk-application-menu-data", + g_object_set_data_full (G_OBJECT (menubar), "gtk-application-menu-data", data, free_items_changed_data); - connect_to_items_changed (model, G_CALLBACK (items_changed), data); + if (app_model) + connect_to_items_changed (app_model, G_CALLBACK (items_changed), data); + if (win_model) + connect_to_items_changed (win_model, G_CALLBACK (items_changed), data); + + repopulate_menu (data); - return menu; + return menubar; } -- 2.43.2