diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c index dccf72a..4574e64 100644 --- a/gtk/gtkmodelmenu.c +++ b/gtk/gtkmodelmenu.c @@ -28,6 +28,7 @@ #include "gtkseparatormenuitem.h" #include "gtkmodelmenuitem.h" #include "gtkapplicationprivate.h" +#include "gtkwidgetprivate.h" #define MODEL_MENU_WIDGET_DATA "gtk-model-menu-widget-data" @@ -73,6 +74,80 @@ gtk_model_menu_binding_free (gpointer data) g_slice_free (GtkModelMenuBinding, binding); } +static GtkMenuItem * +gtk_model_menu_create_custom_item (GMenuModel *menu, + gint item_index, + const gchar *action_namespace) +{ + GtkMenuItem *item = NULL; + gchar *typename = NULL; + GType type; + GObjectClass *class = NULL; + GParamSpec *pspec; + GMenuItem *menuitem = NULL; + + if (!g_menu_model_get_item_attribute (menu, item_index, "x-canonical-type", "s", &typename)) + return NULL; + + type = g_type_from_name (typename); + if (type == 0) + { + g_warning ("gtk_menu_new_from_model: cannot find type '%s'", typename); + goto out; + } + if (!g_type_is_a (type, GTK_TYPE_MENU_ITEM)) + { + g_warning ("gtk_menu_new_from_model: '%s' is not derived from GtkMenuItem", typename); + goto out; + } + + class = g_type_class_ref (type); + + pspec = g_object_class_find_property (class, "menu-item"); + if (pspec == NULL || G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_MENU_ITEM) + { + g_warning ("gtk_menu_new_from_model: '%s' does not have a 'menu-item' property", typename); + goto out; + } + + pspec = g_object_class_find_property (class, "action-group"); + if (pspec == NULL || G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_ACTION_GROUP) + { + g_warning ("gtk_menu_new_from_model: '%s' does not have an 'action-group' property", typename); + goto out; + } + + menuitem = g_menu_item_new_from_model (menu, item_index); + if (action_namespace) + { + gchar *action; + gchar *fullname; + + g_menu_item_get_attribute (menuitem, G_MENU_ATTRIBUTE_ACTION, "s", &action); + fullname = g_strconcat (action_namespace, ".", action, NULL); + g_menu_item_set_attribute (menuitem, G_MENU_ATTRIBUTE_ACTION, "s", fullname); + + g_free (action); + g_free (fullname); + } + + item = g_object_new (type, + "menu-item", menuitem, + NULL); + + g_object_set (item, + "action-group", _gtk_widget_get_action_muxer (GTK_WIDGET (item)), + NULL); + +out: + if (menuitem) + g_object_unref (menuitem); + if (class) + g_type_class_unref (class); + g_free (typename); + return item; +} + static void gtk_model_menu_binding_append_item (GtkModelMenuBinding *binding, GMenuModel *model, @@ -84,7 +159,7 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding *binding, if ((section = g_menu_model_get_item_link (model, item_index, "section"))) { - const gchar *section_namespace = NULL; + gchar *section_namespace = NULL; g_menu_model_get_item_attribute (model, item_index, "label", "s", heading); g_menu_model_get_item_attribute (model, item_index, "action-namespace", "s", §ion_namespace); @@ -107,7 +182,10 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding *binding, { GtkMenuItem *item; - item = gtk_model_menu_item_new (model, item_index, action_namespace, binding->accels); + item = gtk_model_menu_create_custom_item (model, item_index, action_namespace); + if (item == NULL) + item = gtk_model_menu_item_new (model, item_index, action_namespace, binding->accels); + gtk_menu_shell_append (binding->shell, GTK_WIDGET (item)); gtk_widget_show (GTK_WIDGET (item)); binding->n_items++;