[gtk+] Add API to create menus from models
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] Add API to create menus from models
- Date: Wed, 25 Jan 2012 03:28:04 +0000 (UTC)
commit 4240bfb74abf53adb07afc4135dadde4ab866b1f
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Jan 24 22:25:35 2012 -0500
Add API to create menus from models
This is needed to bring context menus, etc into the GAction world.
docs/reference/gtk/gtk3-sections.txt | 2 +
gtk/gtk.symbols | 2 +
gtk/gtkapplicationprivate.h | 7 ++
gtk/gtkapplicationwindow.c | 12 +++
gtk/gtkmenu.h | 1 +
gtk/gtkmenubar.h | 1 +
gtk/gtkmodelmenu.c | 135 +++++++++++++++++++++++++++++++--
gtk/gtkmodelmenu.h | 9 --
gtk/gtkmodelmenuitem.c | 18 +++--
9 files changed, 162 insertions(+), 25 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 3b2317e1..41e42a9 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -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
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 93a4a17..3f377b1 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -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
diff --git a/gtk/gtkapplicationprivate.h b/gtk/gtkapplicationprivate.h
index 4b24a53..10c5016 100644
--- a/gtk/gtkapplicationprivate.h
+++ b/gtk/gtkapplicationprivate.h
@@ -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
diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c
index fabf8ef..5f8b1b3 100644
--- a/gtk/gtkapplicationwindow.c
+++ b/gtk/gtkapplicationwindow.c
@@ -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;
+}
diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h
index 0228236..557949d 100644
--- a/gtk/gtkmenu.h
+++ b/gtk/gtkmenu.h
@@ -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,
diff --git a/gtk/gtkmenubar.h b/gtk/gtkmenubar.h
index bc1f66c..967b04d 100644
--- a/gtk/gtkmenubar.h
+++ b/gtk/gtkmenubar.h
@@ -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,
diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c
index d91d92b..df08f71 100644
--- a/gtk/gtkmodelmenu.c
+++ b/gtk/gtkmodelmenu.c
@@ -29,6 +29,7 @@
#include "gtkmenubar.h"
#include "gtkseparatormenuitem.h"
#include "gtkmodelmenuitem.h"
+#include "gtkapplicationprivate.h"
typedef struct {
GActionObservable *actions;
@@ -65,7 +66,8 @@ gtk_model_menu_binding_free (gpointer data)
binding->connected = g_slist_delete_link (binding->connected, binding->connected);
}
- g_object_unref (binding->actions);
+ if (binding->actions)
+ g_object_unref (binding->actions);
g_object_unref (binding->model);
g_slice_free (GtkModelMenuBinding, binding);
@@ -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;
+}
diff --git a/gtk/gtkmodelmenu.h b/gtk/gtkmodelmenu.h
index 827d143..e1f388b 100644
--- a/gtk/gtkmodelmenu.h
+++ b/gtk/gtkmodelmenu.h
@@ -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);
diff --git a/gtk/gtkmodelmenuitem.c b/gtk/gtkmodelmenuitem.c
index eb7b8f3..e6dd987 100644
--- a/gtk/gtkmodelmenuitem.c
+++ b/gtk/gtkmodelmenuitem.c
@@ -235,15 +235,19 @@ 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);
- 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))
+ if (actions)
{
- gtk_model_menu_item_action_added (G_ACTION_OBSERVER (item), actions, item->action_name, type, enabled, state);
- if (state != NULL)
- g_variant_unref (state);
+ 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))
+ {
+ gtk_model_menu_item_action_added (G_ACTION_OBSERVER (item), actions, item->action_name, type, enabled, state);
+ 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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]