GtkApplication: Merge app menu and menubar
Change bloatpad to have both an app menu and a menubar.
This commit is contained in:

committed by
Ryan Lortie

parent
aae52d4580
commit
65a2962733
@ -1,48 +1,42 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
static void
|
static GtkClipboard *
|
||||||
show_about (GSimpleAction *action,
|
get_clipboard (GtkWidget *widget)
|
||||||
GVariant *parameter,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
GtkWindow *window = user_data;
|
return gtk_widget_get_clipboard (widget, gdk_atom_intern_static_string ("CLIPBOARD"));
|
||||||
|
|
||||||
gtk_show_about_dialog (window,
|
|
||||||
"program-name", "Bloatpad",
|
|
||||||
"title", "About Bloatpad",
|
|
||||||
"comments", "Not much to say, really.",
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
activate_toggle (GSimpleAction *action,
|
window_copy (GSimpleAction *action,
|
||||||
GVariant *parameter,
|
GVariant *parameter,
|
||||||
gpointer user_data)
|
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));
|
gtk_text_buffer_copy_clipboard (gtk_text_view_get_buffer (text),
|
||||||
g_action_change_state (G_ACTION (action), g_variant_new_boolean (!g_variant_get_boolean (state)));
|
get_clipboard ((GtkWidget*) text));
|
||||||
g_variant_unref (state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
change_fullscreen_state (GSimpleAction *action,
|
window_paste (GSimpleAction *action,
|
||||||
GVariant *state,
|
GVariant *parameter,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
if (g_variant_get_boolean (state))
|
GtkWindow *window = GTK_WINDOW (user_data);
|
||||||
gtk_window_fullscreen (user_data);
|
GtkTextView *text = g_object_get_data ((GObject*)window, "bloatpad-text");
|
||||||
else
|
|
||||||
gtk_window_unfullscreen (user_data);
|
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[] = {
|
static GActionEntry win_entries[] = {
|
||||||
{ "about", show_about },
|
{ "copy", window_copy, NULL, NULL, NULL },
|
||||||
{ "fullscreen", activate_toggle, NULL, "false", change_fullscreen_state }
|
{ "paste", window_paste, NULL, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -63,6 +57,8 @@ new_window (GApplication *app,
|
|||||||
gtk_widget_set_vexpand (scrolled, TRUE);
|
gtk_widget_set_vexpand (scrolled, TRUE);
|
||||||
view = gtk_text_view_new ();
|
view = gtk_text_view_new ();
|
||||||
|
|
||||||
|
g_object_set_data ((GObject*)window, "bloatpad-text", view);
|
||||||
|
|
||||||
gtk_container_add (GTK_CONTAINER (scrolled), view);
|
gtk_container_add (GTK_CONTAINER (scrolled), view);
|
||||||
|
|
||||||
gtk_grid_attach (GTK_GRID (grid), scrolled, 0, 0, 1, 1);
|
gtk_grid_attach (GTK_GRID (grid), scrolled, 0, 0, 1, 1);
|
||||||
@ -115,13 +111,20 @@ bloat_pad_finalize (GObject *object)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
show_help (GSimpleAction *action,
|
show_about (GSimpleAction *action,
|
||||||
GVariant *parameter,
|
GVariant *parameter,
|
||||||
gpointer user_data)
|
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
|
static void
|
||||||
quit_app (GSimpleAction *action,
|
quit_app (GSimpleAction *action,
|
||||||
GVariant *parameter,
|
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[] = {
|
static GActionEntry app_entries[] = {
|
||||||
{ "help", show_help, NULL, NULL, NULL },
|
{ "about", show_about, NULL, NULL, NULL },
|
||||||
{ "quit", quit_app, NULL, NULL, NULL },
|
{ "quit", quit_app, NULL, NULL, NULL },
|
||||||
{ "add", add_action, NULL, NULL, NULL },
|
|
||||||
{ "remove", remove_action, NULL, NULL, NULL }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static GActionGroup *
|
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,
|
g_simple_action_group_add_entries (actions,
|
||||||
app_entries, G_N_ELEMENTS (app_entries),
|
app_entries, G_N_ELEMENTS (app_entries),
|
||||||
NULL);
|
NULL);
|
||||||
@ -192,14 +164,29 @@ get_actions (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GMenuModel *
|
static GMenuModel *
|
||||||
get_menu (void)
|
create_app_menu (void)
|
||||||
{
|
{
|
||||||
menu = g_menu_new ();
|
GMenu *menu = g_menu_new ();
|
||||||
g_menu_append (menu, "_Help", "app.help");
|
g_menu_append (menu, "_About Bloatpad", "app.about");
|
||||||
g_menu_append (menu, "_About Bloatpad", "win.about");
|
|
||||||
g_menu_append (menu, "_Fullscreen", "win.fullscreen");
|
|
||||||
g_menu_append (menu, "_Quit", "app.quit");
|
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);
|
return G_MENU_MODEL (menu);
|
||||||
}
|
}
|
||||||
@ -207,8 +194,21 @@ get_menu (void)
|
|||||||
static void
|
static void
|
||||||
bloat_pad_init (BloatPad *app)
|
bloat_pad_init (BloatPad *app)
|
||||||
{
|
{
|
||||||
g_application_set_action_group (G_APPLICATION (app), get_actions ());
|
GActionGroup *actions;
|
||||||
g_application_set_app_menu (G_APPLICATION (app), get_menu ());
|
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
|
static void
|
||||||
|
@ -222,7 +222,6 @@ gtk_application_get_type
|
|||||||
gtk_application_get_windows
|
gtk_application_get_windows
|
||||||
gtk_application_new
|
gtk_application_new
|
||||||
gtk_application_remove_window
|
gtk_application_remove_window
|
||||||
gtk_application_window_get_app_menu
|
|
||||||
gtk_application_window_get_show_app_menu
|
gtk_application_window_get_show_app_menu
|
||||||
gtk_application_window_get_type
|
gtk_application_window_get_type
|
||||||
gtk_application_window_new
|
gtk_application_window_new
|
||||||
|
@ -64,6 +64,8 @@ struct _GtkApplicationWindowPrivate
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
recalculate_app_menu_state (GtkApplicationWindow *window);
|
recalculate_app_menu_state (GtkApplicationWindow *window);
|
||||||
|
static GtkWidget *
|
||||||
|
gtk_application_window_create_menubar (GtkApplicationWindow *window);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_shell_shows_app_menu_changed (GtkSettings *settings,
|
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->override_show_app_menu)
|
||||||
|| window->priv->default_show_app_menu)
|
|| window->priv->default_show_app_menu)
|
||||||
{
|
{
|
||||||
GtkWidget *menubar;
|
GtkWidget *menubar = gtk_application_window_create_menubar (window);
|
||||||
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 ();
|
|
||||||
window->priv->menubar = g_object_ref_sink (menubar);
|
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_set_parent (menubar, GTK_WIDGET (window));
|
||||||
gtk_widget_show_all (menubar);
|
gtk_widget_show_all (menubar);
|
||||||
}
|
}
|
||||||
@ -768,8 +763,8 @@ append_items_from_model (GtkMenuShell *menu,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
populate_menu_from_model (GtkMenuShell *menu,
|
populate_menu_from_model (GtkMenuShell *menu,
|
||||||
GMenuModel *model,
|
GMenuModel *model,
|
||||||
GActionGroup *group)
|
GActionGroup *group)
|
||||||
{
|
{
|
||||||
gboolean need_separator;
|
gboolean need_separator;
|
||||||
|
|
||||||
@ -778,7 +773,9 @@ populate_menu_from_model (GtkMenuShell *menu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
GActionMuxer *muxer;
|
||||||
GtkApplication *application;
|
GtkApplication *application;
|
||||||
|
GtkApplicationWindow *window;
|
||||||
GtkMenuShell *menu;
|
GtkMenuShell *menu;
|
||||||
guint update_idle;
|
guint update_idle;
|
||||||
GHashTable *connected;
|
GHashTable *connected;
|
||||||
@ -789,6 +786,8 @@ free_items_changed_data (gpointer data)
|
|||||||
{
|
{
|
||||||
ItemsChangedData *d = data;
|
ItemsChangedData *d = data;
|
||||||
|
|
||||||
|
g_object_unref (d->muxer);
|
||||||
|
g_object_unref (d->window);
|
||||||
g_object_unref (d->application);
|
g_object_unref (d->application);
|
||||||
|
|
||||||
if (d->update_idle != 0)
|
if (d->update_idle != 0)
|
||||||
@ -805,7 +804,9 @@ repopulate_menu (gpointer data)
|
|||||||
ItemsChangedData *d = data;
|
ItemsChangedData *d = data;
|
||||||
GList *children, *l;
|
GList *children, *l;
|
||||||
GtkWidget *child;
|
GtkWidget *child;
|
||||||
GMenuModel *model;
|
GtkMenuShell *app_shell;
|
||||||
|
GMenuModel *app_model;
|
||||||
|
GMenuModel *window_model;
|
||||||
|
|
||||||
/* remove current children */
|
/* remove current children */
|
||||||
children = gtk_container_get_children (GTK_CONTAINER (d->menu));
|
children = gtk_container_get_children (GTK_CONTAINER (d->menu));
|
||||||
@ -816,9 +817,23 @@ repopulate_menu (gpointer data)
|
|||||||
}
|
}
|
||||||
g_list_free (children);
|
g_list_free (children);
|
||||||
|
|
||||||
/* repopulate */
|
app_model = g_application_get_app_menu (G_APPLICATION (d->application));
|
||||||
model = g_application_get_app_menu (G_APPLICATION (d->application));
|
|
||||||
populate_menu_from_model (d->menu, model, G_ACTION_GROUP (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;
|
d->update_idle = 0;
|
||||||
|
|
||||||
@ -868,60 +883,43 @@ items_changed (GMenuModel *model,
|
|||||||
connect_to_items_changed (model, G_CALLBACK (items_changed), data);
|
connect_to_items_changed (model, G_CALLBACK (items_changed), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static GtkWidget *
|
||||||
* gtk_application_window_get_app_menu:
|
gtk_application_window_create_menubar (GtkApplicationWindow *window)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
GtkApplication *application;
|
GtkApplication *application;
|
||||||
GtkWidget *menu;
|
GMenuModel *app_model;
|
||||||
GMenuModel *model;
|
GMenuModel *win_model;
|
||||||
ItemsChangedData *data;
|
ItemsChangedData *data;
|
||||||
GActionMuxer *muxer;
|
GtkWidget *menubar;
|
||||||
|
|
||||||
application = gtk_window_get_application (GTK_WINDOW (window));
|
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 (!(app_model || win_model))
|
||||||
|
|
||||||
if (!model)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
menu = gtk_menu_new ();
|
menubar = gtk_menu_bar_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);
|
|
||||||
|
|
||||||
data = g_new (ItemsChangedData, 1);
|
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->application = g_object_ref (application);
|
||||||
data->menu = GTK_MENU_SHELL (menu);
|
data->menu = GTK_MENU_SHELL (menubar);
|
||||||
data->update_idle = 0;
|
data->update_idle = 0;
|
||||||
data->connected = g_hash_table_new (NULL, NULL);
|
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);
|
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);
|
||||||
|
|
||||||
return menu;
|
repopulate_menu (data);
|
||||||
|
|
||||||
|
return menubar;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user