1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkItemFactory: Flexible item factory with automatic rc handling
5 * Copyright (C) 1998 Tim Janik
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
25 * file for a list of people on the GTK+ Team. See the ChangeLog
26 * files for a list of changes. These files are distributed with
27 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
32 #undef GTK_DISABLE_DEPRECATED
33 #include "gtkitemfactory.h"
34 #include "gtkoptionmenu.h"
35 #include "gtkmenubar.h"
37 #include "gtkmenuitem.h"
38 #include "gtkradiomenuitem.h"
39 #include "gtkcheckmenuitem.h"
40 #include "gtkimagemenuitem.h"
41 #include "gtktearoffmenuitem.h"
42 #include "gtkaccelmap.h"
43 #include "gtkaccellabel.h"
44 #include "gdk/gdkkeysyms.h"
47 #include "gtkiconfactory.h"
59 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
60 #define ITEM_BLOCK_SIZE (128)
63 /* --- structures --- */
64 typedef struct _GtkIFCBData GtkIFCBData;
65 typedef struct _GtkIFDumpData GtkIFDumpData;
68 GtkItemFactoryCallback func;
71 guint callback_action;
75 /* --- prototypes --- */
76 static void gtk_item_factory_destroy (GtkObject *object);
77 static void gtk_item_factory_finalize (GObject *object);
80 /* --- static variables --- */
81 static const gchar item_factory_string[] = "Gtk-<ItemFactory>";
82 static GQuark quark_popup_data = 0;
83 static GQuark quark_if_menu_pos = 0;
84 static GQuark quark_item_factory = 0;
85 static GQuark quark_item_path = 0;
86 static GQuark quark_action = 0;
87 static GQuark quark_accel_group = 0;
88 static GQuark quark_type_item = 0;
89 static GQuark quark_type_title = 0;
90 static GQuark quark_type_radio_item = 0;
91 static GQuark quark_type_check_item = 0;
92 static GQuark quark_type_toggle_item = 0;
93 static GQuark quark_type_image_item = 0;
94 static GQuark quark_type_stock_item = 0;
95 static GQuark quark_type_tearoff_item = 0;
96 static GQuark quark_type_separator_item = 0;
97 static GQuark quark_type_branch = 0;
98 static GQuark quark_type_last_branch = 0;
100 G_DEFINE_TYPE (GtkItemFactory, gtk_item_factory, GTK_TYPE_OBJECT)
102 /* --- functions --- */
104 gtk_item_factory_class_init (GtkItemFactoryClass *class)
106 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
107 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
109 gobject_class->finalize = gtk_item_factory_finalize;
111 object_class->destroy = gtk_item_factory_destroy;
113 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
115 quark_popup_data = g_quark_from_static_string ("GtkItemFactory-popup-data");
116 quark_if_menu_pos = g_quark_from_static_string ("GtkItemFactory-menu-position");
117 quark_item_factory = g_quark_from_static_string ("GtkItemFactory");
118 quark_item_path = g_quark_from_static_string ("GtkItemFactory-path");
119 quark_action = g_quark_from_static_string ("GtkItemFactory-action");
120 quark_accel_group = g_quark_from_static_string ("GtkAccelGroup");
121 quark_type_item = g_quark_from_static_string ("<Item>");
122 quark_type_title = g_quark_from_static_string ("<Title>");
123 quark_type_radio_item = g_quark_from_static_string ("<RadioItem>");
124 quark_type_check_item = g_quark_from_static_string ("<CheckItem>");
125 quark_type_toggle_item = g_quark_from_static_string ("<ToggleItem>");
126 quark_type_image_item = g_quark_from_static_string ("<ImageItem>");
127 quark_type_stock_item = g_quark_from_static_string ("<StockItem>");
128 quark_type_separator_item = g_quark_from_static_string ("<Separator>");
129 quark_type_tearoff_item = g_quark_from_static_string ("<Tearoff>");
130 quark_type_branch = g_quark_from_static_string ("<Branch>");
131 quark_type_last_branch = g_quark_from_static_string ("<LastBranch>");
135 gtk_item_factory_init (GtkItemFactory *ifactory)
137 ifactory->path = NULL;
138 ifactory->accel_group = NULL;
139 ifactory->widget = NULL;
140 ifactory->items = NULL;
141 ifactory->translate_func = NULL;
142 ifactory->translate_data = NULL;
143 ifactory->translate_notify = NULL;
147 * gtk_item_factory_new:
148 * @container_type: the kind of menu to create; can be
149 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
150 * @path: the factory path of the new item factory, a string of the form
151 * <literal>"<name>"</literal>
152 * @accel_group: a #GtkAccelGroup to which the accelerators for the
153 * menu items will be added, or %NULL to create a new one
154 * @returns: a new #GtkItemFactory
156 * Creates a new #GtkItemFactory.
158 * Beware that the returned object does not have a floating reference.
163 gtk_item_factory_new (GType container_type,
165 GtkAccelGroup *accel_group)
167 GtkItemFactory *ifactory;
169 g_return_val_if_fail (path != NULL, NULL);
171 ifactory = g_object_new (GTK_TYPE_ITEM_FACTORY, NULL);
172 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
178 gtk_item_factory_callback_marshal (GtkWidget *widget,
185 if (data->callback_type == 1)
187 GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
188 func1 (data->func_data, data->callback_action, widget);
190 else if (data->callback_type == 2)
192 GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
193 func2 (widget, data->func_data, data->callback_action);
198 gtk_item_factory_item_remove_widget (GtkWidget *widget,
199 GtkItemFactoryItem *item)
201 item->widgets = g_slist_remove (item->widgets, widget);
202 g_object_set_qdata (G_OBJECT (widget), quark_item_factory, NULL);
203 g_object_set_qdata (G_OBJECT (widget), quark_item_path, NULL);
207 * gtk_item_factory_add_foreign:
208 * @accel_widget: widget to install an accelerator on
209 * @full_path: the full path for the @accel_widget
210 * @accel_group: the accelerator group to install the accelerator in
211 * @keyval: key value of the accelerator
212 * @modifiers: modifier combination of the accelerator
214 * Installs an accelerator for @accel_widget in @accel_group, that causes
215 * the ::activate signal to be emitted if the accelerator is activated.
217 * This function can be used to make widgets participate in the accel
218 * saving/restoring functionality provided by gtk_accel_map_save() and
219 * gtk_accel_map_load(), even if they haven't been created by an item
222 * Deprecated: 2.4: The recommended API for this purpose are the functions
223 * gtk_menu_item_set_accel_path() and gtk_widget_set_accel_path(); don't
224 * use gtk_item_factory_add_foreign() in new code, since it is likely to
225 * be removed in the future.
228 gtk_item_factory_add_foreign (GtkWidget *accel_widget,
229 const gchar *full_path,
230 GtkAccelGroup *accel_group,
232 GdkModifierType modifiers)
234 GtkItemFactoryClass *class;
235 GtkItemFactoryItem *item;
237 g_return_if_fail (GTK_IS_WIDGET (accel_widget));
238 g_return_if_fail (full_path != NULL);
240 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
242 keyval = keyval != GDK_VoidSymbol ? keyval : 0;
244 item = g_hash_table_lookup (class->item_ht, full_path);
247 item = g_slice_new (GtkItemFactoryItem);
249 item->path = g_strdup (full_path);
250 item->widgets = NULL;
252 g_hash_table_insert (class->item_ht, item->path, item);
255 item->widgets = g_slist_prepend (item->widgets, accel_widget);
256 g_signal_connect (accel_widget,
258 G_CALLBACK (gtk_item_factory_item_remove_widget),
261 /* set the item path for the widget
263 g_object_set_qdata (G_OBJECT (accel_widget), quark_item_path, item->path);
264 gtk_widget_set_name (accel_widget, item->path);
267 g_object_ref (accel_group);
268 g_object_set_qdata_full (G_OBJECT (accel_widget),
274 g_object_set_qdata (G_OBJECT (accel_widget), quark_accel_group, NULL);
276 /* install defined accelerators
278 if (g_signal_lookup ("activate", G_TYPE_FROM_INSTANCE (accel_widget)))
282 gtk_accel_map_add_entry (full_path, keyval, modifiers);
283 gtk_widget_set_accel_path (accel_widget, full_path, accel_group);
289 ifactory_cb_data_free (gpointer mem)
291 g_slice_free (GtkIFCBData, mem);
295 gtk_item_factory_add_item (GtkItemFactory *ifactory,
297 const gchar *accelerator,
298 GtkItemFactoryCallback callback,
299 guint callback_action,
300 gpointer callback_data,
305 GtkItemFactoryClass *class;
306 GtkItemFactoryItem *item;
309 GdkModifierType mods;
311 g_return_if_fail (widget != NULL);
312 g_return_if_fail (item_type != NULL);
314 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
316 /* set accelerator group on menu widgets
318 if (GTK_IS_MENU (widget))
319 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
321 /* connect callback if necessary
327 data = g_slice_new (GtkIFCBData);
328 data->func = callback;
329 data->callback_type = callback_type;
330 data->func_data = callback_data;
331 data->callback_action = callback_action;
333 g_object_weak_ref (G_OBJECT (widget),
334 (GWeakNotify) ifactory_cb_data_free,
336 g_signal_connect (widget,
338 G_CALLBACK (gtk_item_factory_callback_marshal),
342 /* link the widget into its item-entry
343 * and keep back pointer on both the item factory and the widget
345 g_object_set_qdata (G_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
346 g_object_set_qdata (G_OBJECT (widget), quark_item_factory, ifactory);
348 gtk_accelerator_parse (accelerator, &keyval, &mods);
354 fpath = g_strconcat (ifactory->path, path, NULL);
355 gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
356 item = g_hash_table_lookup (class->item_ht, fpath);
359 g_return_if_fail (item != NULL);
361 if (!g_slist_find (ifactory->items, item))
362 ifactory->items = g_slist_prepend (ifactory->items, item);
366 * gtk_item_factory_construct:
367 * @ifactory: a #GtkItemFactory
368 * @container_type: the kind of menu to create; can be
369 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
370 * @path: the factory path of @ifactory, a string of the form
371 * <literal>"<name>"</literal>
372 * @accel_group: a #GtkAccelGroup to which the accelerators for the
373 * menu items will be added, or %NULL to create a new one
375 * Initializes an item factory.
380 gtk_item_factory_construct (GtkItemFactory *ifactory,
381 GType container_type,
383 GtkAccelGroup *accel_group)
387 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
388 g_return_if_fail (ifactory->accel_group == NULL);
389 g_return_if_fail (path != NULL);
390 if (!g_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
391 g_return_if_fail (g_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
395 if (path[0] != '<' && path[len - 1] != '>')
397 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
403 ifactory->accel_group = accel_group;
404 g_object_ref (ifactory->accel_group);
407 ifactory->accel_group = gtk_accel_group_new ();
409 ifactory->path = g_strdup (path);
410 ifactory->widget = g_object_connect (g_object_new (container_type, NULL),
411 "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
413 g_object_ref_sink (ifactory);
415 gtk_item_factory_add_item (ifactory,
423 * gtk_item_factory_from_path:
424 * @path: a string starting with a factory path of the form
425 * <literal>"<name>"</literal>
426 * @returns: the #GtkItemFactory created for the given factory path, or %NULL
428 * Finds an item factory which has been constructed using the
429 * <literal>"<name>"</literal> prefix of @path as the @path argument
430 * for gtk_item_factory_new().
435 gtk_item_factory_from_path (const gchar *path)
437 GtkItemFactoryClass *class;
438 GtkItemFactoryItem *item;
442 g_return_val_if_fail (path != NULL, NULL);
443 g_return_val_if_fail (path[0] == '<', NULL);
445 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
448 while (path[i] && path[i] != '>')
452 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
456 fname = g_new (gchar, i + 2);
457 g_memmove (fname, path, i + 1);
460 item = g_hash_table_lookup (class->item_ht, fname);
464 if (item && item->widgets)
465 return gtk_item_factory_from_widget (item->widgets->data);
471 gtk_item_factory_destroy (GtkObject *object)
473 GtkItemFactory *ifactory = (GtkItemFactory*) object;
476 if (ifactory->widget)
480 dobj = GTK_OBJECT (ifactory->widget);
482 g_object_ref_sink (dobj);
483 gtk_object_destroy (dobj);
484 g_object_unref (dobj);
486 ifactory->widget = NULL;
489 for (slist = ifactory->items; slist; slist = slist->next)
491 GtkItemFactoryItem *item = slist->data;
494 for (link = item->widgets; link; link = link->next)
495 if (g_object_get_qdata (link->data, quark_item_factory) == ifactory)
496 g_object_set_qdata (link->data, quark_item_factory, NULL);
498 g_slist_free (ifactory->items);
499 ifactory->items = NULL;
501 GTK_OBJECT_CLASS (gtk_item_factory_parent_class)->destroy (object);
505 gtk_item_factory_finalize (GObject *object)
507 GtkItemFactory *ifactory = GTK_ITEM_FACTORY (object);
509 if (ifactory->accel_group)
510 g_object_unref (ifactory->accel_group);
512 g_free (ifactory->path);
513 g_assert (ifactory->widget == NULL);
515 if (ifactory->translate_notify)
516 ifactory->translate_notify (ifactory->translate_data);
518 G_OBJECT_CLASS (gtk_item_factory_parent_class)->finalize (object);
522 * gtk_item_factory_from_widget:
524 * @returns: the item factory from which @widget was created, or %NULL
526 * Obtains the item factory from which a widget was created.
531 gtk_item_factory_from_widget (GtkWidget *widget)
533 GtkItemFactory *ifactory;
535 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
537 ifactory = g_object_get_qdata (G_OBJECT (widget), quark_item_factory);
539 if (ifactory == NULL && GTK_IS_MENU_ITEM (widget) &&
540 GTK_MENU_ITEM (widget)->submenu != NULL)
542 GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
543 ifactory = g_object_get_qdata (G_OBJECT (menu), quark_item_factory);
550 * gtk_item_factory_path_from_widget:
552 * @returns: the full path to @widget if it has been created by an item
553 * factory, %NULL otherwise. This value is owned by GTK+ and must not be
556 * If @widget has been created by an item factory, returns the full path
557 * to it. (The full path of a widget is the concatenation of the factory
558 * path specified in gtk_item_factory_new() with the path specified in the
559 * #GtkItemFactoryEntry from which the widget was created.)
563 G_CONST_RETURN gchar*
564 gtk_item_factory_path_from_widget (GtkWidget *widget)
568 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
570 path = g_object_get_qdata (G_OBJECT (widget), quark_item_path);
572 if (path == NULL && GTK_IS_MENU_ITEM (widget) &&
573 GTK_MENU_ITEM (widget)->submenu != NULL)
575 GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
576 path = g_object_get_qdata (G_OBJECT (menu), quark_item_path);
583 * gtk_item_factory_create_items:
584 * @ifactory: a #GtkItemFactory
585 * @n_entries: the length of @entries
586 * @entries: an array of #GtkItemFactoryEntry<!-- -->s whose @callback members
587 * must by of type #GtkItemFactoryCallback1
588 * @callback_data: data passed to the callback functions of all entries
590 * Creates the menu items from the @entries.
595 gtk_item_factory_create_items (GtkItemFactory *ifactory,
597 GtkItemFactoryEntry *entries,
598 gpointer callback_data)
600 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
604 * gtk_item_factory_create_items_ac:
605 * @ifactory: a #GtkItemFactory
606 * @n_entries: the length of @entries
607 * @entries: an array of #GtkItemFactoryEntry<!-- -->s
608 * @callback_data: data passed to the callback functions of all entries
609 * @callback_type: 1 if the callback functions in @entries are of type
610 * #GtkItemFactoryCallback1, 2 if they are of type #GtkItemFactoryCallback2
612 * Creates the menu items from the @entries.
617 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
619 GtkItemFactoryEntry *entries,
620 gpointer callback_data,
625 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
626 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
631 g_return_if_fail (entries != NULL);
633 for (i = 0; i < n_entries; i++)
634 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
638 * gtk_item_factory_get_widget:
639 * @ifactory: a #GtkItemFactory
640 * @path: the path to the widget
641 * @returns: the widget for the given path, or %NULL if @path doesn't lead
644 * Obtains the widget which corresponds to @path.
646 * If the widget corresponding to @path is a menu item which opens a
647 * submenu, then the submenu is returned. If you are interested in the menu
648 * item, use gtk_item_factory_get_item() instead.
653 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
656 GtkItemFactoryClass *class;
657 GtkItemFactoryItem *item;
659 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
660 g_return_val_if_fail (path != NULL, NULL);
662 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
665 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
670 fpath = g_strconcat (ifactory->path, path, NULL);
671 item = g_hash_table_lookup (class->item_ht, fpath);
679 for (slist = item->widgets; slist; slist = slist->next)
681 if (gtk_item_factory_from_widget (slist->data) == ifactory)
690 * gtk_item_factory_get_widget_by_action:
691 * @ifactory: a #GtkItemFactory
692 * @action: an action as specified in the @callback_action field
693 * of #GtkItemFactoryEntry
694 * @returns: the widget which corresponds to the given action, or %NULL
695 * if no widget was found
697 * Obtains the widget which was constructed from the #GtkItemFactoryEntry
698 * with the given @action.
700 * If there are multiple items with the same action, the result is
706 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
711 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
713 for (slist = ifactory->items; slist; slist = slist->next)
715 GtkItemFactoryItem *item = slist->data;
718 for (link = item->widgets; link; link = link->next)
719 if (g_object_get_qdata (link->data, quark_item_factory) == ifactory &&
720 g_object_get_qdata (link->data, quark_action) == GUINT_TO_POINTER (action))
728 * gtk_item_factory_get_item:
729 * @ifactory: a #GtkItemFactory
730 * @path: the path to the menu item
731 * @returns: the menu item for the given path, or %NULL if @path doesn't
732 * lead to a menu item
734 * Obtains the menu item which corresponds to @path.
736 * If the widget corresponding to @path is a menu item which opens a
737 * submenu, then the item is returned. If you are interested in the submenu,
738 * use gtk_item_factory_get_widget() instead.
743 gtk_item_factory_get_item (GtkItemFactory *ifactory,
748 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
749 g_return_val_if_fail (path != NULL, NULL);
751 widget = gtk_item_factory_get_widget (ifactory, path);
753 if (GTK_IS_MENU (widget))
754 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
756 return GTK_IS_ITEM (widget) ? widget : NULL;
761 * gtk_item_factory_get_item_by_action:
762 * @ifactory: a #GtkItemFactory
763 * @action: an action as specified in the @callback_action field
764 * of #GtkItemFactoryEntry
765 * @returns: the menu item which corresponds to the given action, or %NULL
766 * if no menu item was found
768 * Obtains the menu item which was constructed from the first
769 * #GtkItemFactoryEntry with the given @action.
774 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
779 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
781 widget = gtk_item_factory_get_widget_by_action (ifactory, action);
783 if (GTK_IS_MENU (widget))
784 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
786 return GTK_IS_ITEM (widget) ? widget : NULL;
790 item_factory_find_separator_r (char *path)
792 gchar *result = NULL;
793 gboolean escaped = FALSE;
803 else if (*path == '/')
814 item_factory_unescape_label (const char *label)
816 char *new = g_malloc (strlen (label) + 1);
818 gboolean escaped = FALSE;
844 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
853 *path = g_strdup (str);
874 *parent_path = g_strdup (*path);
875 p = item_factory_find_separator_r (*parent_path);
878 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
883 if (ifactory->translate_func)
884 translation = ifactory->translate_func (str, ifactory->translate_data);
888 p = item_factory_find_separator_r (translation);
894 *item = item_factory_unescape_label (p);
900 * gtk_item_factory_create_item:
901 * @ifactory: a #GtkItemFactory
902 * @entry: the #GtkItemFactoryEntry to create an item for
903 * @callback_data: data passed to the callback function of @entry
904 * @callback_type: 1 if the callback function of @entry is of type
905 * #GtkItemFactoryCallback1, 2 if it is of type #GtkItemFactoryCallback2
907 * Creates an item for @entry.
912 gtk_item_factory_create_item (GtkItemFactory *ifactory,
913 GtkItemFactoryEntry *entry,
914 gpointer callback_data,
917 GtkOptionMenu *option_menu = NULL;
928 gchar *item_type_path;
929 GtkStockItem stock_item;
931 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
932 g_return_if_fail (entry != NULL);
933 g_return_if_fail (entry->path != NULL);
934 g_return_if_fail (entry->path[0] == '/');
935 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
937 if (!entry->item_type ||
938 entry->item_type[0] == 0)
940 item_type_path = "<Item>";
941 type_id = quark_type_item;
945 item_type_path = entry->item_type;
946 type_id = g_quark_try_string (item_type_path);
950 if (type_id == quark_type_item)
951 type = GTK_TYPE_MENU_ITEM;
952 else if (type_id == quark_type_title)
953 type = GTK_TYPE_MENU_ITEM;
954 else if (type_id == quark_type_radio_item)
955 type = GTK_TYPE_RADIO_MENU_ITEM;
956 else if (type_id == quark_type_check_item)
957 type = GTK_TYPE_CHECK_MENU_ITEM;
958 else if (type_id == quark_type_image_item)
959 type = GTK_TYPE_IMAGE_MENU_ITEM;
960 else if (type_id == quark_type_stock_item)
961 type = GTK_TYPE_IMAGE_MENU_ITEM;
962 else if (type_id == quark_type_tearoff_item)
963 type = GTK_TYPE_TEAROFF_MENU_ITEM;
964 else if (type_id == quark_type_toggle_item)
965 type = GTK_TYPE_CHECK_MENU_ITEM;
966 else if (type_id == quark_type_separator_item)
967 type = GTK_TYPE_MENU_ITEM;
968 else if (type_id == quark_type_branch)
969 type = GTK_TYPE_MENU_ITEM;
970 else if (type_id == quark_type_last_branch)
971 type = GTK_TYPE_MENU_ITEM;
974 GtkWidget *radio_link;
976 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
977 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
979 type = GTK_TYPE_RADIO_MENU_ITEM;
980 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radio_link));
984 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
991 if (!gtk_item_factory_parse_path (ifactory, entry->path,
992 &path, &parent_path, &name))
995 parent = gtk_item_factory_get_widget (ifactory, parent_path);
998 GtkItemFactoryEntry pentry;
1001 ppath = g_strdup (entry->path);
1002 p = item_factory_find_separator_r (ppath);
1003 g_return_if_fail (p != NULL);
1005 pentry.path = ppath;
1006 pentry.accelerator = NULL;
1007 pentry.callback = NULL;
1008 pentry.callback_action = 0;
1009 pentry.item_type = "<Branch>";
1011 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1014 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1015 g_return_if_fail (parent != NULL);
1018 if (GTK_IS_OPTION_MENU (parent))
1020 option_menu = GTK_OPTION_MENU (parent);
1021 if (!option_menu->menu)
1023 GtkWidget *menu = g_object_new (GTK_TYPE_MENU, NULL);
1024 gchar *p = g_strconcat (ifactory->path, parent_path, NULL);
1026 gtk_menu_set_accel_path (GTK_MENU (menu), p);
1028 gtk_option_menu_set_menu (option_menu, menu);
1030 parent = option_menu->menu;
1032 g_free (parent_path);
1034 g_return_if_fail (GTK_IS_CONTAINER (parent));
1036 accelerator = entry->accelerator;
1038 widget = g_object_new (type,
1040 "sensitive", (type_id != quark_type_separator_item &&
1041 type_id != quark_type_title),
1044 if (option_menu && !option_menu->menu_item)
1045 gtk_option_menu_set_history (option_menu, 0);
1047 if (GTK_IS_RADIO_MENU_ITEM (widget))
1048 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1049 if (type_id == quark_type_image_item)
1051 GdkPixbuf *pixbuf = NULL;
1053 if (entry->extra_data)
1055 pixbuf = gdk_pixbuf_new_from_inline (-1,
1060 image = gtk_image_new_from_pixbuf (pixbuf);
1064 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1065 gtk_widget_show (image);
1068 g_object_unref (pixbuf);
1070 if (type_id == quark_type_stock_item)
1072 image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1073 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1074 gtk_widget_show (image);
1076 if (gtk_stock_lookup (entry->extra_data, &stock_item))
1079 accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1083 /* install underline accelerators for this item
1085 if (type_id != quark_type_separator_item &&
1086 type_id != quark_type_tearoff_item &&
1091 label = g_object_new (GTK_TYPE_ACCEL_LABEL,
1094 "accel-widget", widget,
1097 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1102 if (type_id == quark_type_branch ||
1103 type_id == quark_type_last_branch)
1107 if (entry->callback)
1108 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1110 if (type_id == quark_type_last_branch)
1111 gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE);
1114 widget = g_object_new (GTK_TYPE_MENU, NULL);
1115 p = g_strconcat (ifactory->path, path, NULL);
1116 gtk_menu_set_accel_path (GTK_MENU (widget), p);
1119 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1122 gtk_item_factory_add_item (ifactory,
1124 (type_id == quark_type_branch ||
1125 type_id == quark_type_last_branch) ?
1126 (GtkItemFactoryCallback) NULL : entry->callback,
1127 entry->callback_action, callback_data,
1131 if (accelerator != entry->accelerator)
1132 g_free (accelerator);
1137 * gtk_item_factory_create_menu_entries:
1138 * @n_entries: the length of @entries
1139 * @entries: an array of #GtkMenuEntry<!-- -->s
1141 * Creates the menu items from the @entries.
1146 gtk_item_factory_create_menu_entries (guint n_entries,
1147 GtkMenuEntry *entries)
1149 static GPatternSpec *pspec_separator = NULL;
1150 static GPatternSpec *pspec_check = NULL;
1155 g_return_if_fail (entries != NULL);
1157 if (!pspec_separator)
1159 pspec_separator = g_pattern_spec_new ("*<separator>*");
1160 pspec_check = g_pattern_spec_new ("*<check>*");
1163 for (i = 0; i < n_entries; i++)
1165 GtkItemFactory *ifactory;
1166 GtkItemFactoryEntry entry;
1170 path = entries[i].path;
1171 ifactory = gtk_item_factory_from_path (path);
1174 g_warning ("gtk_item_factory_create_menu_entries(): "
1175 "entry[%u] refers to unknown item factory: \"%s\"",
1176 i, entries[i].path);
1180 while (*path != '>')
1186 entry.accelerator = entries[i].accelerator;
1187 entry.callback = entries[i].callback;
1188 entry.callback_action = 0;
1189 if (g_pattern_match_string (pspec_separator, path))
1190 entry.item_type = "<Separator>";
1191 else if (!g_pattern_match_string (pspec_check, path))
1192 entry.item_type = NULL;
1195 gboolean in_brace = FALSE;
1198 cpath = g_new (gchar, strlen (path));
1204 else if (*path == '>')
1211 entry.item_type = "<ToggleItem>";
1215 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1216 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1222 * gtk_item_factories_path_delete:
1223 * @ifactory_path: a factory path to prepend to @path. May be %NULL if @path
1224 * starts with a factory path
1227 * Deletes all widgets constructed from the specified path.
1232 gtk_item_factories_path_delete (const gchar *ifactory_path,
1235 GtkItemFactoryClass *class;
1236 GtkItemFactoryItem *item;
1238 g_return_if_fail (path != NULL);
1240 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1243 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1248 g_return_if_fail (ifactory_path != NULL);
1250 fpath = g_strconcat (ifactory_path, path, NULL);
1251 item = g_hash_table_lookup (class->item_ht, fpath);
1257 GSList *widget_list;
1261 for (slist = item->widgets; slist; slist = slist->next)
1265 widget = slist->data;
1266 widget_list = g_slist_prepend (widget_list, widget);
1267 g_object_ref (widget);
1270 for (slist = widget_list; slist; slist = slist->next)
1274 widget = slist->data;
1275 gtk_widget_destroy (widget);
1276 g_object_unref (widget);
1278 g_slist_free (widget_list);
1283 * gtk_item_factory_delete_item:
1284 * @ifactory: a #GtkItemFactory
1287 * Deletes the menu item which was created for @path by the given
1293 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1298 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1299 g_return_if_fail (path != NULL);
1301 widget = gtk_item_factory_get_widget (ifactory, path);
1305 if (GTK_IS_MENU (widget))
1306 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1308 gtk_widget_destroy (widget);
1313 * gtk_item_factory_delete_entry:
1314 * @ifactory: a #GtkItemFactory
1315 * @entry: a #GtkItemFactoryEntry
1317 * Deletes the menu item which was created from @entry by the given
1323 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1324 GtkItemFactoryEntry *entry)
1330 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1331 g_return_if_fail (entry != NULL);
1332 g_return_if_fail (entry->path != NULL);
1333 g_return_if_fail (entry->path[0] == '/');
1335 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1336 &path, &parent_path, &name))
1339 gtk_item_factory_delete_item (ifactory, path);
1342 g_free (parent_path);
1347 * gtk_item_factory_delete_entries:
1348 * @ifactory: a #GtkItemFactory
1349 * @n_entries: the length of @entries
1350 * @entries: an array of #GtkItemFactoryEntry<!-- -->s
1352 * Deletes the menu items which were created from the @entries by the given
1358 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1360 GtkItemFactoryEntry *entries)
1364 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1366 g_return_if_fail (entries != NULL);
1368 for (i = 0; i < n_entries; i++)
1369 gtk_item_factory_delete_entry (ifactory, entries + i);
1379 gtk_item_factory_menu_pos (GtkMenu *menu,
1385 MenuPos *mpos = func_data;
1392 * gtk_item_factory_popup_data_from_widget:
1394 * @returns: @popup_data associated with the item factory from
1395 * which @widget was created, or %NULL if @widget wasn't created
1396 * by an item factory
1398 * Obtains the @popup_data which was passed to
1399 * gtk_item_factory_popup_with_data(). This data is available until the menu
1400 * is popped down again.
1405 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1407 GtkItemFactory *ifactory;
1409 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1411 ifactory = gtk_item_factory_from_widget (widget);
1413 return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1419 * gtk_item_factory_popup_data:
1420 * @ifactory: a #GtkItemFactory
1421 * @returns: @popup_data associated with @ifactory
1423 * Obtains the @popup_data which was passed to
1424 * gtk_item_factory_popup_with_data(). This data is available until the menu
1425 * is popped down again.
1430 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1432 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1434 return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1438 ifactory_delete_popup_data (GtkObject *object,
1439 GtkItemFactory *ifactory)
1441 g_signal_handlers_disconnect_by_func (object,
1442 ifactory_delete_popup_data,
1444 g_object_set_qdata (G_OBJECT (ifactory), quark_popup_data, NULL);
1448 * gtk_item_factory_popup:
1449 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1450 * @x: the x position
1451 * @y: the y position
1452 * @mouse_button: the mouse button which was pressed to initiate the popup
1453 * @time_: the time at which the activation event occurred
1455 * Pops up the menu constructed from the item factory at (@x, @y).
1457 * The @mouse_button parameter should be the mouse button pressed to initiate
1458 * the menu popup. If the menu popup was initiated by something other than
1459 * a mouse button press, such as a mouse button release or a keypress,
1460 * @mouse_button should be 0.
1462 * The @time_ parameter should be the time stamp of the event that
1463 * initiated the popup. If such an event is not available, use
1464 * gtk_get_current_event_time() instead.
1466 * The operation of the @mouse_button and the @time_ parameter is the same
1467 * as the @button and @activation_time parameters for gtk_menu_popup().
1472 gtk_item_factory_popup (GtkItemFactory *ifactory,
1478 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1482 * gtk_item_factory_popup_with_data:
1483 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1484 * @popup_data: data available for callbacks while the menu is posted
1485 * @destroy: a #GtkDestroyNotify function to be called on @popup_data when
1486 * the menu is unposted
1487 * @x: the x position
1488 * @y: the y position
1489 * @mouse_button: the mouse button which was pressed to initiate the popup
1490 * @time_: the time at which the activation event occurred
1492 * Pops up the menu constructed from the item factory at (@x, @y). Callbacks
1493 * can access the @popup_data while the menu is posted via
1494 * gtk_item_factory_popup_data() and gtk_item_factory_popup_data_from_widget().
1496 * The @mouse_button parameter should be the mouse button pressed to initiate
1497 * the menu popup. If the menu popup was initiated by something other than
1498 * a mouse button press, such as a mouse button release or a keypress,
1499 * @mouse_button should be 0.
1501 * The @time_ parameter should be the time stamp of the event that
1502 * initiated the popup. If such an event is not available, use
1503 * gtk_get_current_event_time() instead.
1505 * The operation of the @mouse_button and the @time_ parameters is the same
1506 * as the @button and @activation_time parameters for gtk_menu_popup().
1511 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1512 gpointer popup_data,
1513 GtkDestroyNotify destroy,
1521 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1522 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1524 mpos = g_object_get_qdata (G_OBJECT (ifactory->widget), quark_if_menu_pos);
1528 mpos = g_new0 (MenuPos, 1);
1529 g_object_set_qdata_full (G_OBJECT (ifactory->widget),
1538 if (popup_data != NULL)
1540 g_object_set_qdata_full (G_OBJECT (ifactory),
1544 g_signal_connect (ifactory->widget,
1546 G_CALLBACK (ifactory_delete_popup_data),
1550 gtk_menu_popup (GTK_MENU (ifactory->widget),
1552 gtk_item_factory_menu_pos, mpos,
1553 mouse_button, time);
1557 * gtk_item_factory_set_translate_func:
1558 * @ifactory: a #GtkItemFactory
1559 * @func: the #GtkTranslateFunc function to be used to translate path elements
1560 * @data: data to pass to @func and @notify
1561 * @notify: a #GtkDestroyNotify function to be called when @ifactory is
1562 * destroyed and when the translation function is changed again
1564 * Sets a function to be used for translating the path elements before they
1570 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1571 GtkTranslateFunc func,
1573 GtkDestroyNotify notify)
1575 g_return_if_fail (ifactory != NULL);
1577 if (ifactory->translate_notify)
1578 ifactory->translate_notify (ifactory->translate_data);
1580 ifactory->translate_func = func;
1581 ifactory->translate_data = data;
1582 ifactory->translate_notify = notify;
1585 #define __GTK_ITEM_FACTORY_C__
1586 #include "gtkaliasdef.c"