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/gtkoptionmenu.h"
34 #include "gtk/gtkmenubar.h"
35 #include "gtk/gtkmenu.h"
36 #include "gtk/gtkmenuitem.h"
37 #include "gtk/gtkradiomenuitem.h"
38 #include "gtk/gtkcheckmenuitem.h"
39 #include "gtk/gtkimagemenuitem.h"
40 #include "gtk/gtktearoffmenuitem.h"
41 #include "gtk/gtkaccelmap.h"
42 #include "gtk/gtkaccellabel.h"
43 #include "gdk/gdkkeysyms.h"
44 #include "gtk/gtkimage.h"
45 #include "gtk/gtkstock.h"
46 #include "gtk/gtkiconfactory.h"
55 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
56 #define ITEM_BLOCK_SIZE (128)
59 /* --- structures --- */
60 typedef struct _GtkIFCBData GtkIFCBData;
61 typedef struct _GtkIFDumpData GtkIFDumpData;
64 GtkItemFactoryCallback func;
67 guint callback_action;
71 /* --- prototypes --- */
72 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
73 static void gtk_item_factory_init (GtkItemFactory *ifactory);
74 static void gtk_item_factory_destroy (GtkObject *object);
75 static void gtk_item_factory_finalize (GObject *object);
78 /* --- static variables --- */
79 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
80 static gpointer parent_class = NULL;
81 static const gchar *item_factory_string = "Gtk-<ItemFactory>";
82 static GMemChunk *ifactory_item_chunks = NULL;
83 static GMemChunk *ifactory_cb_data_chunks = NULL;
84 static GQuark quark_popup_data = 0;
85 static GQuark quark_if_menu_pos = 0;
86 static GQuark quark_item_factory = 0;
87 static GQuark quark_item_path = 0;
88 static GQuark quark_action = 0;
89 static GQuark quark_accel_group = 0;
90 static GQuark quark_type_item = 0;
91 static GQuark quark_type_title = 0;
92 static GQuark quark_type_radio_item = 0;
93 static GQuark quark_type_check_item = 0;
94 static GQuark quark_type_toggle_item = 0;
95 static GQuark quark_type_image_item = 0;
96 static GQuark quark_type_stock_item = 0;
97 static GQuark quark_type_tearoff_item = 0;
98 static GQuark quark_type_separator_item = 0;
99 static GQuark quark_type_branch = 0;
100 static GQuark quark_type_last_branch = 0;
103 /* --- functions --- */
105 gtk_item_factory_get_type (void)
107 static GType item_factory_type = 0;
109 if (!item_factory_type)
111 static const GTypeInfo item_factory_info =
113 sizeof (GtkItemFactoryClass),
114 NULL, /* base_init */
115 NULL, /* base_finalize */
116 (GClassInitFunc) gtk_item_factory_class_init,
117 NULL, /* class_finalize */
118 NULL, /* class_data */
119 sizeof (GtkItemFactory),
121 (GInstanceInitFunc) gtk_item_factory_init,
125 g_type_register_static (GTK_TYPE_OBJECT, "GtkItemFactory",
126 &item_factory_info, 0);
129 return item_factory_type;
133 gtk_item_factory_class_init (GtkItemFactoryClass *class)
135 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
136 GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
138 gtk_item_factory_class = class;
139 parent_class = g_type_class_peek_parent (class);
141 gobject_class->finalize = gtk_item_factory_finalize;
143 object_class->destroy = gtk_item_factory_destroy;
145 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
146 ifactory_item_chunks =
147 g_mem_chunk_new ("GtkItemFactoryItem",
148 sizeof (GtkItemFactoryItem),
149 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
151 ifactory_cb_data_chunks =
152 g_mem_chunk_new ("GtkIFCBData",
153 sizeof (GtkIFCBData),
154 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
157 quark_popup_data = g_quark_from_static_string ("GtkItemFactory-popup-data");
158 quark_if_menu_pos = g_quark_from_static_string ("GtkItemFactory-menu-position");
159 quark_item_factory = g_quark_from_static_string ("GtkItemFactory");
160 quark_item_path = g_quark_from_static_string ("GtkItemFactory-path");
161 quark_action = g_quark_from_static_string ("GtkItemFactory-action");
162 quark_accel_group = g_quark_from_static_string ("GtkAccelGroup");
163 quark_type_item = g_quark_from_static_string ("<Item>");
164 quark_type_title = g_quark_from_static_string ("<Title>");
165 quark_type_radio_item = g_quark_from_static_string ("<RadioItem>");
166 quark_type_check_item = g_quark_from_static_string ("<CheckItem>");
167 quark_type_toggle_item = g_quark_from_static_string ("<ToggleItem>");
168 quark_type_image_item = g_quark_from_static_string ("<ImageItem>");
169 quark_type_stock_item = g_quark_from_static_string ("<StockItem>");
170 quark_type_separator_item = g_quark_from_static_string ("<Separator>");
171 quark_type_tearoff_item = g_quark_from_static_string ("<Tearoff>");
172 quark_type_branch = g_quark_from_static_string ("<Branch>");
173 quark_type_last_branch = g_quark_from_static_string ("<LastBranch>");
177 gtk_item_factory_init (GtkItemFactory *ifactory)
181 object = GTK_OBJECT (ifactory);
183 ifactory->path = NULL;
184 ifactory->accel_group = NULL;
185 ifactory->widget = NULL;
186 ifactory->items = NULL;
187 ifactory->translate_func = NULL;
188 ifactory->translate_data = NULL;
189 ifactory->translate_notify = NULL;
193 * gtk_item_factory_new:
194 * @container_type: the kind of menu to create; can be
195 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
196 * @path: the factory path of the new item factory, a string of the form
197 * <literal>"<name>"</literal>
198 * @accel_group: a #GtkAccelGroup to which the accelerators for the
199 * menu items will be added, or %NULL to create a new one
200 * @returns: a new #GtkItemFactory
202 * Creates a new #GtkItemFactory.
205 gtk_item_factory_new (GType container_type,
207 GtkAccelGroup *accel_group)
209 GtkItemFactory *ifactory;
211 g_return_val_if_fail (path != NULL, NULL);
213 ifactory = g_object_new (GTK_TYPE_ITEM_FACTORY, NULL);
214 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
220 gtk_item_factory_callback_marshal (GtkWidget *widget,
227 if (data->callback_type == 1)
229 GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
230 func1 (data->func_data, data->callback_action, widget);
232 else if (data->callback_type == 2)
234 GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
235 func2 (widget, data->func_data, data->callback_action);
240 gtk_item_factory_item_remove_widget (GtkWidget *widget,
241 GtkItemFactoryItem *item)
243 item->widgets = g_slist_remove (item->widgets, widget);
244 g_object_set_qdata (G_OBJECT (widget), quark_item_factory, NULL);
245 g_object_set_qdata (G_OBJECT (widget), quark_item_path, NULL);
249 * gtk_item_factory_add_foreign:
250 * @accel_widget: widget to install an accelerator on
251 * @full_path: the full path for the @accel_widget
252 * @accel_group: the accelerator group to install the accelerator in
253 * @keyval: key value of the accelerator
254 * @modifiers: modifier combination of the accelerator
256 * Installs an accelerator for @accel_widget in @accel_group, that causes
257 * the ::activate signal to be emitted if the accelerator is activated.
259 * This function can be used to make widgets participate in the accel
260 * saving/restoring functionality provided by gtk_accel_map_save() and
261 * gtk_accel_map_load(), even if they haven't been created by an item
262 * factory. The recommended API for this purpose are the functions
263 * gtk_menu_item_set_accel_path() and gtk_widget_set_accel_path(); don't
264 * use gtk_item_factory_add_foreign() in new code, since it is likely to
265 * be removed in the future.
268 gtk_item_factory_add_foreign (GtkWidget *accel_widget,
269 const gchar *full_path,
270 GtkAccelGroup *accel_group,
272 GdkModifierType modifiers)
274 GtkItemFactoryClass *class;
275 GtkItemFactoryItem *item;
277 g_return_if_fail (GTK_IS_WIDGET (accel_widget));
278 g_return_if_fail (full_path != NULL);
280 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
282 keyval = keyval != GDK_VoidSymbol ? keyval : 0;
284 item = g_hash_table_lookup (class->item_ht, full_path);
287 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
289 item->path = g_strdup (full_path);
290 item->widgets = NULL;
292 g_hash_table_insert (class->item_ht, item->path, item);
295 item->widgets = g_slist_prepend (item->widgets, accel_widget);
296 g_signal_connect (accel_widget,
298 G_CALLBACK (gtk_item_factory_item_remove_widget),
301 /* set the item path for the widget
303 g_object_set_qdata (G_OBJECT (accel_widget), quark_item_path, item->path);
304 gtk_widget_set_name (accel_widget, item->path);
307 g_object_ref (accel_group);
308 g_object_set_qdata_full (G_OBJECT (accel_widget),
314 g_object_set_qdata (G_OBJECT (accel_widget), quark_accel_group, NULL);
316 /* install defined accelerators
318 if (g_signal_lookup ("activate", G_TYPE_FROM_INSTANCE (accel_widget)))
322 gtk_accel_map_add_entry (full_path, keyval, modifiers);
323 gtk_widget_set_accel_path (accel_widget, full_path, accel_group);
329 ifactory_cb_data_free (gpointer mem)
331 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
335 gtk_item_factory_add_item (GtkItemFactory *ifactory,
337 const gchar *accelerator,
338 GtkItemFactoryCallback callback,
339 guint callback_action,
340 gpointer callback_data,
345 GtkItemFactoryClass *class;
346 GtkItemFactoryItem *item;
349 GdkModifierType mods;
351 g_return_if_fail (widget != NULL);
352 g_return_if_fail (item_type != NULL);
354 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
356 /* set accelerator group on menu widgets
358 if (GTK_IS_MENU (widget))
359 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
361 /* connect callback if neccessary
367 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
368 data->func = callback;
369 data->callback_type = callback_type;
370 data->func_data = callback_data;
371 data->callback_action = callback_action;
373 g_object_weak_ref (G_OBJECT (widget),
374 (GWeakNotify) ifactory_cb_data_free,
376 g_signal_connect (widget,
378 G_CALLBACK (gtk_item_factory_callback_marshal),
382 /* link the widget into its item-entry
383 * and keep back pointer on both the item factory and the widget
385 g_object_set_qdata (G_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
386 g_object_set_qdata (G_OBJECT (widget), quark_item_factory, ifactory);
388 gtk_accelerator_parse (accelerator, &keyval, &mods);
394 fpath = g_strconcat (ifactory->path, path, NULL);
395 gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
396 item = g_hash_table_lookup (class->item_ht, fpath);
399 g_return_if_fail (item != NULL);
401 if (!g_slist_find (ifactory->items, item))
402 ifactory->items = g_slist_prepend (ifactory->items, item);
406 * gtk_item_factory_construct:
407 * @ifactory: a #GtkItemFactory
408 * @container_type: the kind of menu to create; can be
409 * #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
410 * @path: the factory path of @ifactory, a string of the form
411 * <literal>"<name>"</literal>
412 * @accel_group: a #GtkAccelGroup to which the accelerators for the
413 * menu items will be added, or %NULL to create a new one
415 * Initializes an item factory.
418 gtk_item_factory_construct (GtkItemFactory *ifactory,
419 GType container_type,
421 GtkAccelGroup *accel_group)
425 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
426 g_return_if_fail (ifactory->accel_group == NULL);
427 g_return_if_fail (path != NULL);
428 if (!g_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
429 g_return_if_fail (g_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
433 if (path[0] != '<' && path[len - 1] != '>')
435 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
441 ifactory->accel_group = accel_group;
442 g_object_ref (ifactory->accel_group);
445 ifactory->accel_group = gtk_accel_group_new ();
447 ifactory->path = g_strdup (path);
448 ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
449 "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
451 g_object_ref (ifactory);
452 gtk_object_sink (GTK_OBJECT (ifactory));
454 gtk_item_factory_add_item (ifactory,
462 * gtk_item_factory_from_path:
463 * @path: a string starting with a factory path of the form
464 * <literal>"<name>"</literal>
465 * @returns: the #GtkItemFactory created for the given factory path, or %NULL
467 * Finds an item factory which has been constructed using the
468 * <literal>"<name>"</literal> prefix of @path as the @path argument
469 * for gtk_item_factory_new().
472 gtk_item_factory_from_path (const gchar *path)
474 GtkItemFactoryClass *class;
475 GtkItemFactoryItem *item;
479 g_return_val_if_fail (path != NULL, NULL);
480 g_return_val_if_fail (path[0] == '<', NULL);
482 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
485 while (path[i] && path[i] != '>')
489 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
493 fname = g_new (gchar, i + 2);
494 g_memmove (fname, path, i + 1);
497 item = g_hash_table_lookup (class->item_ht, fname);
501 if (item && item->widgets)
502 return gtk_item_factory_from_widget (item->widgets->data);
508 gtk_item_factory_destroy (GtkObject *object)
510 GtkItemFactory *ifactory;
513 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
515 ifactory = (GtkItemFactory*) object;
517 if (ifactory->widget)
521 dobj = GTK_OBJECT (ifactory->widget);
524 gtk_object_sink (dobj);
525 gtk_object_destroy (dobj);
526 g_object_unref (dobj);
528 ifactory->widget = NULL;
531 for (slist = ifactory->items; slist; slist = slist->next)
533 GtkItemFactoryItem *item = slist->data;
536 for (link = item->widgets; link; link = link->next)
537 if (g_object_get_qdata (link->data, quark_item_factory) == ifactory)
538 g_object_set_qdata (link->data, quark_item_factory, NULL);
540 g_slist_free (ifactory->items);
541 ifactory->items = NULL;
543 GTK_OBJECT_CLASS (parent_class)->destroy (object);
547 gtk_item_factory_finalize (GObject *object)
549 GtkItemFactory *ifactory;
551 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
553 ifactory = GTK_ITEM_FACTORY (object);
555 g_object_unref (ifactory->accel_group);
556 g_free (ifactory->path);
557 g_assert (ifactory->widget == NULL);
559 if (ifactory->translate_notify)
560 ifactory->translate_notify (ifactory->translate_data);
562 G_OBJECT_CLASS (parent_class)->finalize (object);
566 * gtk_item_factory_from_widget:
568 * @returns: the item factory from which @widget was created, or %NULL
570 * Obtains the item factory from which a widget was created.
573 gtk_item_factory_from_widget (GtkWidget *widget)
575 GtkItemFactory *ifactory;
577 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
579 ifactory = g_object_get_qdata (G_OBJECT (widget), quark_item_factory);
581 if (ifactory == NULL && GTK_IS_MENU_ITEM (widget) &&
582 GTK_MENU_ITEM (widget)->submenu != NULL)
584 GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
585 ifactory = g_object_get_qdata (G_OBJECT (menu), quark_item_factory);
592 * gtk_item_factory_path_from_widget:
594 * @returns: the full path to @widget if it has been created by an item
595 * factory, %NULL otherwise. This value is owned by GTK+ and must not be
598 * If @widget has been created by an item factory, returns the full path
599 * to it. (The full path of a widget is the concatenation of the factory
600 * path specified in gtk_item_factory_new() with the path specified in the
601 * #GtkItemFactoryEntry from which the widget was created.)
603 G_CONST_RETURN gchar*
604 gtk_item_factory_path_from_widget (GtkWidget *widget)
608 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
610 path = g_object_get_qdata (G_OBJECT (widget), quark_item_path);
612 if (path == NULL && GTK_IS_MENU_ITEM (widget) &&
613 GTK_MENU_ITEM (widget)->submenu != NULL)
615 GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
616 path = g_object_get_qdata (G_OBJECT (menu), quark_item_path);
623 * gtk_item_factory_create_items:
624 * @ifactory: a #GtkItemFactory
625 * @n_entries: the length of @entries
626 * @entries: an array of #GtkItemFactoryEntry<!-- -->s whose @callback members
627 * must by of type #GtkItemFactoryCallback1
628 * @callback_data: data passed to the callback functions of all entries
630 * Creates the menu items from the @entries.
633 gtk_item_factory_create_items (GtkItemFactory *ifactory,
635 GtkItemFactoryEntry *entries,
636 gpointer callback_data)
638 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
642 * gtk_item_factory_create_items_ac:
643 * @ifactory: a #GtkItemFactory
644 * @n_entries: the length of @entries
645 * @entries: an array of #GtkItemFactoryEntry<!-- -->s
646 * @callback_data: data passed to the callback functions of all entries
647 * @callback_type: 1 if the callback functions in @entries are of type
648 * #GtkItemFactoryCallback1, 2 if they are of type #GtkItemFactoryCallback2
650 * Creates the menu items from the @entries.
653 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
655 GtkItemFactoryEntry *entries,
656 gpointer callback_data,
661 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
662 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
667 g_return_if_fail (entries != NULL);
669 for (i = 0; i < n_entries; i++)
670 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
674 * gtk_item_factory_get_widget:
675 * @ifactory: a #GtkItemFactory
676 * @path: the path to the widget
677 * @returns: the widget for the given path, or %NULL if @path doesn't lead
680 * Obtains the widget which corresponds to @path.
682 * If the widget corresponding to @path is a menu item which opens a
683 * submenu, then the submenu is returned. If you are interested in the menu
684 * item, use gtk_item_factory_get_item() instead.
687 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
690 GtkItemFactoryClass *class;
691 GtkItemFactoryItem *item;
693 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
694 g_return_val_if_fail (path != NULL, NULL);
696 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
699 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
704 fpath = g_strconcat (ifactory->path, path, NULL);
705 item = g_hash_table_lookup (class->item_ht, fpath);
713 for (slist = item->widgets; slist; slist = slist->next)
715 if (gtk_item_factory_from_widget (slist->data) == ifactory)
724 * gtk_item_factory_get_widget_by_action:
725 * @ifactory: a #GtkItemFactory
726 * @action: an action as specified in the @callback_action field
727 * of #GtkItemFactoryEntry
728 * @returns: the widget which corresponds to the given action, or %NULL
729 * if no widget was found
731 * Obtains the widget which was constructed from the #GtkItemFactoryEntry
732 * with the given @action.
734 * If there are multiple items with the same action, the result is
738 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
743 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
745 for (slist = ifactory->items; slist; slist = slist->next)
747 GtkItemFactoryItem *item = slist->data;
750 for (link = item->widgets; link; link = link->next)
751 if (g_object_get_qdata (link->data, quark_item_factory) == ifactory &&
752 g_object_get_qdata (link->data, quark_action) == GUINT_TO_POINTER (action))
760 * gtk_item_factory_get_item:
761 * @ifactory: a #GtkItemFactory
762 * @path: the path to the menu item
763 * @returns: the menu item for the given path, or %NULL if @path doesn't
764 * lead to a menu item
766 * Obtains the menu item which corresponds to @path.
768 * If the widget corresponding to @path is a menu item which opens a
769 * submenu, then the item is returned. If you are interested in the submenu,
770 * use gtk_item_factory_get_widget() instead.
773 gtk_item_factory_get_item (GtkItemFactory *ifactory,
778 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
779 g_return_val_if_fail (path != NULL, NULL);
781 widget = gtk_item_factory_get_widget (ifactory, path);
783 if (GTK_IS_MENU (widget))
784 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
786 return GTK_IS_ITEM (widget) ? widget : NULL;
791 * gtk_item_factory_get_item_by_action:
792 * @ifactory: a #GtkItemFactory
793 * @action: an action as specified in the @callback_action field
794 * of #GtkItemFactoryEntry
795 * @returns: the menu item which corresponds to the given action, or %NULL
796 * if no menu item was found
798 * Obtains the menu item which was constructed from the first
799 * #GtkItemFactoryEntry with the given @action.
802 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
807 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
809 widget = gtk_item_factory_get_widget_by_action (ifactory, action);
811 if (GTK_IS_MENU (widget))
812 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
814 return GTK_IS_ITEM (widget) ? widget : NULL;
818 item_factory_find_separator_r (char *path)
820 gchar *result = NULL;
821 gboolean escaped = FALSE;
831 else if (*path == '/')
842 item_factory_unescape_label (const char *label)
844 char *new = g_malloc (strlen (label) + 1);
846 gboolean escaped = FALSE;
872 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
881 *path = g_strdup (str);
902 *parent_path = g_strdup (*path);
903 p = item_factory_find_separator_r (*parent_path);
906 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
911 if (ifactory->translate_func)
912 translation = ifactory->translate_func (str, ifactory->translate_data);
916 p = item_factory_find_separator_r (translation);
922 *item = item_factory_unescape_label (p);
928 * gtk_item_factory_create_item:
929 * @ifactory: a #GtkItemFactory
930 * @entry: the #GtkItemFactoryEntry to create an item for
931 * @callback_data: data passed to the callback function of @entry
932 * @callback_type: 1 if the callback function of @entry is of type
933 * #GtkItemFactoryCallback1, 2 if it is of type #GtkItemFactoryCallback2
935 * Creates an item for @entry.
938 gtk_item_factory_create_item (GtkItemFactory *ifactory,
939 GtkItemFactoryEntry *entry,
940 gpointer callback_data,
943 GtkOptionMenu *option_menu = NULL;
954 gchar *item_type_path;
955 GtkStockItem stock_item;
957 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
958 g_return_if_fail (entry != NULL);
959 g_return_if_fail (entry->path != NULL);
960 g_return_if_fail (entry->path[0] == '/');
961 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
963 if (!entry->item_type ||
964 entry->item_type[0] == 0)
966 item_type_path = "<Item>";
967 type_id = quark_type_item;
971 item_type_path = entry->item_type;
972 type_id = g_quark_try_string (item_type_path);
976 if (type_id == quark_type_item)
977 type = GTK_TYPE_MENU_ITEM;
978 else if (type_id == quark_type_title)
979 type = GTK_TYPE_MENU_ITEM;
980 else if (type_id == quark_type_radio_item)
981 type = GTK_TYPE_RADIO_MENU_ITEM;
982 else if (type_id == quark_type_check_item)
983 type = GTK_TYPE_CHECK_MENU_ITEM;
984 else if (type_id == quark_type_image_item)
985 type = GTK_TYPE_IMAGE_MENU_ITEM;
986 else if (type_id == quark_type_stock_item)
987 type = GTK_TYPE_IMAGE_MENU_ITEM;
988 else if (type_id == quark_type_tearoff_item)
989 type = GTK_TYPE_TEAROFF_MENU_ITEM;
990 else if (type_id == quark_type_toggle_item)
991 type = GTK_TYPE_CHECK_MENU_ITEM;
992 else if (type_id == quark_type_separator_item)
993 type = GTK_TYPE_MENU_ITEM;
994 else if (type_id == quark_type_branch)
995 type = GTK_TYPE_MENU_ITEM;
996 else if (type_id == quark_type_last_branch)
997 type = GTK_TYPE_MENU_ITEM;
1000 GtkWidget *radio_link;
1002 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
1003 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
1005 type = GTK_TYPE_RADIO_MENU_ITEM;
1006 radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radio_link));
1010 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1017 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1018 &path, &parent_path, &name))
1021 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1024 GtkItemFactoryEntry pentry;
1027 ppath = g_strdup (entry->path);
1028 p = item_factory_find_separator_r (ppath);
1029 g_return_if_fail (p != NULL);
1031 pentry.path = ppath;
1032 pentry.accelerator = NULL;
1033 pentry.callback = NULL;
1034 pentry.callback_action = 0;
1035 pentry.item_type = "<Branch>";
1037 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1040 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1041 g_return_if_fail (parent != NULL);
1044 if (GTK_IS_OPTION_MENU (parent))
1046 option_menu = GTK_OPTION_MENU (parent);
1047 if (!option_menu->menu)
1049 GtkWidget *menu = g_object_new (GTK_TYPE_MENU, NULL);
1050 gchar *p = g_strconcat (ifactory->path, parent_path, NULL);
1052 gtk_menu_set_accel_path (GTK_MENU (menu), p);
1054 gtk_option_menu_set_menu (option_menu, menu);
1056 parent = option_menu->menu;
1058 g_free (parent_path);
1060 g_return_if_fail (GTK_IS_CONTAINER (parent));
1062 accelerator = entry->accelerator;
1064 widget = gtk_widget_new (type,
1066 "sensitive", (type_id != quark_type_separator_item &&
1067 type_id != quark_type_title),
1070 if (option_menu && !option_menu->menu_item)
1071 gtk_option_menu_set_history (option_menu, 0);
1073 if (GTK_IS_RADIO_MENU_ITEM (widget))
1074 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1075 if (type_id == quark_type_image_item)
1077 GError *error = NULL;
1078 GdkPixbuf *pixbuf = NULL;
1081 pixbuf = gdk_pixbuf_new_from_inline (-1,
1086 image = gtk_image_new_from_pixbuf (pixbuf);
1089 g_warning ("Error loading menu image: %s", error->message);
1090 g_error_free (error);
1095 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1096 gtk_widget_show (image);
1099 g_object_unref (pixbuf);
1101 if (type_id == quark_type_stock_item)
1103 image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1104 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1105 gtk_widget_show (image);
1107 if (gtk_stock_lookup (entry->extra_data, &stock_item))
1110 accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1114 /* install underline accelerators for this item
1116 if (type_id != quark_type_separator_item &&
1117 type_id != quark_type_tearoff_item &&
1122 label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1125 "accel_widget", widget,
1128 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1133 if (type_id == quark_type_branch ||
1134 type_id == quark_type_last_branch)
1138 if (entry->callback)
1139 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1141 if (type_id == quark_type_last_branch)
1142 gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE);
1145 widget = gtk_widget_new (GTK_TYPE_MENU, NULL);
1146 p = g_strconcat (ifactory->path, path, NULL);
1147 gtk_menu_set_accel_path (GTK_MENU (widget), p);
1150 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1153 gtk_item_factory_add_item (ifactory,
1155 (type_id == quark_type_branch ||
1156 type_id == quark_type_last_branch) ?
1157 (GtkItemFactoryCallback) NULL : entry->callback,
1158 entry->callback_action, callback_data,
1162 if (accelerator != entry->accelerator)
1163 g_free (accelerator);
1168 * gtk_item_factory_create_menu_entries:
1169 * @n_entries: the length of @entries
1170 * @entries: an array of #GtkMenuEntry<!-- -->s
1172 * Creates the menu items from the @entries.
1175 gtk_item_factory_create_menu_entries (guint n_entries,
1176 GtkMenuEntry *entries)
1178 static GPatternSpec *pspec_separator = NULL;
1179 static GPatternSpec *pspec_check = NULL;
1184 g_return_if_fail (entries != NULL);
1186 if (!pspec_separator)
1188 pspec_separator = g_pattern_spec_new ("*<separator>*");
1189 pspec_check = g_pattern_spec_new ("*<check>*");
1192 for (i = 0; i < n_entries; i++)
1194 GtkItemFactory *ifactory;
1195 GtkItemFactoryEntry entry;
1199 path = entries[i].path;
1200 ifactory = gtk_item_factory_from_path (path);
1203 g_warning ("gtk_item_factory_create_menu_entries(): "
1204 "entry[%u] refers to unknown item factory: \"%s\"",
1205 i, entries[i].path);
1209 while (*path != '>')
1215 entry.accelerator = entries[i].accelerator;
1216 entry.callback = entries[i].callback;
1217 entry.callback_action = 0;
1218 if (g_pattern_match_string (pspec_separator, path))
1219 entry.item_type = "<Separator>";
1220 else if (!g_pattern_match_string (pspec_check, path))
1221 entry.item_type = NULL;
1224 gboolean in_brace = FALSE;
1227 cpath = g_new (gchar, strlen (path));
1233 else if (*path == '>')
1240 entry.item_type = "<ToggleItem>";
1244 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1245 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1251 * gtk_item_factories_path_delete:
1252 * @ifactory_path: a factory path to prepend to @path. May be %NULL if @path
1253 * starts with a factory path
1256 * Deletes all widgets constructed from the specified path.
1259 gtk_item_factories_path_delete (const gchar *ifactory_path,
1262 GtkItemFactoryClass *class;
1263 GtkItemFactoryItem *item;
1265 g_return_if_fail (path != NULL);
1267 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1270 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1275 g_return_if_fail (ifactory_path != NULL);
1277 fpath = g_strconcat (ifactory_path, path, NULL);
1278 item = g_hash_table_lookup (class->item_ht, fpath);
1284 GSList *widget_list;
1288 for (slist = item->widgets; slist; slist = slist->next)
1292 widget = slist->data;
1293 widget_list = g_slist_prepend (widget_list, widget);
1294 g_object_ref (widget);
1297 for (slist = widget_list; slist; slist = slist->next)
1301 widget = slist->data;
1302 gtk_widget_destroy (widget);
1303 g_object_unref (widget);
1305 g_slist_free (widget_list);
1310 * gtk_item_factory_delete_item:
1311 * @ifactory: a #GtkItemFactory
1314 * Deletes the menu item which was created for @path by the given
1318 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1321 GtkItemFactoryClass *class;
1324 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1325 g_return_if_fail (path != NULL);
1327 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
1329 widget = gtk_item_factory_get_widget (ifactory, path);
1333 if (GTK_IS_MENU (widget))
1334 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1336 gtk_widget_destroy (widget);
1341 * gtk_item_factory_delete_entry:
1342 * @ifactory: a #GtkItemFactory
1343 * @entry: a #GtkItemFactoryEntry
1345 * Deletes the menu item which was created from @entry by the given
1349 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1350 GtkItemFactoryEntry *entry)
1356 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1357 g_return_if_fail (entry != NULL);
1358 g_return_if_fail (entry->path != NULL);
1359 g_return_if_fail (entry->path[0] == '/');
1361 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1362 &path, &parent_path, &name))
1365 gtk_item_factory_delete_item (ifactory, path);
1368 g_free (parent_path);
1373 * gtk_item_factory_delete_entries:
1374 * @ifactory: a #GtkItemFactory
1375 * @n_entries: the length of @entries
1376 * @entries: an array of #GtkItemFactoryEntry<!-- -->s
1378 * Deletes the menu items which were created from the @entries by the given
1382 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1384 GtkItemFactoryEntry *entries)
1388 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1390 g_return_if_fail (entries != NULL);
1392 for (i = 0; i < n_entries; i++)
1393 gtk_item_factory_delete_entry (ifactory, entries + i);
1403 gtk_item_factory_menu_pos (GtkMenu *menu,
1409 MenuPos *mpos = func_data;
1416 * gtk_item_factory_popup_data_from_widget:
1418 * @returns: @popup_data associated with the item factory from
1419 * which @widget was created, or %NULL if @widget wasn't created
1420 * by an item factory
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_from_widget (GtkWidget *widget)
1429 GtkItemFactory *ifactory;
1431 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1433 ifactory = gtk_item_factory_from_widget (widget);
1435 return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1441 * gtk_item_factory_popup_data:
1442 * @ifactory: a #GtkItemFactory
1443 * @returns: @popup_data associated with @ifactory
1445 * Obtains the @popup_data which was passed to
1446 * gtk_item_factory_popup_with_data(). This data is available until the menu
1447 * is popped down again.
1450 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1452 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1454 return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1458 ifactory_delete_popup_data (GtkObject *object,
1459 GtkItemFactory *ifactory)
1461 g_signal_handlers_disconnect_by_func (object,
1462 ifactory_delete_popup_data,
1464 g_object_set_qdata (G_OBJECT (ifactory), quark_popup_data, NULL);
1468 * gtk_item_factory_popup:
1469 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1470 * @x: the x position
1471 * @y: the y position
1472 * @mouse_button: the mouse button which was pressed to initiate the popup
1473 * @time_: the time at which the activation event occurred
1475 * Pops up the menu constructed from the item factory at (@x, @y).
1477 * The @mouse_button parameter should be the mouse button pressed to initiate
1478 * the menu popup. If the menu popup was initiated by something other than
1479 * a mouse button press, such as a mouse button release or a keypress,
1480 * @mouse_button should be 0.
1482 * The @time_ parameter should be the time stamp of the event that
1483 * initiated the popup. If such an event is not available, use
1484 * gtk_get_current_event_time() instead.
1486 * The operation of the @mouse_button and the @time_ parameter is the same
1487 * as the @button and @activation_time parameters for gtk_menu_popup().
1490 gtk_item_factory_popup (GtkItemFactory *ifactory,
1496 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1500 * gtk_item_factory_popup_with_data:
1501 * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1502 * @popup_data: data available for callbacks while the menu is posted
1503 * @destroy: a #GtkDestroyNotify function to be called on @popup_data when
1504 * the menu is unposted
1505 * @x: the x position
1506 * @y: the y position
1507 * @mouse_button: the mouse button which was pressed to initiate the popup
1508 * @time_: the time at which the activation event occurred
1510 * Pops up the menu constructed from the item factory at (@x, @y). Callbacks
1511 * can access the @popup_data while the menu is posted via
1512 * gtk_item_factory_popup_data() and gtk_item_factory_popup_data_from_widget().
1514 * The @mouse_button parameter should be the mouse button pressed to initiate
1515 * the menu popup. If the menu popup was initiated by something other than
1516 * a mouse button press, such as a mouse button release or a keypress,
1517 * @mouse_button should be 0.
1519 * The @time_ parameter should be the time stamp of the event that
1520 * initiated the popup. If such an event is not available, use
1521 * gtk_get_current_event_time() instead.
1523 * The operation of the @mouse_button and the @time_ parameters is the same
1524 * as the @button and @activation_time parameters for gtk_menu_popup().
1527 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1528 gpointer popup_data,
1529 GtkDestroyNotify destroy,
1537 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1538 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1540 mpos = g_object_get_qdata (G_OBJECT (ifactory->widget), quark_if_menu_pos);
1544 mpos = g_new0 (MenuPos, 1);
1545 g_object_set_qdata_full (G_OBJECT (ifactory->widget),
1554 if (popup_data != NULL)
1556 g_object_set_qdata_full (G_OBJECT (ifactory),
1560 g_signal_connect (ifactory->widget,
1562 G_CALLBACK (ifactory_delete_popup_data),
1566 gtk_menu_popup (GTK_MENU (ifactory->widget),
1568 gtk_item_factory_menu_pos, mpos,
1569 mouse_button, time);
1573 * gtk_item_factory_set_translate_func:
1574 * @ifactory: a #GtkItemFactory
1575 * @func: the #GtkTranslateFunc function to be used to translate path elements
1576 * @data: data to pass to @func and @notify
1577 * @notify: a #GtkDestroyNotify function to be called when @ifactory is
1578 * destroyed and when the translation function is changed again
1580 * Sets a function to be used for translating the path elements before they
1584 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1585 GtkTranslateFunc func,
1587 GtkDestroyNotify notify)
1589 g_return_if_fail (ifactory != NULL);
1591 if (ifactory->translate_notify)
1592 ifactory->translate_notify (ifactory->translate_data);
1594 ifactory->translate_func = func;
1595 ifactory->translate_data = data;
1596 ifactory->translate_notify = notify;