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 #include "gtkitemfactory.h"
33 #include "gtk/gtkmenubar.h"
34 #include "gtk/gtkmenu.h"
35 #include "gtk/gtkmenuitem.h"
36 #include "gtk/gtkradiomenuitem.h"
37 #include "gtk/gtkcheckmenuitem.h"
38 #include "gtk/gtkimagemenuitem.h"
39 #include "gtk/gtktearoffmenuitem.h"
40 #include "gtk/gtkaccelmap.h"
41 #include "gtk/gtkaccellabel.h"
42 #include "gdk/gdkkeysyms.h"
43 #include "gtk/gtkimage.h"
44 #include "gtk/gtkstock.h"
45 #include "gtk/gtkiconfactory.h"
54 #undef GTK_DISABLE_DEPRECATED
55 #include "gtk/gtkoptionmenu.h"
56 #define GTK_DISABLE_DEPRECATED
60 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
61 #define ITEM_BLOCK_SIZE (128)
64 /* --- structures --- */
65 typedef struct _GtkIFCBData GtkIFCBData;
66 typedef struct _GtkIFDumpData GtkIFDumpData;
69 GtkItemFactoryCallback func;
72 guint callback_action;
76 /* --- prototypes --- */
77 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
78 static void gtk_item_factory_init (GtkItemFactory *ifactory);
79 static void gtk_item_factory_destroy (GtkObject *object);
80 static void gtk_item_factory_finalize (GObject *object);
83 /* --- static variables --- */
84 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
85 static gpointer parent_class = NULL;
86 static const gchar item_factory_string[] = "Gtk-<ItemFactory>";
87 static GQuark quark_popup_data = 0;
88 static GQuark quark_if_menu_pos = 0;
89 static GQuark quark_item_factory = 0;
90 static GQuark quark_item_path = 0;
91 static GQuark quark_action = 0;
92 static GQuark quark_accel_group = 0;
93 static GQuark quark_type_item = 0;
94 static GQuark quark_type_title = 0;
95 static GQuark quark_type_radio_item = 0;
96 static GQuark quark_type_check_item = 0;
97 static GQuark quark_type_toggle_item = 0;
98 static GQuark quark_type_image_item = 0;
99 static GQuark quark_type_stock_item = 0;
100 static GQuark quark_type_tearoff_item = 0;
101 static GQuark quark_type_separator_item = 0;
102 static GQuark quark_type_branch = 0;
103 static GQuark quark_type_last_branch = 0;
106 /* --- functions --- */
108 gtk_item_factory_get_type (void)
110 static GType item_factory_type = 0;
112 if (!item_factory_type)
114 static const GTypeInfo item_factory_info =
116 sizeof (GtkItemFactoryClass),
117 NULL, /* base_init */
118 NULL, /* base_finalize */
119 (GClassInitFunc) gtk_item_factory_class_init,
120 NULL, /* class_finalize */
121 NULL, /* class_data */
122 sizeof (GtkItemFactory),
124 (GInstanceInitFunc) gtk_item_factory_init,
128 g_type_register_static (GTK_TYPE_OBJECT, I_("GtkItemFactory"),
129 &item_factory_info, 0);
132 return item_factory_type;
136 gtk_item_factory_class_init (GtkItemFactoryClass *class)
138 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
139 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
141 gtk_item_factory_class = class;
142 parent_class = g_type_class_peek_parent (class);
144 gobject_class->finalize = gtk_item_factory_finalize;
146 object_class->destroy = gtk_item_factory_destroy;
148 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
150 quark_popup_data = g_quark_from_static_string ("GtkItemFactory-popup-data");
151 quark_if_menu_pos = g_quark_from_static_string ("GtkItemFactory-menu-position");
152 quark_item_factory = g_quark_from_static_string ("GtkItemFactory");
153 quark_item_path = g_quark_from_static_string ("GtkItemFactory-path");
154 quark_action = g_quark_from_static_string ("GtkItemFactory-action");
155 quark_accel_group = g_quark_from_static_string ("GtkAccelGroup");
156 quark_type_item = g_quark_from_static_string ("<Item>");
157 quark_type_title = g_quark_from_static_string ("<Title>");
158 quark_type_radio_item = g_quark_from_static_string ("<RadioItem>");
159 quark_type_check_item = g_quark_from_static_string ("<CheckItem>");
160 quark_type_toggle_item = g_quark_from_static_string ("<ToggleItem>");
161 quark_type_image_item = g_quark_from_static_string ("<ImageItem>");
162 quark_type_stock_item = g_quark_from_static_string ("<StockItem>");
163 quark_type_separator_item = g_quark_from_static_string ("<Separator>");
164 quark_type_tearoff_item = g_quark_from_static_string ("<Tearoff>");
165 quark_type_branch = g_quark_from_static_string ("<Branch>");
166 quark_type_last_branch = g_quark_from_static_string ("<LastBranch>");
170 gtk_item_factory_init (GtkItemFactory *ifactory)
172 ifactory->path = NULL;
173 ifactory->accel_group = NULL;
174 ifactory->widget = NULL;
175 ifactory->items = NULL;
176 ifactory->translate_func = NULL;
177 ifactory->translate_data = NULL;
178 ifactory->translate_notify = NULL;
182 * gtk_item_factory_new:
183 * @container_type: the kind of menu to create; can be
184 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
185 * @path: the factory path of the new item factory, a string of the form
186 * <literal>"<name>"</literal>
187 * @accel_group: a #GtkAccelGroup to which the accelerators for the
188 * menu items will be added, or %NULL to create a new one
189 * @returns: a new #GtkItemFactory
191 * Creates a new #GtkItemFactory.
193 * Beware that the returned object does not have a floating reference.
196 gtk_item_factory_new (GType container_type,
198 GtkAccelGroup *accel_group)
200 GtkItemFactory *ifactory;
202 g_return_val_if_fail (path != NULL, NULL);
204 ifactory = g_object_new (GTK_TYPE_ITEM_FACTORY, NULL);
205 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
211 gtk_item_factory_callback_marshal (GtkWidget *widget,
218 if (data->callback_type == 1)
220 GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
221 func1 (data->func_data, data->callback_action, widget);
223 else if (data->callback_type == 2)
225 GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
226 func2 (widget, data->func_data, data->callback_action);
231 gtk_item_factory_item_remove_widget (GtkWidget *widget,
232 GtkItemFactoryItem *item)
234 item->widgets = g_slist_remove (item->widgets, widget);
235 g_object_set_qdata (G_OBJECT (widget), quark_item_factory, NULL);
236 g_object_set_qdata (G_OBJECT (widget), quark_item_path, NULL);
240 * gtk_item_factory_add_foreign:
241 * @accel_widget: widget to install an accelerator on
242 * @full_path: the full path for the @accel_widget
243 * @accel_group: the accelerator group to install the accelerator in
244 * @keyval: key value of the accelerator
245 * @modifiers: modifier combination of the accelerator
247 * Installs an accelerator for @accel_widget in @accel_group, that causes
248 * the ::activate signal to be emitted if the accelerator is activated.
250 * This function can be used to make widgets participate in the accel
251 * saving/restoring functionality provided by gtk_accel_map_save() and
252 * gtk_accel_map_load(), even if they haven't been created by an item
255 * Deprecated: The recommended API for this purpose are the functions
256 * gtk_menu_item_set_accel_path() and gtk_widget_set_accel_path(); don't
257 * use gtk_item_factory_add_foreign() in new code, since it is likely to
258 * be removed in the future.
261 gtk_item_factory_add_foreign (GtkWidget *accel_widget,
262 const gchar *full_path,
263 GtkAccelGroup *accel_group,
265 GdkModifierType modifiers)
267 GtkItemFactoryClass *class;
268 GtkItemFactoryItem *item;
270 g_return_if_fail (GTK_IS_WIDGET (accel_widget));
271 g_return_if_fail (full_path != NULL);
273 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
275 keyval = keyval != GDK_VoidSymbol ? keyval : 0;
277 item = g_hash_table_lookup (class->item_ht, full_path);
280 item = g_slice_new (GtkItemFactoryItem);
282 item->path = g_strdup (full_path);
283 item->widgets = NULL;
285 g_hash_table_insert (class->item_ht, item->path, item);
288 item->widgets = g_slist_prepend (item->widgets, accel_widget);
289 g_signal_connect (accel_widget,
291 G_CALLBACK (gtk_item_factory_item_remove_widget),
294 /* set the item path for the widget
296 g_object_set_qdata (G_OBJECT (accel_widget), quark_item_path, item->path);
297 gtk_widget_set_name (accel_widget, item->path);
300 g_object_ref (accel_group);
301 g_object_set_qdata_full (G_OBJECT (accel_widget),
307 g_object_set_qdata (G_OBJECT (accel_widget), quark_accel_group, NULL);
309 /* install defined accelerators
311 if (g_signal_lookup ("activate", G_TYPE_FROM_INSTANCE (accel_widget)))
315 gtk_accel_map_add_entry (full_path, keyval, modifiers);
316 gtk_widget_set_accel_path (accel_widget, full_path, accel_group);
322 ifactory_cb_data_free (gpointer mem)
324 g_slice_free (GtkIFCBData, mem);
328 gtk_item_factory_add_item (GtkItemFactory *ifactory,
330 const gchar *accelerator,
331 GtkItemFactoryCallback callback,
332 guint callback_action,
333 gpointer callback_data,
338 GtkItemFactoryClass *class;
339 GtkItemFactoryItem *item;
342 GdkModifierType mods;
344 g_return_if_fail (widget != NULL);
345 g_return_if_fail (item_type != NULL);
347 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
349 /* set accelerator group on menu widgets
351 if (GTK_IS_MENU (widget))
352 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
354 /* connect callback if necessary
360 data = g_slice_new (GtkIFCBData);
361 data->func = callback;
362 data->callback_type = callback_type;
363 data->func_data = callback_data;
364 data->callback_action = callback_action;
366 g_object_weak_ref (G_OBJECT (widget),
367 (GWeakNotify) ifactory_cb_data_free,
369 g_signal_connect (widget,
371 G_CALLBACK (gtk_item_factory_callback_marshal),
375 /* link the widget into its item-entry
376 * and keep back pointer on both the item factory and the widget
378 g_object_set_qdata (G_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
379 g_object_set_qdata (G_OBJECT (widget), quark_item_factory, ifactory);
381 gtk_accelerator_parse (accelerator, &keyval, &mods);
387 fpath = g_strconcat (ifactory->path, path, NULL);
388 gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
389 item = g_hash_table_lookup (class->item_ht, fpath);
392 g_return_if_fail (item != NULL);
394 if (!g_slist_find (ifactory->items, item))
395 ifactory->items = g_slist_prepend (ifactory->items, item);
399 * gtk_item_factory_construct:
400 * @ifactory: a #GtkItemFactory
401 * @container_type: the kind of menu to create; can be
402 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
403 * @path: the factory path of @ifactory, a string of the form
404 * <literal>"<name>"</literal>
405 * @accel_group: a #GtkAccelGroup to which the accelerators for the
406 * menu items will be added, or %NULL to create a new one
408 * Initializes an item factory.
411 gtk_item_factory_construct (GtkItemFactory *ifactory,
412 GType container_type,
414 GtkAccelGroup *accel_group)
418 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
419 g_return_if_fail (ifactory->accel_group == NULL);
420 g_return_if_fail (path != NULL);
421 if (!g_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
422 g_return_if_fail (g_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
426 if (path[0] != '<' && path[len - 1] != '>')
428 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
434 ifactory->accel_group = accel_group;
435 g_object_ref (ifactory->accel_group);
438 ifactory->accel_group = gtk_accel_group_new ();
440 ifactory->path = g_strdup (path);
441 ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
442 "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
444 g_object_ref_sink (ifactory);
446 gtk_item_factory_add_item (ifactory,
454 * gtk_item_factory_from_path:
455 * @path: a string starting with a factory path of the form
456 * <literal>"<name>"</literal>
457 * @returns: the #GtkItemFactory created for the given factory path, or %NULL
459 * Finds an item factory which has been constructed using the
460 * <literal>"<name>"</literal> prefix of @path as the @path argument
461 * for gtk_item_factory_new().
464 gtk_item_factory_from_path (const gchar *path)
466 GtkItemFactoryClass *class;
467 GtkItemFactoryItem *item;
471 g_return_val_if_fail (path != NULL, NULL);
472 g_return_val_if_fail (path[0] == '<', NULL);
474 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
477 while (path[i] && path[i] != '>')
481 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
485 fname = g_new (gchar, i + 2);
486 g_memmove (fname, path, i + 1);
489 item = g_hash_table_lookup (class->item_ht, fname);
493 if (item && item->widgets)
494 return gtk_item_factory_from_widget (item->widgets->data);
500 gtk_item_factory_destroy (GtkObject *object)
502 GtkItemFactory *ifactory;
505 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
507 ifactory = (GtkItemFactory*) object;
509 if (ifactory->widget)
513 dobj = GTK_OBJECT (ifactory->widget);
515 g_object_ref_sink (dobj);
516 gtk_object_destroy (dobj);
517 g_object_unref (dobj);
519 ifactory->widget = NULL;
522 for (slist = ifactory->items; slist; slist = slist->next)
524 GtkItemFactoryItem *item = slist->data;
527 for (link = item->widgets; link; link = link->next)
528 if (g_object_get_qdata (link->data, quark_item_factory) == ifactory)
529 g_object_set_qdata (link->data, quark_item_factory, NULL);
531 g_slist_free (ifactory->items);
532 ifactory->items = NULL;
534 GTK_OBJECT_CLASS (parent_class)->destroy (object);
538 gtk_item_factory_finalize (GObject *object)
540 GtkItemFactory *ifactory;
542 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
544 ifactory = GTK_ITEM_FACTORY (object);
546 g_object_unref (ifactory->accel_group);
547 g_free (ifactory->path);
548 g_assert (ifactory->widget == NULL);
550 if (ifactory->translate_notify)
551 ifactory->translate_notify (ifactory->translate_data);
553 G_OBJECT_CLASS (parent_class)->finalize (object);
557 * gtk_item_factory_from_widget:
559 * @returns: the item factory from which @widget was created, or %NULL
561 * Obtains the item factory from which a widget was created.
564 gtk_item_factory_from_widget (GtkWidget *widget)
566 GtkItemFactory *ifactory;
568 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
570 ifactory = g_object_get_qdata (G_OBJECT (widget), quark_item_factory);
572 if (ifactory == NULL && GTK_IS_MENU_ITEM (widget) &&
573 GTK_MENU_ITEM (widget)->submenu != NULL)
575 GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
576 ifactory = g_object_get_qdata (G_OBJECT (menu), quark_item_factory);
583 * gtk_item_factory_path_from_widget:
585 * @returns: the full path to @widget if it has been created by an item
586 * factory, %NULL otherwise. This value is owned by GTK+ and must not be
589 * If @widget has been created by an item factory, returns the full path
590 * to it. (The full path of a widget is the concatenation of the factory
591 * path specified in gtk_item_factory_new() with the path specified in the
592 * #GtkItemFactoryEntry from which the widget was created.)
594 G_CONST_RETURN gchar*
595 gtk_item_factory_path_from_widget (GtkWidget *widget)
599 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
601 path = g_object_get_qdata (G_OBJECT (widget), quark_item_path);
603 if (path == NULL && GTK_IS_MENU_ITEM (widget) &&
604 GTK_MENU_ITEM (widget)->submenu != NULL)
606 GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
607 path = g_object_get_qdata (G_OBJECT (menu), quark_item_path);
614 * gtk_item_factory_create_items:
615 * @ifactory: a #GtkItemFactory
616 * @n_entries: the length of @entries
617 * @entries: an array of #GtkItemFactoryEntry<!-- -->s whose @callback members
618 * must by of type #GtkItemFactoryCallback1
619 * @callback_data: data passed to the callback functions of all entries
621 * Creates the menu items from the @entries.
624 gtk_item_factory_create_items (GtkItemFactory *ifactory,
626 GtkItemFactoryEntry *entries,
627 gpointer callback_data)
629 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
633 * gtk_item_factory_create_items_ac:
634 * @ifactory: a #GtkItemFactory
635 * @n_entries: the length of @entries
636 * @entries: an array of #GtkItemFactoryEntry<!-- -->s
637 * @callback_data: data passed to the callback functions of all entries
638 * @callback_type: 1 if the callback functions in @entries are of type
639 * #GtkItemFactoryCallback1, 2 if they are of type #GtkItemFactoryCallback2
641 * Creates the menu items from the @entries.
644 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
646 GtkItemFactoryEntry *entries,
647 gpointer callback_data,
652 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
653 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
658 g_return_if_fail (entries != NULL);
660 for (i = 0; i < n_entries; i++)
661 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
665 * gtk_item_factory_get_widget:
666 * @ifactory: a #GtkItemFactory
667 * @path: the path to the widget
668 * @returns: the widget for the given path, or %NULL if @path doesn't lead
671 * Obtains the widget which corresponds to @path.
673 * If the widget corresponding to @path is a menu item which opens a
674 * submenu, then the submenu is returned. If you are interested in the menu
675 * item, use gtk_item_factory_get_item() instead.
678 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
681 GtkItemFactoryClass *class;
682 GtkItemFactoryItem *item;
684 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
685 g_return_val_if_fail (path != NULL, NULL);
687 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
690 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
695 fpath = g_strconcat (ifactory->path, path, NULL);
696 item = g_hash_table_lookup (class->item_ht, fpath);
704 for (slist = item->widgets; slist; slist = slist->next)
706 if (gtk_item_factory_from_widget (slist->data) == ifactory)
715 * gtk_item_factory_get_widget_by_action:
716 * @ifactory: a #GtkItemFactory
717 * @action: an action as specified in the @callback_action field
718 * of #GtkItemFactoryEntry
719 * @returns: the widget which corresponds to the given action, or %NULL
720 * if no widget was found
722 * Obtains the widget which was constructed from the #GtkItemFactoryEntry
723 * with the given @action.
725 * If there are multiple items with the same action, the result is
729 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
734 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
736 for (slist = ifactory->items; slist; slist = slist->next)
738 GtkItemFactoryItem *item = slist->data;
741 for (link = item->widgets; link; link = link->next)
742 if (g_object_get_qdata (link->data, quark_item_factory) == ifactory &&
743 g_object_get_qdata (link->data, quark_action) == GUINT_TO_POINTER (action))
751 * gtk_item_factory_get_item:
752 * @ifactory: a #GtkItemFactory
753 * @path: the path to the menu item
754 * @returns: the menu item for the given path, or %NULL if @path doesn't
755 * lead to a menu item
757 * Obtains the menu item which corresponds to @path.
759 * If the widget corresponding to @path is a menu item which opens a
760 * submenu, then the item is returned. If you are interested in the submenu,
761 * use gtk_item_factory_get_widget() instead.
764 gtk_item_factory_get_item (GtkItemFactory *ifactory,
769 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
770 g_return_val_if_fail (path != NULL, NULL);
772 widget = gtk_item_factory_get_widget (ifactory, path);
774 if (GTK_IS_MENU (widget))
775 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
777 return GTK_IS_ITEM (widget) ? widget : NULL;
782 * gtk_item_factory_get_item_by_action:
783 * @ifactory: a #GtkItemFactory
784 * @action: an action as specified in the @callback_action field
785 * of #GtkItemFactoryEntry
786 * @returns: the menu item which corresponds to the given action, or %NULL
787 * if no menu item was found
789 * Obtains the menu item which was constructed from the first
790 * #GtkItemFactoryEntry with the given @action.
793 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
798 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
800 widget = gtk_item_factory_get_widget_by_action (ifactory, action);
802 if (GTK_IS_MENU (widget))
803 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
805 return GTK_IS_ITEM (widget) ? widget : NULL;
809 item_factory_find_separator_r (char *path)
811 gchar *result = NULL;
812 gboolean escaped = FALSE;
822 else if (*path == '/')
833 item_factory_unescape_label (const char *label)
835 char *new = g_malloc (strlen (label) + 1);
837 gboolean escaped = FALSE;
863 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
872 *path = g_strdup (str);
893 *parent_path = g_strdup (*path);
894 p = item_factory_find_separator_r (*parent_path);
897 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
902 if (ifactory->translate_func)
903 translation = ifactory->translate_func (str, ifactory->translate_data);
907 p = item_factory_find_separator_r (translation);
913 *item = item_factory_unescape_label (p);
919 * gtk_item_factory_create_item:
920 * @ifactory: a #GtkItemFactory
921 * @entry: the #GtkItemFactoryEntry to create an item for
922 * @callback_data: data passed to the callback function of @entry
923 * @callback_type: 1 if the callback function of @entry is of type
924 * #GtkItemFactoryCallback1, 2 if it is of type #GtkItemFactoryCallback2
926 * Creates an item for @entry.
929 gtk_item_factory_create_item (GtkItemFactory *ifactory,
930 GtkItemFactoryEntry *entry,
931 gpointer callback_data,
934 GtkOptionMenu *option_menu = NULL;
945 gchar *item_type_path;
946 GtkStockItem stock_item;
948 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
949 g_return_if_fail (entry != NULL);
950 g_return_if_fail (entry->path != NULL);
951 g_return_if_fail (entry->path[0] == '/');
952 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
954 if (!entry->item_type ||
955 entry->item_type[0] == 0)
957 item_type_path = "<Item>";
958 type_id = quark_type_item;
962 item_type_path = entry->item_type;
963 type_id = g_quark_try_string (item_type_path);
967 if (type_id == quark_type_item)
968 type = GTK_TYPE_MENU_ITEM;
969 else if (type_id == quark_type_title)
970 type = GTK_TYPE_MENU_ITEM;
971 else if (type_id == quark_type_radio_item)
972 type = GTK_TYPE_RADIO_MENU_ITEM;
973 else if (type_id == quark_type_check_item)
974 type = GTK_TYPE_CHECK_MENU_ITEM;
975 else if (type_id == quark_type_image_item)
976 type = GTK_TYPE_IMAGE_MENU_ITEM;
977 else if (type_id == quark_type_stock_item)
978 type = GTK_TYPE_IMAGE_MENU_ITEM;
979 else if (type_id == quark_type_tearoff_item)
980 type = GTK_TYPE_TEAROFF_MENU_ITEM;
981 else if (type_id == quark_type_toggle_item)
982 type = GTK_TYPE_CHECK_MENU_ITEM;
983 else if (type_id == quark_type_separator_item)
984 type = GTK_TYPE_MENU_ITEM;
985 else if (type_id == quark_type_branch)
986 type = GTK_TYPE_MENU_ITEM;
987 else if (type_id == quark_type_last_branch)
988 type = GTK_TYPE_MENU_ITEM;
991 GtkWidget *radio_link;
993 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
994 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
996 type = GTK_TYPE_RADIO_MENU_ITEM;
997 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radio_link));
1001 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1008 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1009 &path, &parent_path, &name))
1012 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1015 GtkItemFactoryEntry pentry;
1018 ppath = g_strdup (entry->path);
1019 p = item_factory_find_separator_r (ppath);
1020 g_return_if_fail (p != NULL);
1022 pentry.path = ppath;
1023 pentry.accelerator = NULL;
1024 pentry.callback = NULL;
1025 pentry.callback_action = 0;
1026 pentry.item_type = "<Branch>";
1028 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1031 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1032 g_return_if_fail (parent != NULL);
1035 if (GTK_IS_OPTION_MENU (parent))
1037 option_menu = GTK_OPTION_MENU (parent);
1038 if (!option_menu->menu)
1040 GtkWidget *menu = g_object_new (GTK_TYPE_MENU, NULL);
1041 gchar *p = g_strconcat (ifactory->path, parent_path, NULL);
1043 gtk_menu_set_accel_path (GTK_MENU (menu), p);
1045 gtk_option_menu_set_menu (option_menu, menu);
1047 parent = option_menu->menu;
1049 g_free (parent_path);
1051 g_return_if_fail (GTK_IS_CONTAINER (parent));
1053 accelerator = entry->accelerator;
1055 widget = gtk_widget_new (type,
1057 "sensitive", (type_id != quark_type_separator_item &&
1058 type_id != quark_type_title),
1061 if (option_menu && !option_menu->menu_item)
1062 gtk_option_menu_set_history (option_menu, 0);
1064 if (GTK_IS_RADIO_MENU_ITEM (widget))
1065 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1066 if (type_id == quark_type_image_item)
1068 GdkPixbuf *pixbuf = NULL;
1070 if (entry->extra_data)
1072 pixbuf = gdk_pixbuf_new_from_inline (-1,
1077 image = gtk_image_new_from_pixbuf (pixbuf);
1081 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1082 gtk_widget_show (image);
1085 g_object_unref (pixbuf);
1087 if (type_id == quark_type_stock_item)
1089 image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1090 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1091 gtk_widget_show (image);
1093 if (gtk_stock_lookup (entry->extra_data, &stock_item))
1096 accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1100 /* install underline accelerators for this item
1102 if (type_id != quark_type_separator_item &&
1103 type_id != quark_type_tearoff_item &&
1108 label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1111 "accel-widget", widget,
1114 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1119 if (type_id == quark_type_branch ||
1120 type_id == quark_type_last_branch)
1124 if (entry->callback)
1125 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1127 if (type_id == quark_type_last_branch)
1128 gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE);
1131 widget = gtk_widget_new (GTK_TYPE_MENU, NULL);
1132 p = g_strconcat (ifactory->path, path, NULL);
1133 gtk_menu_set_accel_path (GTK_MENU (widget), p);
1136 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1139 gtk_item_factory_add_item (ifactory,
1141 (type_id == quark_type_branch ||
1142 type_id == quark_type_last_branch) ?
1143 (GtkItemFactoryCallback) NULL : entry->callback,
1144 entry->callback_action, callback_data,
1148 if (accelerator != entry->accelerator)
1149 g_free (accelerator);
1154 * gtk_item_factory_create_menu_entries:
1155 * @n_entries: the length of @entries
1156 * @entries: an array of #GtkMenuEntry<!-- -->s
1158 * Creates the menu items from the @entries.
1161 gtk_item_factory_create_menu_entries (guint n_entries,
1162 GtkMenuEntry *entries)
1164 static GPatternSpec *pspec_separator = NULL;
1165 static GPatternSpec *pspec_check = NULL;
1170 g_return_if_fail (entries != NULL);
1172 if (!pspec_separator)
1174 pspec_separator = g_pattern_spec_new ("*<separator>*");
1175 pspec_check = g_pattern_spec_new ("*<check>*");
1178 for (i = 0; i < n_entries; i++)
1180 GtkItemFactory *ifactory;
1181 GtkItemFactoryEntry entry;
1185 path = entries[i].path;
1186 ifactory = gtk_item_factory_from_path (path);
1189 g_warning ("gtk_item_factory_create_menu_entries(): "
1190 "entry[%u] refers to unknown item factory: \"%s\"",
1191 i, entries[i].path);
1195 while (*path != '>')
1201 entry.accelerator = entries[i].accelerator;
1202 entry.callback = entries[i].callback;
1203 entry.callback_action = 0;
1204 if (g_pattern_match_string (pspec_separator, path))
1205 entry.item_type = "<Separator>";
1206 else if (!g_pattern_match_string (pspec_check, path))
1207 entry.item_type = NULL;
1210 gboolean in_brace = FALSE;
1213 cpath = g_new (gchar, strlen (path));
1219 else if (*path == '>')
1226 entry.item_type = "<ToggleItem>";
1230 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1231 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1237 * gtk_item_factories_path_delete:
1238 * @ifactory_path: a factory path to prepend to @path. May be %NULL if @path
1239 * starts with a factory path
1242 * Deletes all widgets constructed from the specified path.
1245 gtk_item_factories_path_delete (const gchar *ifactory_path,
1248 GtkItemFactoryClass *class;
1249 GtkItemFactoryItem *item;
1251 g_return_if_fail (path != NULL);
1253 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1256 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1261 g_return_if_fail (ifactory_path != NULL);
1263 fpath = g_strconcat (ifactory_path, path, NULL);
1264 item = g_hash_table_lookup (class->item_ht, fpath);
1270 GSList *widget_list;
1274 for (slist = item->widgets; slist; slist = slist->next)
1278 widget = slist->data;
1279 widget_list = g_slist_prepend (widget_list, widget);
1280 g_object_ref (widget);
1283 for (slist = widget_list; slist; slist = slist->next)
1287 widget = slist->data;
1288 gtk_widget_destroy (widget);
1289 g_object_unref (widget);
1291 g_slist_free (widget_list);
1296 * gtk_item_factory_delete_item:
1297 * @ifactory: a #GtkItemFactory
1300 * Deletes the menu item which was created for @path by the given
1304 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1309 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1310 g_return_if_fail (path != NULL);
1312 widget = gtk_item_factory_get_widget (ifactory, path);
1316 if (GTK_IS_MENU (widget))
1317 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1319 gtk_widget_destroy (widget);
1324 * gtk_item_factory_delete_entry:
1325 * @ifactory: a #GtkItemFactory
1326 * @entry: a #GtkItemFactoryEntry
1328 * Deletes the menu item which was created from @entry by the given
1332 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1333 GtkItemFactoryEntry *entry)
1339 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1340 g_return_if_fail (entry != NULL);
1341 g_return_if_fail (entry->path != NULL);
1342 g_return_if_fail (entry->path[0] == '/');
1344 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1345 &path, &parent_path, &name))
1348 gtk_item_factory_delete_item (ifactory, path);
1351 g_free (parent_path);
1356 * gtk_item_factory_delete_entries:
1357 * @ifactory: a #GtkItemFactory
1358 * @n_entries: the length of @entries
1359 * @entries: an array of #GtkItemFactoryEntry<!-- -->s
1361 * Deletes the menu items which were created from the @entries by the given
1365 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1367 GtkItemFactoryEntry *entries)
1371 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1373 g_return_if_fail (entries != NULL);
1375 for (i = 0; i < n_entries; i++)
1376 gtk_item_factory_delete_entry (ifactory, entries + i);
1386 gtk_item_factory_menu_pos (GtkMenu *menu,
1392 MenuPos *mpos = func_data;
1399 * gtk_item_factory_popup_data_from_widget:
1401 * @returns: @popup_data associated with the item factory from
1402 * which @widget was created, or %NULL if @widget wasn't created
1403 * by an item factory
1405 * Obtains the @popup_data which was passed to
1406 * gtk_item_factory_popup_with_data(). This data is available until the menu
1407 * is popped down again.
1410 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1412 GtkItemFactory *ifactory;
1414 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1416 ifactory = gtk_item_factory_from_widget (widget);
1418 return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1424 * gtk_item_factory_popup_data:
1425 * @ifactory: a #GtkItemFactory
1426 * @returns: @popup_data associated with @ifactory
1428 * Obtains the @popup_data which was passed to
1429 * gtk_item_factory_popup_with_data(). This data is available until the menu
1430 * is popped down again.
1433 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1435 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1437 return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1441 ifactory_delete_popup_data (GtkObject *object,
1442 GtkItemFactory *ifactory)
1444 g_signal_handlers_disconnect_by_func (object,
1445 ifactory_delete_popup_data,
1447 g_object_set_qdata (G_OBJECT (ifactory), quark_popup_data, NULL);
1451 * gtk_item_factory_popup:
1452 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1453 * @x: the x position
1454 * @y: the y position
1455 * @mouse_button: the mouse button which was pressed to initiate the popup
1456 * @time_: the time at which the activation event occurred
1458 * Pops up the menu constructed from the item factory at (@x, @y).
1460 * The @mouse_button parameter should be the mouse button pressed to initiate
1461 * the menu popup. If the menu popup was initiated by something other than
1462 * a mouse button press, such as a mouse button release or a keypress,
1463 * @mouse_button should be 0.
1465 * The @time_ parameter should be the time stamp of the event that
1466 * initiated the popup. If such an event is not available, use
1467 * gtk_get_current_event_time() instead.
1469 * The operation of the @mouse_button and the @time_ parameter is the same
1470 * as the @button and @activation_time parameters for gtk_menu_popup().
1473 gtk_item_factory_popup (GtkItemFactory *ifactory,
1479 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1483 * gtk_item_factory_popup_with_data:
1484 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1485 * @popup_data: data available for callbacks while the menu is posted
1486 * @destroy: a #GtkDestroyNotify function to be called on @popup_data when
1487 * the menu is unposted
1488 * @x: the x position
1489 * @y: the y position
1490 * @mouse_button: the mouse button which was pressed to initiate the popup
1491 * @time_: the time at which the activation event occurred
1493 * Pops up the menu constructed from the item factory at (@x, @y). Callbacks
1494 * can access the @popup_data while the menu is posted via
1495 * gtk_item_factory_popup_data() and gtk_item_factory_popup_data_from_widget().
1497 * The @mouse_button parameter should be the mouse button pressed to initiate
1498 * the menu popup. If the menu popup was initiated by something other than
1499 * a mouse button press, such as a mouse button release or a keypress,
1500 * @mouse_button should be 0.
1502 * The @time_ parameter should be the time stamp of the event that
1503 * initiated the popup. If such an event is not available, use
1504 * gtk_get_current_event_time() instead.
1506 * The operation of the @mouse_button and the @time_ parameters is the same
1507 * as the @button and @activation_time parameters for gtk_menu_popup().
1510 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1511 gpointer popup_data,
1512 GtkDestroyNotify destroy,
1520 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1521 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1523 mpos = g_object_get_qdata (G_OBJECT (ifactory->widget), quark_if_menu_pos);
1527 mpos = g_new0 (MenuPos, 1);
1528 g_object_set_qdata_full (G_OBJECT (ifactory->widget),
1537 if (popup_data != NULL)
1539 g_object_set_qdata_full (G_OBJECT (ifactory),
1543 g_signal_connect (ifactory->widget,
1545 G_CALLBACK (ifactory_delete_popup_data),
1549 gtk_menu_popup (GTK_MENU (ifactory->widget),
1551 gtk_item_factory_menu_pos, mpos,
1552 mouse_button, time);
1556 * gtk_item_factory_set_translate_func:
1557 * @ifactory: a #GtkItemFactory
1558 * @func: the #GtkTranslateFunc function to be used to translate path elements
1559 * @data: data to pass to @func and @notify
1560 * @notify: a #GtkDestroyNotify function to be called when @ifactory is
1561 * destroyed and when the translation function is changed again
1563 * Sets a function to be used for translating the path elements before they
1567 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1568 GtkTranslateFunc func,
1570 GtkDestroyNotify notify)
1572 g_return_if_fail (ifactory != NULL);
1574 if (ifactory->translate_notify)
1575 ifactory->translate_notify (ifactory->translate_data);
1577 ifactory->translate_func = func;
1578 ifactory->translate_data = data;
1579 ifactory->translate_notify = notify;
1582 #define __GTK_ITEM_FACTORY_C__
1583 #include "gtkaliasdef.c"