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/gtksignal.h"
34 #include "gtk/gtkoptionmenu.h"
35 #include "gtk/gtkmenubar.h"
36 #include "gtk/gtkmenu.h"
37 #include "gtk/gtkmenuitem.h"
38 #include "gtk/gtkradiomenuitem.h"
39 #include "gtk/gtkcheckmenuitem.h"
40 #include "gtk/gtkimagemenuitem.h"
41 #include "gtk/gtktearoffmenuitem.h"
42 #include "gtk/gtkaccelmap.h"
43 #include "gtk/gtkaccellabel.h"
44 #include "gdk/gdkkeysyms.h"
45 #include "gtk/gtkimage.h"
46 #include "gtk/gtkstock.h"
47 #include "gtk/gtkiconfactory.h"
56 #include <io.h> /* For _open and _close */
59 #define S_ISREG(mode) ((mode)&_S_IFREG)
65 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
66 #define ITEM_BLOCK_SIZE (128)
69 /* --- structures --- */
70 typedef struct _GtkIFCBData GtkIFCBData;
71 typedef struct _GtkIFDumpData GtkIFDumpData;
74 GtkItemFactoryCallback func;
77 guint callback_action;
81 /* --- prototypes --- */
82 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
83 static void gtk_item_factory_init (GtkItemFactory *ifactory);
84 static void gtk_item_factory_destroy (GtkObject *object);
85 static void gtk_item_factory_finalize (GObject *object);
88 /* --- static variables --- */
89 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
90 static gpointer parent_class = NULL;
91 static const gchar *item_factory_string = "Gtk-<ItemFactory>";
92 static GMemChunk *ifactory_item_chunks = NULL;
93 static GMemChunk *ifactory_cb_data_chunks = NULL;
94 static GQuark quark_popup_data = 0;
95 static GQuark quark_if_menu_pos = 0;
96 static GQuark quark_item_factory = 0;
97 static GQuark quark_item_path = 0;
98 static GQuark quark_action = 0;
99 static GQuark quark_accel_group = 0;
100 static GQuark quark_type_item = 0;
101 static GQuark quark_type_title = 0;
102 static GQuark quark_type_radio_item = 0;
103 static GQuark quark_type_check_item = 0;
104 static GQuark quark_type_toggle_item = 0;
105 static GQuark quark_type_image_item = 0;
106 static GQuark quark_type_stock_item = 0;
107 static GQuark quark_type_tearoff_item = 0;
108 static GQuark quark_type_separator_item = 0;
109 static GQuark quark_type_branch = 0;
110 static GQuark quark_type_last_branch = 0;
113 /* --- functions --- */
115 gtk_item_factory_get_type (void)
117 static GtkType item_factory_type = 0;
119 if (!item_factory_type)
121 static const GtkTypeInfo item_factory_info =
124 sizeof (GtkItemFactory),
125 sizeof (GtkItemFactoryClass),
126 (GtkClassInitFunc) gtk_item_factory_class_init,
127 (GtkObjectInitFunc) gtk_item_factory_init,
128 /* reserved_1 */ NULL,
129 /* reserved_2 */ NULL,
130 (GtkClassInitFunc) NULL,
133 item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
136 return item_factory_type;
140 gtk_item_factory_class_init (GtkItemFactoryClass *class)
142 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
143 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
145 gtk_item_factory_class = class;
146 parent_class = g_type_class_peek_parent (class);
148 gobject_class->finalize = gtk_item_factory_finalize;
150 object_class->destroy = gtk_item_factory_destroy;
152 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
153 ifactory_item_chunks =
154 g_mem_chunk_new ("GtkItemFactoryItem",
155 sizeof (GtkItemFactoryItem),
156 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
158 ifactory_cb_data_chunks =
159 g_mem_chunk_new ("GtkIFCBData",
160 sizeof (GtkIFCBData),
161 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
164 quark_popup_data = g_quark_from_static_string ("GtkItemFactory-popup-data");
165 quark_if_menu_pos = g_quark_from_static_string ("GtkItemFactory-menu-position");
166 quark_item_factory = g_quark_from_static_string ("GtkItemFactory");
167 quark_item_path = g_quark_from_static_string ("GtkItemFactory-path");
168 quark_action = g_quark_from_static_string ("GtkItemFactory-action");
169 quark_accel_group = g_quark_from_static_string ("GtkAccelGroup");
170 quark_type_item = g_quark_from_static_string ("<Item>");
171 quark_type_title = g_quark_from_static_string ("<Title>");
172 quark_type_radio_item = g_quark_from_static_string ("<RadioItem>");
173 quark_type_check_item = g_quark_from_static_string ("<CheckItem>");
174 quark_type_toggle_item = g_quark_from_static_string ("<ToggleItem>");
175 quark_type_image_item = g_quark_from_static_string ("<ImageItem>");
176 quark_type_stock_item = g_quark_from_static_string ("<StockItem>");
177 quark_type_separator_item = g_quark_from_static_string ("<Separator>");
178 quark_type_tearoff_item = g_quark_from_static_string ("<Tearoff>");
179 quark_type_branch = g_quark_from_static_string ("<Branch>");
180 quark_type_last_branch = g_quark_from_static_string ("<LastBranch>");
184 gtk_item_factory_init (GtkItemFactory *ifactory)
188 object = GTK_OBJECT (ifactory);
190 ifactory->path = NULL;
191 ifactory->accel_group = NULL;
192 ifactory->widget = NULL;
193 ifactory->items = NULL;
194 ifactory->translate_func = NULL;
195 ifactory->translate_data = NULL;
196 ifactory->translate_notify = NULL;
200 * gtk_item_factory_new:
201 * @container_type: the kind of menu to create; can be
202 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
203 * @path: the factory path of the new item factory, a string of the form
204 * <literal>"<name>"</literal>
205 * @accel_group: a #GtkAccelGroup to which the accelerators for the
206 * menu items will be added, or %NULL to create a new one
207 * @returns: a new #GtkItemFactory
209 * Creates a new #GtkItemFactory.
212 gtk_item_factory_new (GtkType container_type,
214 GtkAccelGroup *accel_group)
216 GtkItemFactory *ifactory;
218 g_return_val_if_fail (path != NULL, NULL);
220 ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
221 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
227 gtk_item_factory_callback_marshal (GtkWidget *widget,
234 if (data->callback_type == 1)
236 GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
237 func1 (data->func_data, data->callback_action, widget);
239 else if (data->callback_type == 2)
241 GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
242 func2 (widget, data->func_data, data->callback_action);
247 gtk_item_factory_item_remove_widget (GtkWidget *widget,
248 GtkItemFactoryItem *item)
250 item->widgets = g_slist_remove (item->widgets, widget);
251 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
252 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_path);
256 * gtk_item_factory_add_foreign:
257 * @accel_widget: widget to install an accelerator on
258 * @full_path: the full path for the @accel_widget
259 * @accel_group: the accelerator group to install the accelerator in
260 * @keyval: key value of the accelerator
261 * @modifiers: modifier combination of the accelerator
263 * Installs an accelerator for @accel_widget in @accel_group, that causes
264 * the ::activate signal to be emitted if the accelerator is activated.
266 * This function can be used to make widgets participate in the accel
267 * saving/restoring functionality provided by gtk_accel_map_save() and
268 * gtk_accel_map_load(), even if they haven't been created by an item
272 gtk_item_factory_add_foreign (GtkWidget *accel_widget,
273 const gchar *full_path,
274 GtkAccelGroup *accel_group,
276 GdkModifierType modifiers)
278 GtkItemFactoryClass *class;
279 GtkItemFactoryItem *item;
281 g_return_if_fail (GTK_IS_WIDGET (accel_widget));
282 g_return_if_fail (full_path != NULL);
284 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
286 keyval = keyval != GDK_VoidSymbol ? keyval : 0;
288 item = g_hash_table_lookup (class->item_ht, full_path);
291 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
293 item->path = g_strdup (full_path);
294 item->widgets = NULL;
296 g_hash_table_insert (class->item_ht, item->path, item);
299 item->widgets = g_slist_prepend (item->widgets, accel_widget);
300 gtk_signal_connect (GTK_OBJECT (accel_widget),
302 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
305 /* set the item path for the widget
307 gtk_object_set_data_by_id (GTK_OBJECT (accel_widget),
308 quark_item_path, item->path);
309 gtk_widget_set_name (accel_widget, item->path);
312 gtk_accel_group_ref (accel_group);
313 gtk_object_set_data_by_id_full (GTK_OBJECT (accel_widget),
316 (GtkDestroyNotify) gtk_accel_group_unref);
319 gtk_object_set_data_by_id (GTK_OBJECT (accel_widget),
320 quark_accel_group, NULL);
322 /* install defined accelerators
324 if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (accel_widget)))
328 gtk_accel_map_add_entry (full_path, keyval, modifiers);
329 _gtk_widget_set_accel_path (accel_widget, full_path, accel_group);
335 ifactory_cb_data_free (gpointer mem)
337 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
341 gtk_item_factory_add_item (GtkItemFactory *ifactory,
343 const gchar *accelerator,
344 GtkItemFactoryCallback callback,
345 guint callback_action,
346 gpointer callback_data,
351 GtkItemFactoryClass *class;
352 GtkItemFactoryItem *item;
356 g_return_if_fail (widget != NULL);
357 g_return_if_fail (item_type != NULL);
359 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
361 /* set accelerator group on menu widgets
363 if (GTK_IS_MENU (widget))
364 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
366 /* connect callback if neccessary
372 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
373 data->func = callback;
374 data->callback_type = callback_type;
375 data->func_data = callback_data;
376 data->callback_action = callback_action;
378 gtk_object_weakref (GTK_OBJECT (widget),
379 ifactory_cb_data_free,
381 gtk_signal_connect (GTK_OBJECT (widget),
383 GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
387 /* link the widget into its item-entry
388 * and keep back pointer on both the item factory and the widget
390 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
391 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
393 gtk_accelerator_parse (accelerator, &keyval, &mods);
399 fpath = g_strconcat (ifactory->path, path, NULL);
400 gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
401 item = g_hash_table_lookup (class->item_ht, fpath);
404 g_return_if_fail (item != NULL);
406 if (!g_slist_find (ifactory->items, item))
407 ifactory->items = g_slist_prepend (ifactory->items, item);
411 * gtk_item_factory_construct:
412 * @ifactory: a #GtkItemFactory
413 * @container_type: the kind of menu to create; can be
414 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
415 * @path: the factory path of @ifactory, a string of the form
416 * <literal>"<name>"</literal>
417 * @accel_group: a #GtkAccelGroup to which the accelerators for the
418 * menu items will be added, or %NULL to create a new one
420 * Initializes an item factory.
423 gtk_item_factory_construct (GtkItemFactory *ifactory,
424 GtkType container_type,
426 GtkAccelGroup *accel_group)
430 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
431 g_return_if_fail (ifactory->accel_group == NULL);
432 g_return_if_fail (path != NULL);
433 if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
434 g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
438 if (path[0] != '<' && path[len - 1] != '>')
440 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
446 ifactory->accel_group = accel_group;
447 gtk_accel_group_ref (ifactory->accel_group);
450 ifactory->accel_group = gtk_accel_group_new ();
452 ifactory->path = g_strdup (path);
453 ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
454 "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
456 gtk_object_ref (GTK_OBJECT (ifactory));
457 gtk_object_sink (GTK_OBJECT (ifactory));
459 gtk_item_factory_add_item (ifactory,
467 * gtk_item_factory_from_path:
468 * @path: a string starting with a factory path of the form
469 * <literal>"<name>"</literal>
470 * @returns: the #GtkItemFactory created for the given factory path, or %NULL
472 * Finds an item factory which has been constructed using the
473 * <literal>"<name>"</literal> prefix of @path as the @path argument
474 * for gtk_item_factory_new().
477 gtk_item_factory_from_path (const gchar *path)
479 GtkItemFactoryClass *class;
480 GtkItemFactoryItem *item;
484 g_return_val_if_fail (path != NULL, NULL);
485 g_return_val_if_fail (path[0] == '<', NULL);
487 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
490 while (path[i] && path[i] != '>')
494 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
498 fname = g_new (gchar, i + 2);
499 g_memmove (fname, path, i + 1);
502 item = g_hash_table_lookup (class->item_ht, fname);
506 if (item && item->widgets)
507 return gtk_item_factory_from_widget (item->widgets->data);
513 gtk_item_factory_destroy (GtkObject *object)
515 GtkItemFactory *ifactory;
518 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
520 ifactory = (GtkItemFactory*) object;
522 if (ifactory->widget)
526 dobj = GTK_OBJECT (ifactory->widget);
528 gtk_object_ref (dobj);
529 gtk_object_sink (dobj);
530 gtk_object_destroy (dobj);
531 gtk_object_unref (dobj);
533 ifactory->widget = NULL;
536 for (slist = ifactory->items; slist; slist = slist->next)
538 GtkItemFactoryItem *item = slist->data;
541 for (link = item->widgets; link; link = link->next)
542 if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory)
543 gtk_object_remove_data_by_id (link->data, quark_item_factory);
545 g_slist_free (ifactory->items);
546 ifactory->items = NULL;
548 GTK_OBJECT_CLASS (parent_class)->destroy (object);
552 gtk_item_factory_finalize (GObject *object)
554 GtkItemFactory *ifactory;
556 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
558 ifactory = GTK_ITEM_FACTORY (object);
560 gtk_accel_group_unref (ifactory->accel_group);
561 g_free (ifactory->path);
562 g_assert (ifactory->widget == NULL);
564 if (ifactory->translate_notify)
565 ifactory->translate_notify (ifactory->translate_data);
567 G_OBJECT_CLASS (parent_class)->finalize (object);
571 * gtk_item_factory_from_widget:
573 * @returns: the item factory from which @widget was created, or %NULL
575 * Obtains the item factory from which a widget was created.
578 gtk_item_factory_from_widget (GtkWidget *widget)
580 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
582 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
586 * gtk_item_factory_path_from_widget:
588 * @returns: the full path to @widget if it been created by an item factory,
591 * If @widget has been created by an item factory, returns the full path
592 * to it. (The full path of a widget is the concatenation of the factory
593 * path specified in gtk_item_factory_new() with the path specified in the
594 * #GtkItemFactoryEntry from which the widget was created.)
597 gtk_item_factory_path_from_widget (GtkWidget *widget)
599 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
601 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_path);
605 * gtk_item_factory_create_items:
606 * @ifactory: a #GtkItemFactory
607 * @n_entries: the length of @entries
608 * @entries: an array of #GtkItemFactoryEntry<!>s whose @callback members
609 * must by of type #GtkItemFactoryCallback1
610 * @callback_data: data passed to the callback functions of all entries
612 * Creates the menu items from the @entries.
615 gtk_item_factory_create_items (GtkItemFactory *ifactory,
617 GtkItemFactoryEntry *entries,
618 gpointer callback_data)
620 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
624 * gtk_item_factory_create_items_ac:
625 * @ifactory: a #GtkItemFactory
626 * @n_entries: the length of @entries
627 * @entries: an array of #GtkItemFactoryEntry<!>s
628 * @callback_data: data passed to the callback functions of all entries
629 * @callback_type: 1 if the callback functions in @entries are of type
630 * #GtkItemFactoryCallback1, 2 if they are of type #GtkItemFactoryCallback2
632 * Creates the menu items from the @entries.
635 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
637 GtkItemFactoryEntry *entries,
638 gpointer callback_data,
643 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
644 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
649 g_return_if_fail (entries != NULL);
651 for (i = 0; i < n_entries; i++)
652 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
656 * gtk_item_factory_get_widget:
657 * @ifactory: a #GtkItemFactory
658 * @path: the path to the widget
659 * @returns: the widget for the given path, or %NULL if @path doesn't lead
662 * Obtains the widget which corresponds to @path.
664 * If the widget corresponding to @path is a menu item which opens a
665 * submenu, then the submenu is returned. If you are interested in the menu
666 * item, use gtk_item_factory_get_item() instead.
669 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
672 GtkItemFactoryClass *class;
673 GtkItemFactoryItem *item;
675 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
676 g_return_val_if_fail (path != NULL, NULL);
678 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
681 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
686 fpath = g_strconcat (ifactory->path, path, NULL);
687 item = g_hash_table_lookup (class->item_ht, fpath);
695 for (slist = item->widgets; slist; slist = slist->next)
697 if (gtk_item_factory_from_widget (slist->data) == ifactory)
706 * gtk_item_factory_get_widget_by_action:
707 * @ifactory: a #GtkItemFactory
708 * @action: an action as specified in the @callback_action field
709 * of #GtkItemFactoryEntry
710 * @returns: the widget which corresponds to the given action, or %NULL
711 * if no widget was found
713 * Obtains the widget which was constructed from the #GtkItemFactoryEntry
714 * with the given @action.
716 * If there are multiple items with the same action, the result is
720 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
725 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
727 for (slist = ifactory->items; slist; slist = slist->next)
729 GtkItemFactoryItem *item = slist->data;
732 for (link = item->widgets; link; link = link->next)
733 if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory &&
734 gtk_object_get_data_by_id (link->data, quark_action) == GUINT_TO_POINTER (action))
742 * gtk_item_factory_get_item:
743 * @ifactory: a #GtkItemFactory
744 * @path: the path to the menu item
745 * @returns: the menu item for the given path, or %NULL if @path doesn't
746 * lead to a menu item
748 * Obtains the menu item which corresponds to @path.
750 * If the widget corresponding to @path is a menu item which opens a
751 * submenu, then the item is returned. If you are interested in the submenu,
752 * use gtk_item_factory_get_widget() instead.
755 gtk_item_factory_get_item (GtkItemFactory *ifactory,
760 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
761 g_return_val_if_fail (path != NULL, NULL);
763 widget = gtk_item_factory_get_widget (ifactory, path);
765 if (GTK_IS_MENU (widget))
766 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
768 return GTK_IS_ITEM (widget) ? widget : NULL;
773 * gtk_item_factory_get_item_by_action:
774 * @ifactory: a #GtkItemFactory
775 * @action: an action as specified in the @callback_action field
776 * of #GtkItemFactoryEntry
777 * @returns: the menu item which corresponds to the given action, or %NULL
778 * if no menu item was found
780 * Obtains the menu item which was constructed from the first
781 * #GtkItemFactoryEntry with the given @action.
784 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
789 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
791 widget = gtk_item_factory_get_widget_by_action (ifactory, action);
793 if (GTK_IS_MENU (widget))
794 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
796 return GTK_IS_ITEM (widget) ? widget : NULL;
800 item_factory_find_separator_r (char *path)
802 gchar *result = NULL;
803 gboolean escaped = FALSE;
813 else if (*path == '/')
824 item_factory_unescape_label (const char *label)
826 char *new = g_malloc (strlen (label) + 1);
828 gboolean escaped = FALSE;
854 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
863 *path = g_strdup (str);
884 *parent_path = g_strdup (*path);
885 p = item_factory_find_separator_r (*parent_path);
888 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
893 if (ifactory->translate_func)
894 translation = ifactory->translate_func (str, ifactory->translate_data);
898 p = item_factory_find_separator_r (translation);
904 *item = item_factory_unescape_label (p);
910 * gtk_item_factory_create_item:
911 * @ifactory: a #GtkItemFactory
912 * @entry: the #GtkItemFactoryEntry to create an item for
913 * @callback_data: data passed to the callback function of @entry
914 * @callback_type: 1 if the callback function of @entry is of type
915 * #GtkItemFactoryCallback1, 2 if it is of type #GtkItemFactoryCallback2
917 * Creates an item for @entry.
920 gtk_item_factory_create_item (GtkItemFactory *ifactory,
921 GtkItemFactoryEntry *entry,
922 gpointer callback_data,
925 GtkOptionMenu *option_menu = NULL;
936 gchar *item_type_path;
937 GtkStockItem stock_item;
939 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
940 g_return_if_fail (entry != NULL);
941 g_return_if_fail (entry->path != NULL);
942 g_return_if_fail (entry->path[0] == '/');
943 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
945 if (!entry->item_type ||
946 entry->item_type[0] == 0)
948 item_type_path = "<Item>";
949 type_id = quark_type_item;
953 item_type_path = entry->item_type;
954 type_id = gtk_object_data_try_key (item_type_path);
958 if (type_id == quark_type_item)
959 type = GTK_TYPE_MENU_ITEM;
960 else if (type_id == quark_type_title)
961 type = GTK_TYPE_MENU_ITEM;
962 else if (type_id == quark_type_radio_item)
963 type = GTK_TYPE_RADIO_MENU_ITEM;
964 else if (type_id == quark_type_check_item)
965 type = GTK_TYPE_CHECK_MENU_ITEM;
966 else if (type_id == quark_type_image_item)
967 type = GTK_TYPE_IMAGE_MENU_ITEM;
968 else if (type_id == quark_type_stock_item)
969 type = GTK_TYPE_IMAGE_MENU_ITEM;
970 else if (type_id == quark_type_tearoff_item)
971 type = GTK_TYPE_TEAROFF_MENU_ITEM;
972 else if (type_id == quark_type_toggle_item)
973 type = GTK_TYPE_CHECK_MENU_ITEM;
974 else if (type_id == quark_type_separator_item)
975 type = GTK_TYPE_MENU_ITEM;
976 else if (type_id == quark_type_branch)
977 type = GTK_TYPE_MENU_ITEM;
978 else if (type_id == quark_type_last_branch)
979 type = GTK_TYPE_MENU_ITEM;
982 GtkWidget *radio_link;
984 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
985 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
987 type = GTK_TYPE_RADIO_MENU_ITEM;
988 radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
992 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
999 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1000 &path, &parent_path, &name))
1003 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1006 GtkItemFactoryEntry pentry;
1009 ppath = g_strdup (entry->path);
1010 p = item_factory_find_separator_r (ppath);
1011 g_return_if_fail (p != NULL);
1013 pentry.path = ppath;
1014 pentry.accelerator = NULL;
1015 pentry.callback = NULL;
1016 pentry.callback_action = 0;
1017 pentry.item_type = "<Branch>";
1019 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1022 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1023 g_return_if_fail (parent != NULL);
1026 if (GTK_IS_OPTION_MENU (parent))
1028 option_menu = GTK_OPTION_MENU (parent);
1029 if (!option_menu->menu)
1031 GtkWidget *menu = g_object_new (GTK_TYPE_MENU, NULL);
1032 gchar *p = g_strconcat (ifactory->path, parent_path, NULL);
1034 gtk_menu_set_accel_path (GTK_MENU (menu), p);
1036 gtk_option_menu_set_menu (option_menu, menu);
1038 parent = option_menu->menu;
1040 g_free (parent_path);
1042 g_return_if_fail (GTK_IS_CONTAINER (parent));
1044 accelerator = entry->accelerator;
1046 widget = gtk_widget_new (type,
1048 "sensitive", (type_id != quark_type_separator_item &&
1049 type_id != quark_type_title),
1052 if (option_menu && !option_menu->menu_item)
1053 gtk_option_menu_set_history (option_menu, 0);
1055 if (type == GTK_TYPE_RADIO_MENU_ITEM)
1056 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1057 if (GTK_IS_CHECK_MENU_ITEM (widget))
1058 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
1059 if (type_id == quark_type_image_item)
1061 GdkPixbuf *pixbuf = NULL;
1064 pixbuf = gdk_pixbuf_new_from_inline (-1,
1069 image = gtk_image_new_from_pixbuf (pixbuf);
1072 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1073 gtk_widget_show (image);
1076 g_object_unref (G_OBJECT (pixbuf));
1078 if (type_id == quark_type_stock_item)
1080 image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1081 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1082 gtk_widget_show (image);
1084 if (gtk_stock_lookup (entry->extra_data, &stock_item))
1087 accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1091 /* install underline accelerators for this item
1093 if (type_id != quark_type_separator_item &&
1094 type_id != quark_type_tearoff_item &&
1099 label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1102 "accel_widget", widget,
1105 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1110 if (type_id == quark_type_branch ||
1111 type_id == quark_type_last_branch)
1115 if (entry->callback)
1116 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1118 if (type_id == quark_type_last_branch)
1119 gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE);
1122 widget = gtk_widget_new (GTK_TYPE_MENU, NULL);
1123 p = g_strconcat (ifactory->path, path, NULL);
1124 gtk_menu_set_accel_path (GTK_MENU (widget), p);
1127 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1130 gtk_item_factory_add_item (ifactory,
1132 (type_id == quark_type_branch ||
1133 type_id == quark_type_last_branch) ?
1134 (GtkItemFactoryCallback) NULL : entry->callback,
1135 entry->callback_action, callback_data,
1139 if (accelerator != entry->accelerator)
1140 g_free (accelerator);
1145 * gtk_item_factory_create_menu_entries:
1146 * @n_entries: the length of @entries
1147 * @entries: an array of #GtkMenuEntry<!>s
1149 * Creates the menu items from the @entries.
1152 gtk_item_factory_create_menu_entries (guint n_entries,
1153 GtkMenuEntry *entries)
1155 static GPatternSpec *pspec_separator = NULL;
1156 static GPatternSpec *pspec_check = NULL;
1161 g_return_if_fail (entries != NULL);
1163 if (!pspec_separator)
1165 pspec_separator = g_pattern_spec_new ("*<separator>*");
1166 pspec_check = g_pattern_spec_new ("*<check>*");
1169 for (i = 0; i < n_entries; i++)
1171 GtkItemFactory *ifactory;
1172 GtkItemFactoryEntry entry;
1176 path = entries[i].path;
1177 ifactory = gtk_item_factory_from_path (path);
1180 g_warning ("gtk_item_factory_create_menu_entries(): "
1181 "entry[%u] refers to unknown item factory: \"%s\"",
1182 i, entries[i].path);
1186 while (*path != '>')
1192 entry.accelerator = entries[i].accelerator;
1193 entry.callback = entries[i].callback;
1194 entry.callback_action = 0;
1195 if (g_pattern_match_string (pspec_separator, path))
1196 entry.item_type = "<Separator>";
1197 else if (!g_pattern_match_string (pspec_check, path))
1198 entry.item_type = NULL;
1201 gboolean in_brace = FALSE;
1204 cpath = g_new (gchar, strlen (path));
1210 else if (*path == '>')
1217 entry.item_type = "<ToggleItem>";
1221 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1222 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1228 * gtk_item_factories_path_delete:
1229 * @ifactory_path: a factory path to prepend to @path. May be %NULL if @path
1230 * starts with a factory path
1233 * Deletes all widgets constructed from the specified path.
1236 gtk_item_factories_path_delete (const gchar *ifactory_path,
1239 GtkItemFactoryClass *class;
1240 GtkItemFactoryItem *item;
1242 g_return_if_fail (path != NULL);
1244 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1247 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1252 g_return_if_fail (ifactory_path != NULL);
1254 fpath = g_strconcat (ifactory_path, path, NULL);
1255 item = g_hash_table_lookup (class->item_ht, fpath);
1261 GSList *widget_list;
1265 for (slist = item->widgets; slist; slist = slist->next)
1269 widget = slist->data;
1270 widget_list = g_slist_prepend (widget_list, widget);
1271 gtk_widget_ref (widget);
1274 for (slist = widget_list; slist; slist = slist->next)
1278 widget = slist->data;
1279 gtk_widget_destroy (widget);
1280 gtk_widget_unref (widget);
1282 g_slist_free (widget_list);
1287 * gtk_item_factory_delete_item:
1288 * @ifactory: a #GtkItemFactory
1291 * Deletes the menu item which was created for @path by the given
1295 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1298 GtkItemFactoryClass *class;
1301 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1302 g_return_if_fail (path != NULL);
1304 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
1306 widget = gtk_item_factory_get_widget (ifactory, path);
1310 if (GTK_IS_MENU (widget))
1311 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1313 gtk_widget_destroy (widget);
1318 * gtk_item_factory_delete_entry:
1319 * @ifactory: a #GtkItemFactory
1320 * @entry: a #GtkItemFactoryEntry
1322 * Deletes the menu item which was created from @entry by the given
1326 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1327 GtkItemFactoryEntry *entry)
1333 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1334 g_return_if_fail (entry != NULL);
1335 g_return_if_fail (entry->path != NULL);
1336 g_return_if_fail (entry->path[0] == '/');
1338 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1339 &path, &parent_path, &name))
1342 gtk_item_factory_delete_item (ifactory, path);
1345 g_free (parent_path);
1350 * gtk_item_factory_delete_entries:
1351 * @ifactory: a #GtkItemFactory
1352 * @n_entries: the length of @entries
1353 * @entries: an array of #GtkItemFactoryEntry<!>s
1355 * Deletes the menu items which were created from the @entries by the given
1359 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1361 GtkItemFactoryEntry *entries)
1365 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1367 g_return_if_fail (entries != NULL);
1369 for (i = 0; i < n_entries; i++)
1370 gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1380 gtk_item_factory_menu_pos (GtkMenu *menu,
1386 MenuPos *mpos = func_data;
1393 * gtk_item_factory_popup_data_from_widget:
1395 * @returns: @popup_data associated with the item factory from
1396 * which @widget was created, or %NULL if @widget wasn't created
1397 * by an item factory
1399 * Obtains the @popup_data which was passed to
1400 * gtk_item_factory_popup_with_data(). This data is available until the menu
1401 * is popped down again.
1404 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1406 GtkItemFactory *ifactory;
1408 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1410 ifactory = gtk_item_factory_from_widget (widget);
1412 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1418 * gtk_item_factory_popup_data:
1419 * @ifactory: a #GtkItemFactory
1420 * @returns: @popup_data associated with @ifactory
1422 * Obtains the @popup_data which was passed to
1423 * gtk_item_factory_popup_with_data(). This data is available until the menu
1424 * is popped down again.
1427 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1429 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1431 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1435 ifactory_delete_popup_data (GtkObject *object,
1436 GtkItemFactory *ifactory)
1438 gtk_signal_disconnect_by_func (object,
1439 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1441 gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1445 * gtk_item_factory_popup:
1446 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1447 * @x: the x position
1448 * @y: the y position
1449 * @mouse_button: the mouse button which was pressed to initiate this action
1450 * @time: a timestamp for this action
1452 * Pops up the menu constructed from the item factory at (@x, @y).
1455 gtk_item_factory_popup (GtkItemFactory *ifactory,
1461 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1465 * gtk_item_factory_popup_with_data:
1466 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1467 * @popup_data: data available for callbacks while the menu is posted
1468 * @destroy: a #GtkDestroyNotify function to be called on @popup_data when
1469 * the menu is unposted
1470 * @x: the x position
1471 * @y: the y position
1472 * @mouse_button: the mouse button which was pressed to initiate this action
1473 * @time: a timestamp for this action
1475 * Pops up the menu constructed from the item factory at (@x, @y). Callbacks
1476 * can access the @popup_data while the menu is posted via
1477 * gtk_item_factory_popup_data() and gtk_item_factory_popup_data_from_widget().
1480 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1481 gpointer popup_data,
1482 GtkDestroyNotify destroy,
1490 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1491 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1493 mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1497 mpos = g_new0 (MenuPos, 1);
1498 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1507 if (popup_data != NULL)
1509 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1513 gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1515 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1519 gtk_menu_popup (GTK_MENU (ifactory->widget),
1521 gtk_item_factory_menu_pos, mpos,
1522 mouse_button, time);
1526 * gtk_item_factory_set_translate_func:
1527 * @ifactory: a #GtkItemFactory
1528 * @func: the #GtkTranslateFunc function to be used to translate path elements
1529 * @data: data to pass to @func and @notify
1530 * @notify: a #GtkDestroyNotify function to be called when @ifactory is
1531 * destroyed and when the translation function is changed again
1533 * Sets a function to be used for translating the path elements before they
1537 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1538 GtkTranslateFunc func,
1540 GtkDestroyNotify notify)
1542 g_return_if_fail (ifactory != NULL);
1544 if (ifactory->translate_notify)
1545 ifactory->translate_notify (ifactory->translate_data);
1547 ifactory->translate_func = func;
1548 ifactory->translate_data = data;
1549 ifactory->translate_notify = notify;