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/gtkaccellabel.h"
43 #include "gdk/gdkkeysyms.h"
44 #include "gtk/gtkimage.h"
45 #include "gtk/gtkstock.h"
46 #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 GtkPrintFunc print_func;
83 guint modified_only : 1;
88 /* --- prototypes --- */
89 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
90 static void gtk_item_factory_init (GtkItemFactory *ifactory);
91 static void gtk_item_factory_destroy (GtkObject *object);
92 static void gtk_item_factory_finalize (GObject *object);
95 /* --- static variables --- */
96 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
97 static gpointer parent_class = NULL;
98 static const gchar *item_factory_string = "Gtk-<ItemFactory>";
99 static GMemChunk *ifactory_item_chunks = NULL;
100 static GMemChunk *ifactory_cb_data_chunks = NULL;
101 static GQuark quark_popup_data = 0;
102 static GQuark quark_if_menu_pos = 0;
103 static GQuark quark_item_factory = 0;
104 static GQuark quark_item_path = 0;
105 static GQuark quark_action = 0;
106 static GQuark quark_accel_group = 0;
107 static GQuark quark_type_item = 0;
108 static GQuark quark_type_title = 0;
109 static GQuark quark_type_radio_item = 0;
110 static GQuark quark_type_check_item = 0;
111 static GQuark quark_type_toggle_item = 0;
112 static GQuark quark_type_image_item = 0;
113 static GQuark quark_type_stock_item = 0;
114 static GQuark quark_type_tearoff_item = 0;
115 static GQuark quark_type_separator_item = 0;
116 static GQuark quark_type_branch = 0;
117 static GQuark quark_type_last_branch = 0;
118 static GScannerConfig ifactory_scanner_config =
122 ) /* cset_skip_characters */,
127 ) /* cset_identifier_first */,
134 ) /* cset_identifier_nth */,
135 ( ";\n" ) /* cpair_comment_single */,
137 FALSE /* case_sensitive */,
139 TRUE /* skip_comment_multi */,
140 TRUE /* skip_comment_single */,
141 FALSE /* scan_comment_multi */,
142 TRUE /* scan_identifier */,
143 FALSE /* scan_identifier_1char */,
144 FALSE /* scan_identifier_NULL */,
145 TRUE /* scan_symbols */,
146 TRUE /* scan_binary */,
147 TRUE /* scan_octal */,
148 TRUE /* scan_float */,
150 FALSE /* scan_hex_dollar */,
151 TRUE /* scan_string_sq */,
152 TRUE /* scan_string_dq */,
153 TRUE /* numbers_2_int */,
154 FALSE /* int_2_float */,
155 FALSE /* identifier_2_string */,
156 TRUE /* char_2_token */,
157 FALSE /* symbol_2_token */,
161 /* --- functions --- */
163 gtk_item_factory_get_type (void)
165 static GtkType item_factory_type = 0;
167 if (!item_factory_type)
169 static const GtkTypeInfo item_factory_info =
172 sizeof (GtkItemFactory),
173 sizeof (GtkItemFactoryClass),
174 (GtkClassInitFunc) gtk_item_factory_class_init,
175 (GtkObjectInitFunc) gtk_item_factory_init,
176 /* reserved_1 */ NULL,
177 /* reserved_2 */ NULL,
178 (GtkClassInitFunc) NULL,
181 item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
184 return item_factory_type;
188 gtk_item_factory_class_init (GtkItemFactoryClass *class)
190 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
191 GtkObjectClass *object_class;
193 gtk_item_factory_class = class;
195 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
197 object_class = (GtkObjectClass*) class;
199 gobject_class->finalize = gtk_item_factory_finalize;
201 object_class->destroy = gtk_item_factory_destroy;
203 class->cpair_comment_single = g_strdup (";\n");
205 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
207 ifactory_item_chunks =
208 g_mem_chunk_new ("GtkItemFactoryItem",
209 sizeof (GtkItemFactoryItem),
210 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
212 ifactory_cb_data_chunks =
213 g_mem_chunk_new ("GtkIFCBData",
214 sizeof (GtkIFCBData),
215 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
218 quark_popup_data = g_quark_from_static_string ("GtkItemFactory-popup-data");
219 quark_if_menu_pos = g_quark_from_static_string ("GtkItemFactory-menu-position");
220 quark_item_factory = g_quark_from_static_string ("GtkItemFactory");
221 quark_item_path = g_quark_from_static_string ("GtkItemFactory-path");
222 quark_action = g_quark_from_static_string ("GtkItemFactory-action");
223 quark_accel_group = g_quark_from_static_string ("GtkAccelGroup");
224 quark_type_item = g_quark_from_static_string ("<Item>");
225 quark_type_title = g_quark_from_static_string ("<Title>");
226 quark_type_radio_item = g_quark_from_static_string ("<RadioItem>");
227 quark_type_check_item = g_quark_from_static_string ("<CheckItem>");
228 quark_type_toggle_item = g_quark_from_static_string ("<ToggleItem>");
229 quark_type_image_item = g_quark_from_static_string ("<ImageItem>");
230 quark_type_stock_item = g_quark_from_static_string ("<StockItem>");
231 quark_type_tearoff_item = g_quark_from_static_string ("<Tearoff>");
232 quark_type_separator_item = g_quark_from_static_string ("<Separator>");
233 quark_type_branch = g_quark_from_static_string ("<Branch>");
234 quark_type_last_branch = g_quark_from_static_string ("<LastBranch>");
238 gtk_item_factory_init (GtkItemFactory *ifactory)
242 object = GTK_OBJECT (ifactory);
244 ifactory->path = NULL;
245 ifactory->accel_group = NULL;
246 ifactory->widget = NULL;
247 ifactory->items = NULL;
248 ifactory->translate_func = NULL;
249 ifactory->translate_data = NULL;
250 ifactory->translate_notify = NULL;
254 gtk_item_factory_new (GtkType container_type,
256 GtkAccelGroup *accel_group)
258 GtkItemFactory *ifactory;
260 g_return_val_if_fail (path != NULL, NULL);
262 ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
263 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
269 gtk_item_factory_callback_marshal (GtkWidget *widget,
276 if (data->callback_type == 1)
278 GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
279 func1 (data->func_data, data->callback_action, widget);
281 else if (data->callback_type == 2)
283 GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
284 func2 (widget, data->func_data, data->callback_action);
289 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
295 if (item->in_propagation)
298 item->in_propagation = TRUE;
301 for (slist = item->widgets; slist; slist = slist->next)
305 widget = slist->data;
307 if (widget != exclude)
309 gtk_widget_ref (widget);
310 widget_list = g_slist_prepend (widget_list, widget);
314 for (slist = widget_list; slist; slist = slist->next)
317 GtkAccelGroup *accel_group;
320 widget = slist->data;
322 accel_group = gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_accel_group);
324 signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
325 if (signal_id && accel_group)
327 if (item->accelerator_key)
328 gtk_widget_add_accelerator (widget,
331 item->accelerator_key,
332 item->accelerator_mods,
338 work = gtk_accel_group_entries_from_object (GTK_OBJECT (widget));
341 GtkAccelEntry *ac_entry;
343 ac_entry = work->data;
345 if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
346 ac_entry->accel_group == accel_group &&
347 ac_entry->signal_id == signal_id)
348 gtk_widget_remove_accelerator (GTK_WIDGET (widget),
349 ac_entry->accel_group,
350 ac_entry->accelerator_key,
351 ac_entry->accelerator_mods);
356 gtk_widget_unref (widget);
359 g_slist_free (widget_list);
361 item->in_propagation = FALSE;
365 gtk_item_factory_item_add_accelerator (GtkWidget *widget,
366 guint accel_signal_id,
367 GtkAccelGroup *accel_group,
370 GtkAccelFlags accel_flags,
371 GtkItemFactoryItem *item)
373 if (!item->in_propagation &&
374 g_slist_find (item->widgets, widget) &&
375 accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
377 item->accelerator_key = accel_key;
378 item->accelerator_mods = accel_mods;
379 item->modified = TRUE;
381 gtk_item_factory_propagate_accelerator (item, widget);
388 gtk_item_factory_item_remove_accelerator (GtkWidget *widget,
389 GtkAccelGroup *accel_group,
392 GtkItemFactoryItem *item)
394 if (!item->in_propagation &&
395 g_slist_find (item->widgets, widget) &&
396 item->accelerator_key == accel_key &&
397 item->accelerator_mods == accel_mods)
399 item->accelerator_key = 0;
400 item->accelerator_mods = 0;
401 item->modified = TRUE;
403 gtk_item_factory_propagate_accelerator (item, widget);
408 gtk_item_factory_item_remove_widget (GtkWidget *widget,
409 GtkItemFactoryItem *item)
411 item->widgets = g_slist_remove (item->widgets, widget);
412 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
413 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_path);
417 gtk_item_factory_add_foreign (GtkWidget *accel_widget,
418 const gchar *full_path,
419 GtkAccelGroup *accel_group,
421 GdkModifierType modifiers)
423 GtkItemFactoryClass *class;
424 GtkItemFactoryItem *item;
426 g_return_if_fail (GTK_IS_WIDGET (accel_widget));
427 g_return_if_fail (full_path != NULL);
429 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
431 keyval = keyval != GDK_VoidSymbol ? keyval : 0;
433 item = g_hash_table_lookup (class->item_ht, full_path);
436 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
438 item->path = g_strdup (full_path);
439 item->accelerator_key = keyval;
440 item->accelerator_mods = modifiers;
441 item->modified = FALSE;
442 item->in_propagation = FALSE;
444 item->widgets = NULL;
446 g_hash_table_insert (class->item_ht, item->path, item);
449 item->widgets = g_slist_prepend (item->widgets, accel_widget);
450 gtk_signal_connect (GTK_OBJECT (accel_widget),
452 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
455 /* set the item path for the widget
457 gtk_object_set_data_by_id (GTK_OBJECT (accel_widget), quark_item_path, item->path);
458 gtk_widget_set_name (accel_widget, item->path);
461 gtk_accel_group_ref (accel_group);
462 gtk_object_set_data_by_id_full (GTK_OBJECT (accel_widget),
465 (GtkDestroyNotify) gtk_accel_group_unref);
468 gtk_object_set_data_by_id (GTK_OBJECT (accel_widget), quark_accel_group, NULL);
470 /* install defined accelerators
472 if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (accel_widget)))
474 if (item->accelerator_key && accel_group)
475 gtk_widget_add_accelerator (accel_widget,
478 item->accelerator_key,
479 item->accelerator_mods,
482 gtk_widget_remove_accelerators (accel_widget,
487 /* keep track of accelerator changes
489 gtk_signal_connect_after (GTK_OBJECT (accel_widget),
491 GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
493 gtk_signal_connect_after (GTK_OBJECT (accel_widget),
494 "remove-accelerator",
495 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
500 ifactory_cb_data_free (gpointer mem)
502 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
506 gtk_item_factory_add_item (GtkItemFactory *ifactory,
508 const gchar *accelerator,
509 GtkItemFactoryCallback callback,
510 guint callback_action,
511 gpointer callback_data,
516 GtkItemFactoryClass *class;
517 GtkItemFactoryItem *item;
521 g_return_if_fail (widget != NULL);
522 g_return_if_fail (item_type != NULL);
524 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
526 /* set accelerator group on menu widgets
528 if (GTK_IS_MENU (widget))
529 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
531 /* connect callback if neccessary
537 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
538 data->func = callback;
539 data->callback_type = callback_type;
540 data->func_data = callback_data;
541 data->callback_action = callback_action;
543 gtk_object_weakref (GTK_OBJECT (widget),
544 ifactory_cb_data_free,
546 gtk_signal_connect (GTK_OBJECT (widget),
548 GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
552 /* link the widget into its item-entry
553 * and keep back pointer on both the item factory and the widget
555 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
556 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
558 gtk_accelerator_parse (accelerator, &keyval, &mods);
564 fpath = g_strconcat (ifactory->path, path, NULL);
565 gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
566 item = g_hash_table_lookup (class->item_ht, fpath);
569 g_return_if_fail (item != NULL);
571 if (!g_slist_find (ifactory->items, item))
572 ifactory->items = g_slist_prepend (ifactory->items, item);
576 gtk_item_factory_construct (GtkItemFactory *ifactory,
577 GtkType container_type,
579 GtkAccelGroup *accel_group)
583 g_return_if_fail (ifactory != NULL);
584 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
585 g_return_if_fail (ifactory->accel_group == NULL);
586 g_return_if_fail (path != NULL);
587 if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
588 g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
592 if (path[0] != '<' && path[len - 1] != '>')
594 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
600 ifactory->accel_group = accel_group;
601 gtk_accel_group_ref (ifactory->accel_group);
604 ifactory->accel_group = gtk_accel_group_new ();
606 ifactory->path = g_strdup (path);
607 ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
608 "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
610 gtk_object_ref (GTK_OBJECT (ifactory));
611 gtk_object_sink (GTK_OBJECT (ifactory));
613 gtk_item_factory_add_item (ifactory,
621 gtk_item_factory_from_path (const gchar *path)
623 GtkItemFactoryClass *class;
624 GtkItemFactoryItem *item;
628 g_return_val_if_fail (path != NULL, NULL);
629 g_return_val_if_fail (path[0] == '<', NULL);
631 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
634 while (path[i] && path[i] != '>')
638 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
642 fname = g_new (gchar, i + 2);
643 g_memmove (fname, path, i + 1);
646 item = g_hash_table_lookup (class->item_ht, fname);
650 if (item && item->widgets)
651 return gtk_item_factory_from_widget (item->widgets->data);
657 gtk_item_factory_destroy (GtkObject *object)
659 GtkItemFactory *ifactory;
662 g_return_if_fail (object != NULL);
663 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
665 ifactory = (GtkItemFactory*) object;
667 if (ifactory->widget)
671 dobj = GTK_OBJECT (ifactory->widget);
673 gtk_object_ref (dobj);
674 gtk_object_sink (dobj);
675 gtk_object_destroy (dobj);
676 gtk_object_unref (dobj);
678 ifactory->widget = NULL;
681 for (slist = ifactory->items; slist; slist = slist->next)
683 GtkItemFactoryItem *item = slist->data;
686 for (link = item->widgets; link; link = link->next)
687 if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory)
688 gtk_object_remove_data_by_id (link->data, quark_item_factory);
690 g_slist_free (ifactory->items);
691 ifactory->items = NULL;
693 GTK_OBJECT_CLASS (parent_class)->destroy (object);
697 gtk_item_factory_finalize (GObject *object)
699 GtkItemFactory *ifactory;
701 g_return_if_fail (object != NULL);
702 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
704 ifactory = GTK_ITEM_FACTORY (object);
706 gtk_accel_group_unref (ifactory->accel_group);
707 g_free (ifactory->path);
708 g_assert (ifactory->widget == NULL);
710 if (ifactory->translate_notify)
711 ifactory->translate_notify (ifactory->translate_data);
713 G_OBJECT_CLASS (parent_class)->finalize (object);
717 gtk_item_factory_from_widget (GtkWidget *widget)
719 g_return_val_if_fail (widget != NULL, NULL);
720 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
722 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
726 gtk_item_factory_path_from_widget (GtkWidget *widget)
728 g_return_val_if_fail (widget != NULL, NULL);
729 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
731 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_path);
735 item_factory_escape_path (const gchar *path)
737 GString *str = g_string_new (NULL);
746 g_string_append (str, "\\n");
749 g_string_append (str, "\\r");
753 g_string_append_c (str, '\\');
756 g_string_append_c (str, c);
762 return g_string_free (str, FALSE);
766 gtk_item_factory_foreach (gpointer hash_key,
770 GtkItemFactoryItem *item;
775 gchar comment_prefix[2] = "\000\000";
780 if (data->pspec && !g_pattern_match_string (data->pspec, item->path))
783 comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
785 path = item_factory_escape_path (hash_key);
786 name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
787 string = g_strconcat (item->modified ? "" : comment_prefix,
797 data->print_func (data->func_data, string);
803 gtk_item_factory_dump_items (GPatternSpec *path_pspec,
804 gboolean modified_only,
805 GtkPrintFunc print_func,
810 g_return_if_fail (print_func != NULL);
812 if (!gtk_item_factory_class)
813 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
815 data.print_func = print_func;
816 data.func_data = func_data;
817 data.modified_only = (modified_only != FALSE);
818 data.pspec = path_pspec;
820 g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
824 gtk_item_factory_print_func (gpointer FILE_pointer,
827 FILE *f_out = FILE_pointer;
829 g_return_if_fail (FILE_pointer != NULL);
830 g_return_if_fail (string != NULL);
832 fputs (string, f_out);
837 gtk_item_factory_dump_rc (const gchar *file_name,
838 GPatternSpec *path_pspec,
839 gboolean modified_only)
843 g_return_if_fail (file_name != NULL);
845 f_out = fopen (file_name, "w");
850 if (g_get_prgname ())
851 fputs (g_get_prgname (), f_out);
852 fputs (" GtkItemFactory rc-file -*- scheme -*-\n", f_out);
853 fputs ("; this file is an automated menu-path dump\n", f_out);
854 fputs (";\n", f_out);
856 gtk_item_factory_dump_items (path_pspec,
858 gtk_item_factory_print_func,
865 gtk_item_factory_create_items (GtkItemFactory *ifactory,
867 GtkItemFactoryEntry *entries,
868 gpointer callback_data)
870 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
874 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
876 GtkItemFactoryEntry *entries,
877 gpointer callback_data,
882 g_return_if_fail (ifactory != NULL);
883 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
884 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
889 g_return_if_fail (entries != NULL);
891 for (i = 0; i < n_entries; i++)
892 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
896 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
899 GtkItemFactoryClass *class;
900 GtkItemFactoryItem *item;
902 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
903 g_return_val_if_fail (path != NULL, NULL);
905 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
908 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
913 fpath = g_strconcat (ifactory->path, path, NULL);
914 item = g_hash_table_lookup (class->item_ht, fpath);
922 for (slist = item->widgets; slist; slist = slist->next)
924 if (gtk_item_factory_from_widget (slist->data) == ifactory)
933 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
938 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
940 for (slist = ifactory->items; slist; slist = slist->next)
942 GtkItemFactoryItem *item = slist->data;
945 for (link = item->widgets; link; link = link->next)
946 if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory &&
947 gtk_object_get_data_by_id (link->data, quark_action) == GUINT_TO_POINTER (action))
955 gtk_item_factory_get_item (GtkItemFactory *ifactory,
960 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
961 g_return_val_if_fail (path != NULL, NULL);
963 widget = gtk_item_factory_get_widget (ifactory, path);
965 if (GTK_IS_MENU (widget))
966 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
968 return GTK_IS_ITEM (widget) ? widget : NULL;
972 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
977 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
979 widget = gtk_item_factory_get_widget_by_action (ifactory, action);
981 if (GTK_IS_MENU (widget))
982 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
984 return GTK_IS_ITEM (widget) ? widget : NULL;
988 item_factory_find_separator_r (char *path)
990 gchar *result = NULL;
991 gboolean escaped = FALSE;
1001 else if (*path == '/')
1012 item_factory_unescape_label (const char *label)
1014 char *new = g_malloc (strlen (label) + 1);
1016 gboolean escaped = FALSE;
1042 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
1045 gchar **parent_path,
1051 *path = g_strdup (str);
1072 *parent_path = g_strdup (*path);
1073 p = item_factory_find_separator_r (*parent_path);
1076 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
1081 if (ifactory->translate_func)
1082 translation = ifactory->translate_func (str, ifactory->translate_data);
1086 p = item_factory_find_separator_r (translation);
1092 *item = item_factory_unescape_label (p);
1098 gtk_item_factory_create_item (GtkItemFactory *ifactory,
1099 GtkItemFactoryEntry *entry,
1100 gpointer callback_data,
1101 guint callback_type)
1103 GtkOptionMenu *option_menu = NULL;
1107 GSList *radio_group;
1114 gchar *item_type_path;
1115 GtkStockItem stock_item;
1117 g_return_if_fail (ifactory != NULL);
1118 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1119 g_return_if_fail (entry != NULL);
1120 g_return_if_fail (entry->path != NULL);
1121 g_return_if_fail (entry->path[0] == '/');
1122 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
1124 if (!entry->item_type ||
1125 entry->item_type[0] == 0)
1127 item_type_path = "<Item>";
1128 type_id = quark_type_item;
1132 item_type_path = entry->item_type;
1133 type_id = gtk_object_data_try_key (item_type_path);
1137 if (type_id == quark_type_item)
1138 type = GTK_TYPE_MENU_ITEM;
1139 else if (type_id == quark_type_title)
1140 type = GTK_TYPE_MENU_ITEM;
1141 else if (type_id == quark_type_radio_item)
1142 type = GTK_TYPE_RADIO_MENU_ITEM;
1143 else if (type_id == quark_type_check_item)
1144 type = GTK_TYPE_CHECK_MENU_ITEM;
1145 else if (type_id == quark_type_image_item)
1146 type = GTK_TYPE_IMAGE_MENU_ITEM;
1147 else if (type_id == quark_type_stock_item)
1148 type = GTK_TYPE_IMAGE_MENU_ITEM;
1149 else if (type_id == quark_type_tearoff_item)
1150 type = GTK_TYPE_TEAROFF_MENU_ITEM;
1151 else if (type_id == quark_type_toggle_item)
1152 type = GTK_TYPE_CHECK_MENU_ITEM;
1153 else if (type_id == quark_type_separator_item)
1154 type = GTK_TYPE_MENU_ITEM;
1155 else if (type_id == quark_type_branch)
1156 type = GTK_TYPE_MENU_ITEM;
1157 else if (type_id == quark_type_last_branch)
1158 type = GTK_TYPE_MENU_ITEM;
1161 GtkWidget *radio_link;
1163 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
1164 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
1166 type = GTK_TYPE_RADIO_MENU_ITEM;
1167 radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
1171 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1178 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1179 &path, &parent_path, &name))
1182 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1185 GtkItemFactoryEntry pentry;
1188 ppath = g_strdup (entry->path);
1189 p = item_factory_find_separator_r (ppath);
1190 g_return_if_fail (p != NULL);
1192 pentry.path = ppath;
1193 pentry.accelerator = NULL;
1194 pentry.callback = NULL;
1195 pentry.callback_action = 0;
1196 pentry.item_type = "<Branch>";
1198 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1201 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1202 g_return_if_fail (parent != NULL);
1204 g_free (parent_path);
1206 if (GTK_IS_OPTION_MENU (parent))
1208 option_menu = GTK_OPTION_MENU (parent);
1209 if (!option_menu->menu)
1210 gtk_option_menu_set_menu (option_menu, gtk_widget_new (GTK_TYPE_MENU, NULL));
1211 parent = option_menu->menu;
1214 g_return_if_fail (GTK_IS_CONTAINER (parent));
1216 accelerator = entry->accelerator;
1218 widget = gtk_widget_new (type,
1219 "GtkWidget::visible", TRUE,
1220 "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
1221 type_id != quark_type_title),
1222 "GtkWidget::parent", parent,
1224 if (option_menu && !option_menu->menu_item)
1225 gtk_option_menu_set_history (option_menu, 0);
1227 if (type == GTK_TYPE_RADIO_MENU_ITEM)
1228 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1229 if (GTK_IS_CHECK_MENU_ITEM (widget))
1230 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
1231 if (GTK_IS_IMAGE_MENU_ITEM (widget))
1233 GdkPixbuf *pixbuf = NULL;
1236 pixbuf = gdk_pixbuf_new_from_inline (entry->extra_data,
1242 image = gtk_image_new_from_pixbuf (pixbuf);
1245 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1248 g_object_unref (G_OBJECT (pixbuf));
1250 if (type_id == quark_type_stock_item)
1252 image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1254 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1256 if (gtk_stock_lookup (entry->extra_data, &stock_item))
1259 accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1265 /* install underline accelerators for this item
1267 if (type_id != quark_type_separator_item &&
1268 type_id != quark_type_tearoff_item &&
1273 label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1274 "GtkWidget::visible", TRUE,
1275 "GtkWidget::parent", widget,
1276 "GtkAccelLabel::accel_widget", widget,
1277 "GtkMisc::xalign", 0.0,
1280 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1285 if (type_id == quark_type_branch ||
1286 type_id == quark_type_last_branch)
1288 if (entry->callback)
1289 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1292 if (type_id == quark_type_last_branch)
1293 gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1296 widget = gtk_widget_new (GTK_TYPE_MENU,
1299 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1302 gtk_item_factory_add_item (ifactory,
1304 (type_id == quark_type_branch ||
1305 type_id == quark_type_last_branch) ?
1306 (GtkItemFactoryCallback) NULL : entry->callback,
1307 entry->callback_action, callback_data,
1312 if (accelerator != entry->accelerator)
1313 g_free (accelerator);
1319 gtk_item_factory_create_menu_entries (guint n_entries,
1320 GtkMenuEntry *entries)
1322 static GPatternSpec *pspec_separator = NULL;
1323 static GPatternSpec *pspec_check = NULL;
1328 g_return_if_fail (entries != NULL);
1330 if (!pspec_separator)
1332 pspec_separator = g_pattern_spec_new ("*<separator>*");
1333 pspec_check = g_pattern_spec_new ("*<check>*");
1336 for (i = 0; i < n_entries; i++)
1338 GtkItemFactory *ifactory;
1339 GtkItemFactoryEntry entry;
1343 path = entries[i].path;
1344 ifactory = gtk_item_factory_from_path (path);
1347 g_warning ("gtk_item_factory_create_menu_entries(): "
1348 "entry[%u] refers to unknown item factory: \"%s\"",
1349 i, entries[i].path);
1353 while (*path != '>')
1359 entry.accelerator = entries[i].accelerator;
1360 entry.callback = entries[i].callback;
1361 entry.callback_action = 0;
1362 if (g_pattern_match_string (pspec_separator, path))
1363 entry.item_type = "<Separator>";
1364 else if (!g_pattern_match_string (pspec_check, path))
1365 entry.item_type = NULL;
1368 gboolean in_brace = FALSE;
1371 cpath = g_new (gchar, strlen (path));
1377 else if (*path == '>')
1384 entry.item_type = "<ToggleItem>";
1388 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1389 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1395 gtk_item_factories_path_delete (const gchar *ifactory_path,
1398 GtkItemFactoryClass *class;
1399 GtkItemFactoryItem *item;
1401 g_return_if_fail (path != NULL);
1403 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1406 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1411 g_return_if_fail (ifactory_path != NULL);
1413 fpath = g_strconcat (ifactory_path, path, NULL);
1414 item = g_hash_table_lookup (class->item_ht, fpath);
1420 GSList *widget_list;
1424 for (slist = item->widgets; slist; slist = slist->next)
1428 widget = slist->data;
1429 widget_list = g_slist_prepend (widget_list, widget);
1430 gtk_widget_ref (widget);
1433 for (slist = widget_list; slist; slist = slist->next)
1437 widget = slist->data;
1438 gtk_widget_destroy (widget);
1439 gtk_widget_unref (widget);
1441 g_slist_free (widget_list);
1446 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1449 GtkItemFactoryClass *class;
1452 g_return_if_fail (ifactory != NULL);
1453 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1454 g_return_if_fail (path != NULL);
1456 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
1458 widget = gtk_item_factory_get_widget (ifactory, path);
1462 if (GTK_IS_MENU (widget))
1463 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1465 gtk_widget_destroy (widget);
1470 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1471 GtkItemFactoryEntry *entry)
1473 g_return_if_fail (ifactory != NULL);
1474 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1475 g_return_if_fail (entry != NULL);
1477 gtk_item_factory_delete_item (ifactory, entry->path);
1481 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1483 GtkItemFactoryEntry *entries)
1487 g_return_if_fail (ifactory != NULL);
1488 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1490 g_return_if_fail (entries != NULL);
1492 for (i = 0; i < n_entries; i++)
1493 gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1503 gtk_item_factory_menu_pos (GtkMenu *menu,
1509 MenuPos *mpos = func_data;
1516 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1518 GtkItemFactory *ifactory;
1520 g_return_val_if_fail (widget != NULL, NULL);
1521 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1523 ifactory = gtk_item_factory_from_widget (widget);
1525 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1531 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1533 g_return_val_if_fail (ifactory != NULL, NULL);
1534 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1536 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1540 ifactory_delete_popup_data (GtkObject *object,
1541 GtkItemFactory *ifactory)
1543 gtk_signal_disconnect_by_func (object,
1544 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1546 gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1550 gtk_item_factory_popup (GtkItemFactory *ifactory,
1556 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1560 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1561 gpointer popup_data,
1562 GtkDestroyNotify destroy,
1570 g_return_if_fail (ifactory != NULL);
1571 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1572 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1574 mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1578 mpos = g_new0 (MenuPos, 1);
1579 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1588 if (popup_data != NULL)
1590 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1594 gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1596 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1600 gtk_menu_popup (GTK_MENU (ifactory->widget),
1602 gtk_item_factory_menu_pos, mpos,
1603 mouse_button, time);
1607 gtk_item_factory_parse_menu_path (GScanner *scanner,
1608 GtkItemFactoryClass *class)
1610 GtkItemFactoryItem *item;
1612 g_scanner_get_next_token (scanner);
1613 if (scanner->token != G_TOKEN_STRING)
1614 return G_TOKEN_STRING;
1616 g_scanner_peek_next_token (scanner);
1617 if (scanner->next_token != G_TOKEN_STRING)
1619 g_scanner_get_next_token (scanner);
1620 return G_TOKEN_STRING;
1623 item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1626 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1628 item->path = g_strdup (scanner->value.v_string);
1629 item->accelerator_key = 0;
1630 item->accelerator_mods = 0;
1631 item->modified = TRUE;
1632 item->in_propagation = FALSE;
1634 item->widgets = NULL;
1636 g_hash_table_insert (class->item_ht, item->path, item);
1638 g_scanner_get_next_token (scanner);
1640 if (!item->in_propagation)
1645 old_keyval = item->accelerator_key;
1646 old_mods = item->accelerator_mods;
1647 gtk_accelerator_parse (scanner->value.v_string,
1648 &item->accelerator_key,
1649 &item->accelerator_mods);
1650 if (old_keyval != item->accelerator_key ||
1651 old_mods != item->accelerator_mods)
1653 item->modified = TRUE;
1654 gtk_item_factory_propagate_accelerator (item, NULL);
1658 g_scanner_get_next_token (scanner);
1659 if (scanner->token != ')')
1662 return G_TOKEN_NONE;
1666 gtk_item_factory_parse_statement (GScanner *scanner,
1667 GtkItemFactoryClass *class)
1669 guint expected_token;
1671 g_scanner_get_next_token (scanner);
1673 if (scanner->token == G_TOKEN_SYMBOL)
1675 guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1677 parser_func = scanner->value.v_symbol;
1679 /* check whether this is a GtkItemFactory symbol.
1681 if (parser_func == gtk_item_factory_parse_menu_path)
1682 expected_token = parser_func (scanner, class);
1684 expected_token = G_TOKEN_SYMBOL;
1687 expected_token = G_TOKEN_SYMBOL;
1689 /* skip rest of statement on errrors
1691 if (expected_token != G_TOKEN_NONE)
1693 register guint level;
1696 if (scanner->token == ')')
1698 if (scanner->token == '(')
1701 while (!g_scanner_eof (scanner) && level > 0)
1703 g_scanner_get_next_token (scanner);
1705 if (scanner->token == '(')
1707 else if (scanner->token == ')')
1714 gtk_item_factory_parse_rc_string (const gchar *rc_string)
1718 g_return_if_fail (rc_string != NULL);
1720 if (!gtk_item_factory_class)
1721 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1723 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1724 scanner = g_scanner_new (&ifactory_scanner_config);
1726 g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1728 gtk_item_factory_parse_rc_scanner (scanner);
1730 g_scanner_destroy (scanner);
1734 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1736 gpointer saved_symbol;
1738 g_return_if_fail (scanner != NULL);
1740 if (!gtk_item_factory_class)
1741 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1743 saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1744 g_scanner_remove_symbol (scanner, "menu-path");
1745 g_scanner_add_symbol (scanner, "menu-path", gtk_item_factory_parse_menu_path);
1747 g_scanner_peek_next_token (scanner);
1749 while (scanner->next_token == '(')
1751 g_scanner_get_next_token (scanner);
1753 gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1755 g_scanner_peek_next_token (scanner);
1758 g_scanner_remove_symbol (scanner, "menu-path");
1759 g_scanner_add_symbol (scanner, "menu-path", saved_symbol);
1763 gtk_item_factory_parse_rc (const gchar *file_name)
1768 g_return_if_fail (file_name != NULL);
1770 if (!S_ISREG (g_scanner_stat_mode (file_name)))
1773 fd = open (file_name, O_RDONLY);
1777 if (!gtk_item_factory_class)
1778 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1780 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1781 scanner = g_scanner_new (&ifactory_scanner_config);
1783 g_scanner_input_file (scanner, fd);
1785 gtk_item_factory_parse_rc_scanner (scanner);
1787 g_scanner_destroy (scanner);
1793 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1794 GtkTranslateFunc func,
1796 GtkDestroyNotify notify)
1798 g_return_if_fail (ifactory != NULL);
1800 if (ifactory->translate_notify)
1801 ifactory->translate_notify (ifactory->translate_data);
1803 ifactory->translate_func = func;
1804 ifactory->translate_data = data;
1805 ifactory->translate_notify = notify;