Commit 4240bfb7 authored by Matthias Clasen's avatar Matthias Clasen

Add API to create menus from models

This is needed to bring context menus, etc into the GAction world.
parent e7d64001
......@@ -2059,6 +2059,7 @@ gtk_link_button_get_type
<TITLE>GtkMenu</TITLE>
GtkMenu
gtk_menu_new
gtk_menu_new_from_model
gtk_menu_set_screen
gtk_menu_reorder_child
gtk_menu_attach
......@@ -2103,6 +2104,7 @@ gtk_menu_get_type
<TITLE>GtkMenuBar</TITLE>
GtkMenuBar
gtk_menu_bar_new
gtk_menu_bar_new_from_model
GtkPackDirection
gtk_menu_bar_set_pack_direction
gtk_menu_bar_get_pack_direction
......
......@@ -1533,6 +1533,7 @@ gtk_menu_bar_get_child_pack_direction
gtk_menu_bar_get_pack_direction
gtk_menu_bar_get_type
gtk_menu_bar_new
gtk_menu_bar_new_from_model
gtk_menu_bar_set_child_pack_direction
gtk_menu_bar_set_pack_direction
gtk_menu_detach
......@@ -1569,6 +1570,7 @@ gtk_menu_item_set_use_underline
gtk_menu_item_toggle_size_allocate
gtk_menu_item_toggle_size_request
gtk_menu_new
gtk_menu_new_from_model
gtk_menu_popdown
gtk_menu_popup
gtk_menu_popup_for_device
......
......@@ -38,6 +38,13 @@ G_GNUC_INTERNAL
GSimpleActionObserver * gtk_application_window_create_observer (GtkApplicationWindow *window,
const gchar *action_name,
GVariant *target);
G_GNUC_INTERNAL
GActionObservable * gtk_application_window_get_observable (GtkApplicationWindow *window);
G_GNUC_INTERNAL
GtkAccelGroup * gtk_application_window_get_accel_group (GtkApplicationWindow *window);
G_GNUC_INTERNAL
const gchar * gtk_application_get_dbus_object_path (GtkApplication *application);
G_GNUC_INTERNAL
......
......@@ -1012,3 +1012,15 @@ gtk_application_window_create_observer (GtkApplicationWindow *window,
return g_simple_action_observer_new (window->priv->muxer, action_name, target);
}
GActionObservable *
gtk_application_window_get_observable (GtkApplicationWindow *window)
{
return G_ACTION_OBSERVABLE (window->priv->muxer);
}
GtkAccelGroup *
gtk_application_window_get_accel_group (GtkApplicationWindow *window)
{
return window->priv->accels;
}
......@@ -117,6 +117,7 @@ struct _GtkMenuClass
GType gtk_menu_get_type (void) G_GNUC_CONST;
GtkWidget* gtk_menu_new (void);
GtkWidget* gtk_menu_new_from_model (GMenuModel *model);
/* Display the menu onscreen */
void gtk_menu_popup (GtkMenu *menu,
......
......@@ -71,6 +71,7 @@ struct _GtkMenuBarClass
GType gtk_menu_bar_get_type (void) G_GNUC_CONST;
GtkWidget* gtk_menu_bar_new (void);
GtkWidget* gtk_menu_bar_new_from_model (GMenuModel *model);
GtkPackDirection gtk_menu_bar_get_pack_direction (GtkMenuBar *menubar);
void gtk_menu_bar_set_pack_direction (GtkMenuBar *menubar,
......
......@@ -29,6 +29,7 @@
#include "gtkmenubar.h"
#include "gtkseparatormenuitem.h"
#include "gtkmodelmenuitem.h"
#include "gtkapplicationprivate.h"
typedef struct {
GActionObservable *actions;
......@@ -65,6 +66,7 @@ gtk_model_menu_binding_free (gpointer data)
binding->connected = g_slist_delete_link (binding->connected, binding->connected);
}
if (binding->actions)
g_object_unref (binding->actions);
g_object_unref (binding->model);
......@@ -224,25 +226,38 @@ gtk_model_menu_binding_items_changed (GMenuModel *model,
}
}
void
static void
gtk_model_menu_bind (GtkMenuShell *shell,
GMenuModel *model,
GActionObservable *actions,
GtkAccelGroup *accels,
gboolean with_separators)
{
GtkModelMenuBinding *binding;
binding = g_slice_new (GtkModelMenuBinding);
binding->model = g_object_ref (model);
binding->actions = g_object_ref (actions);
binding->accels = accels;
binding->actions = NULL;
binding->accels = NULL;
binding->shell = shell;
binding->update_idle = 0;
binding->connected = NULL;
binding->with_separators = with_separators;
g_object_set_data_full (G_OBJECT (shell), "gtk-model-menu-binding", binding, gtk_model_menu_binding_free);
}
static void
gtk_model_menu_populate (GtkMenuShell *shell,
GActionObservable *actions,
GtkAccelGroup *accels)
{
GtkModelMenuBinding *binding;
binding = (GtkModelMenuBinding*) g_object_get_data (G_OBJECT (shell), "gtk-model-menu-binding");
binding->actions = g_object_ref (actions);
binding->accels = accels;
gtk_model_menu_binding_populate (binding);
}
......@@ -254,8 +269,59 @@ gtk_model_menu_create_menu (GMenuModel *model,
GtkWidget *menu;
menu = gtk_menu_new ();
gtk_menu_set_accel_group (GTK_MENU (menu), accels);
gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, actions, accels, TRUE);
gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, FALSE);
gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels);
return menu;
}
static void
notify_attach (GtkMenu *menu,
GParamSpec *pspec,
gpointer data)
{
GtkWidget *widget;
GtkWidget *toplevel;
GActionObservable *actions;
GtkAccelGroup *accels;
widget = gtk_menu_get_attach_widget (menu);
toplevel = gtk_widget_get_toplevel (widget);
if (GTK_IS_APPLICATION_WINDOW (toplevel))
{
actions = gtk_application_window_get_observable (GTK_APPLICATION_WINDOW (toplevel));
accels = gtk_application_window_get_accel_group (GTK_APPLICATION_WINDOW (toplevel));
gtk_model_menu_populate (GTK_MENU_SHELL (menu), actions, accels);
}
}
/**
* gtk_menu_new_from_model:
* @model: a #GMenuModel
*
* Creates a #GtkMenu and populates it with menu items and
* submenus according to @model.
*
* The created menu items are connected to actions found in the
* #GtkApplicationWindow to which the menu belongs - typically
* by means of being attached to a widget (see gtk_menu_attach_to_widget())
* that is contained within the #GtkApplicationWindows widget hierarchy.
*
* Returns: a new #GtkMenu
*
* Since: 3.4
*/
GtkWidget *
gtk_menu_new_from_model (GMenuModel *model)
{
GtkWidget *menu;
menu = gtk_menu_new ();
gtk_model_menu_bind (GTK_MENU_SHELL (menu), model, TRUE);
g_signal_connect (menu, "notify::attach-widget",
G_CALLBACK (notify_attach), NULL);
return menu;
}
......@@ -268,8 +334,59 @@ gtk_model_menu_create_menu_bar (GMenuModel *model,
GtkWidget *menubar;
menubar = gtk_menu_bar_new ();
gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, actions, accels, FALSE);
gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, FALSE);
gtk_model_menu_populate (GTK_MENU_SHELL (menubar), actions, accels);
return menubar;
}
static void
hierarchy_changed (GtkMenuShell *shell,
GObject *previous_toplevel,
gpointer data)
{
GtkWidget *toplevel;
GActionObservable *actions;
GtkAccelGroup *accels;
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
if (GTK_IS_APPLICATION_WINDOW (toplevel))
{
actions = gtk_application_window_get_observable (GTK_APPLICATION_WINDOW (toplevel));
accels = gtk_application_window_get_accel_group (GTK_APPLICATION_WINDOW (toplevel));
gtk_model_menu_populate (shell, actions, accels);
}
}
/**
* gtk_menu_bar_new_from_model:
* @model: a #GMenuModel
*
* Creates a new #GtkMenuBar and populates it with menu items
* and submenus according to @model.
*
* The created menu items are connected to actions found in the
* #GtkApplicationWindow to which the menu bar belongs - typically
* by means of being contained within the #GtkApplicationWindows
* widget hierarchy.
*
* Returns: a new #GtkMenuBar
*
* Since: 3.4
*/
GtkWidget *
gtk_menu_bar_new_from_model (GMenuModel *model)
{
GtkWidget *menubar;
menubar = gtk_menu_bar_new ();
gtk_model_menu_bind (GTK_MENU_SHELL (menubar), model, FALSE);
g_signal_connect (menubar, "hierarchy-changed",
G_CALLBACK (hierarchy_changed), NULL);
return menubar;
}
......@@ -27,19 +27,10 @@
#include <gtk/gtkaccelgroup.h>
#include <gio/gio.h>
G_GNUC_INTERNAL
void gtk_model_menu_bind (GtkMenuShell *shell,
GMenuModel *model,
GActionObservable *actions,
GtkAccelGroup *accels,
gboolean with_separators);
G_GNUC_INTERNAL
GtkWidget * gtk_model_menu_create_menu_bar (GMenuModel *model,
GActionObservable *actions,
GtkAccelGroup *accels);
G_GNUC_INTERNAL
GtkWidget * gtk_model_menu_create_menu (GMenuModel *model,
GActionObservable *actions,
GtkAccelGroup *accels);
......
......@@ -235,6 +235,8 @@ gtk_model_menu_item_setup (GtkModelMenuItem *item,
/* observer already causes us to hold a hard ref on the group */
item->actions = G_ACTION_GROUP (actions);
if (actions)
{
g_action_observable_register_observer (actions, item->action_name, G_ACTION_OBSERVER (item));
if (g_action_group_query_action (G_ACTION_GROUP (actions), item->action_name, &enabled, &type, NULL, NULL, &state))
......@@ -243,7 +245,9 @@ gtk_model_menu_item_setup (GtkModelMenuItem *item,
if (state != NULL)
g_variant_unref (state);
}
else
gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
}
else
gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment