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 Library 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 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library 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.
22 #include "gtkitemfactory.h"
23 #include "gtk/gtksignal.h"
24 #include "gtk/gtkoptionmenu.h"
25 #include "gtk/gtkmenubar.h"
26 #include "gtk/gtkmenu.h"
27 #include "gtk/gtkmenuitem.h"
28 #include "gtk/gtkradiomenuitem.h"
29 #include "gtk/gtkcheckmenuitem.h"
30 #include "gtk/gtktearoffmenuitem.h"
31 #include "gtk/gtkaccellabel.h"
32 #include "gdk/gdkkeysyms.h"
42 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
43 #define ITEM_BLOCK_SIZE (128)
46 /* --- structures --- */
47 typedef struct _GtkIFCBData GtkIFCBData;
48 typedef struct _GtkIFActionLink GtkIFActionLink;
49 typedef struct _GtkIFDumpData GtkIFDumpData;
52 GtkItemFactoryCallback func;
55 guint callback_action;
57 struct _GtkIFActionLink
60 guint callback_action;
64 GtkPrintFunc print_func;
66 guint modified_only : 1;
67 GtkPatternSpec *pspec;
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 (GtkObject *object);
78 /* --- static variables --- */
79 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
80 static GtkObjectClass *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 const gchar *key_popup_data = "GtkItemFactory-popup-data";
85 static GQuark quark_popup_data = 0;
86 static const gchar *key_if_menu_pos = "GtkItemFactory-menu-position";
87 static GQuark quark_if_menu_pos = 0;
88 static const gchar *key_item_factory = "GtkItemFactory";
89 static GQuark quark_item_factory = 0;
90 static const gchar *key_item_factory_path = "GtkItemFactory-path";
91 static GQuark quark_item_factory_path = 0;
92 static const gchar *key_type_item = "<Item>";
93 static GQuark quark_type_item = 0;
94 static const gchar *key_type_title = "<Title>";
95 static GQuark quark_type_title = 0;
96 static const gchar *key_type_radio_item = "<RadioItem>";
97 static GQuark quark_type_radio_item = 0;
98 static const gchar *key_type_check_item = "<CheckItem>";
99 static GQuark quark_type_check_item = 0;
100 static const gchar *key_type_toggle_item = "<ToggleItem>";
101 static GQuark quark_type_toggle_item = 0;
102 static const gchar *key_type_tearoff_item = "<Tearoff>";
103 static GQuark quark_type_tearoff_item = 0;
104 static const gchar *key_type_separator_item = "<Separator>";
105 static GQuark quark_type_separator_item = 0;
106 static const gchar *key_type_branch = "<Branch>";
107 static GQuark quark_type_branch = 0;
108 static const gchar *key_type_last_branch = "<LastBranch>";
109 static GQuark quark_type_last_branch = 0;
110 static GScannerConfig ifactory_scanner_config =
114 ) /* cset_skip_characters */,
119 ) /* cset_identifier_first */,
126 ) /* cset_identifier_nth */,
127 ( ";\n" ) /* cpair_comment_single */,
129 FALSE /* case_sensitive */,
131 TRUE /* skip_comment_multi */,
132 TRUE /* skip_comment_single */,
133 FALSE /* scan_comment_multi */,
134 TRUE /* scan_identifier */,
135 FALSE /* scan_identifier_1char */,
136 FALSE /* scan_identifier_NULL */,
137 TRUE /* scan_symbols */,
138 TRUE /* scan_binary */,
139 TRUE /* scan_octal */,
140 TRUE /* scan_float */,
142 FALSE /* scan_hex_dollar */,
143 TRUE /* scan_string_sq */,
144 TRUE /* scan_string_dq */,
145 TRUE /* numbers_2_int */,
146 FALSE /* int_2_float */,
147 FALSE /* identifier_2_string */,
148 TRUE /* char_2_token */,
149 FALSE /* symbol_2_token */,
153 /* --- functions --- */
155 gtk_item_factory_get_type (void)
157 static GtkType item_factory_type = 0;
159 if (!item_factory_type)
161 static const GtkTypeInfo item_factory_info =
164 sizeof (GtkItemFactory),
165 sizeof (GtkItemFactoryClass),
166 (GtkClassInitFunc) gtk_item_factory_class_init,
167 (GtkObjectInitFunc) gtk_item_factory_init,
168 /* reserved_1 */ NULL,
169 /* reserved_2 */ NULL,
170 (GtkClassInitFunc) NULL,
173 item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
176 return item_factory_type;
180 gtk_item_factory_class_init (GtkItemFactoryClass *class)
182 GtkObjectClass *object_class;
184 gtk_item_factory_class = class;
186 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
188 object_class = (GtkObjectClass*) class;
190 object_class->destroy = gtk_item_factory_destroy;
191 object_class->finalize = gtk_item_factory_finalize;
193 class->cpair_comment_single = g_strdup (";\n");
195 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
196 ifactory_item_chunks =
197 g_mem_chunk_new ("GtkItemFactoryItem",
198 sizeof (GtkItemFactoryItem),
199 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
201 ifactory_cb_data_chunks =
202 g_mem_chunk_new ("GtkIFCBData",
203 sizeof (GtkIFCBData),
204 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
207 quark_popup_data = g_quark_from_static_string (key_popup_data);
208 quark_if_menu_pos = g_quark_from_static_string (key_if_menu_pos);
209 quark_item_factory = g_quark_from_static_string (key_item_factory);
210 quark_item_factory_path = g_quark_from_static_string (key_item_factory_path);
211 quark_type_item = g_quark_from_static_string (key_type_item);
212 quark_type_title = g_quark_from_static_string (key_type_title);
213 quark_type_radio_item = g_quark_from_static_string (key_type_radio_item);
214 quark_type_check_item = g_quark_from_static_string (key_type_check_item);
215 quark_type_toggle_item = g_quark_from_static_string (key_type_toggle_item);
216 quark_type_tearoff_item = g_quark_from_static_string (key_type_tearoff_item);
217 quark_type_separator_item = g_quark_from_static_string (key_type_separator_item);
218 quark_type_branch = g_quark_from_static_string (key_type_branch);
219 quark_type_last_branch = g_quark_from_static_string (key_type_last_branch);
223 gtk_item_factory_init (GtkItemFactory *ifactory)
227 object = GTK_OBJECT (ifactory);
229 ifactory->path = NULL;
230 ifactory->accel_group = NULL;
231 ifactory->widget = NULL;
232 ifactory->widgets_by_action = NULL;
236 gtk_item_factory_new (GtkType container_type,
238 GtkAccelGroup *accel_group)
240 GtkItemFactory *ifactory;
242 g_return_val_if_fail (path != NULL, NULL);
244 ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
245 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
251 gtk_item_factory_callback_marshal (GtkWidget *widget,
258 if (data->callback_type == 1)
260 GtkItemFactoryCallback1 func1 = data->func;
261 func1 (data->func_data, data->callback_action, widget);
263 else if (data->callback_type == 2)
265 GtkItemFactoryCallback2 func2 = data->func;
266 func2 (widget, data->func_data, data->callback_action);
271 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
277 if (item->in_propagation)
280 item->in_propagation = TRUE;
283 for (slist = item->widgets; slist; slist = slist->next)
287 widget = slist->data;
289 if (widget != exclude)
291 gtk_widget_ref (widget);
292 widget_list = g_slist_prepend (widget_list, widget);
296 for (slist = widget_list; slist; slist = slist->next)
299 GtkItemFactory *ifactory;
301 widget = slist->data;
303 ifactory = gtk_item_factory_from_widget (widget);
309 signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
312 if (item->accelerator_key)
313 gtk_widget_add_accelerator (widget,
315 ifactory->accel_group,
316 item->accelerator_key,
317 item->accelerator_mods,
323 work = gtk_accel_group_entries_from_object (GTK_OBJECT (widget));
326 GtkAccelEntry *ac_entry;
328 ac_entry = work->data;
330 if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
331 ac_entry->accel_group == ifactory->accel_group &&
332 ac_entry->signal_id == signal_id)
333 gtk_widget_remove_accelerator (GTK_WIDGET (widget),
334 ac_entry->accel_group,
335 ac_entry->accelerator_key,
336 ac_entry->accelerator_mods);
341 gtk_widget_unref (widget);
343 g_slist_free (widget_list);
345 item->in_propagation = FALSE;
349 gtk_item_factory_item_add_accelerator (GtkWidget *widget,
350 guint accel_signal_id,
351 GtkAccelGroup *accel_group,
354 GtkAccelFlags accel_flags,
355 GtkItemFactoryItem *item)
357 if (!item->in_propagation &&
358 g_slist_find (item->widgets, widget) &&
359 accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
361 item->accelerator_key = accel_key;
362 item->accelerator_mods = accel_mods;
363 item->modified = TRUE;
365 gtk_item_factory_propagate_accelerator (item, widget);
372 gtk_item_factory_item_remove_accelerator (GtkWidget *widget,
373 GtkAccelGroup *accel_group,
376 GtkItemFactoryItem *item)
378 if (!item->in_propagation &&
379 g_slist_find (item->widgets, widget) &&
380 item->accelerator_key == accel_key &&
381 item->accelerator_mods == accel_mods)
383 item->accelerator_key = 0;
384 item->accelerator_mods = 0;
385 item->modified = TRUE;
387 gtk_item_factory_propagate_accelerator (item, widget);
392 gtk_item_factory_item_remove_widget (GtkWidget *widget,
393 GtkItemFactoryItem *item)
395 item->widgets = g_slist_remove (item->widgets, widget);
396 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
397 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
401 ifactory_cb_data_free (gpointer mem)
403 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
407 gtk_item_factory_add_item (GtkItemFactory *ifactory,
409 const gchar *accelerator,
410 GtkItemFactoryCallback callback,
411 guint callback_action,
412 gpointer callback_data,
417 GtkItemFactoryClass *class;
418 GtkItemFactoryItem *item;
421 g_return_if_fail (widget != NULL);
422 g_return_if_fail (item_type != NULL);
424 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
426 fpath = g_strconcat (ifactory->path, path, NULL);
427 item = g_hash_table_lookup (class->item_ht, fpath);
429 /* link the widget into its item-entry
437 gtk_accelerator_parse (accelerator, &keyval, &mods);
444 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
448 item->accelerator_key = keyval;
449 item->accelerator_mods = mods;
450 item->modified = FALSE;
451 item->in_propagation = FALSE;
452 item->item_type = NULL;
453 item->widgets = NULL;
455 g_hash_table_insert (class->item_ht, item->path, item);
459 if (item->item_type == NULL)
461 g_assert (item->widgets == NULL);
463 if (item_type != ITEM_FACTORY_STRING)
464 item->item_type = g_strdup (item_type);
466 item->item_type = ITEM_FACTORY_STRING;
469 item->widgets = g_slist_prepend (item->widgets, widget);
470 gtk_signal_connect (GTK_OBJECT (widget),
472 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
475 /* set back pointers for the widget
477 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
478 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory_path, item->path);
479 gtk_widget_set_name (widget, item->path);
481 /* set accelerator group on menu widgets
483 if (GTK_IS_MENU (widget))
484 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
486 /* install defined accelerators
488 if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
490 if (item->accelerator_key)
491 gtk_widget_add_accelerator (widget,
493 ifactory->accel_group,
494 item->accelerator_key,
495 item->accelerator_mods,
498 gtk_widget_remove_accelerators (widget,
503 /* keep track of accelerator changes
505 gtk_signal_connect_after (GTK_OBJECT (widget),
507 GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
509 gtk_signal_connect_after (GTK_OBJECT (widget),
510 "remove-accelerator",
511 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
514 /* keep a per-action list of the widgets on the factory
518 GtkIFActionLink *link;
520 link = g_new (GtkIFActionLink, 1);
521 link->widget = widget;
522 link->callback_action = callback_action;
523 ifactory->widgets_by_action = g_slist_prepend (ifactory->widgets_by_action, link);
526 /* connect callback if neccessary
532 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
533 data->func = callback;
534 data->callback_type = callback_type;
535 data->func_data = callback_data;
536 data->callback_action = callback_action;
538 gtk_object_weakref (GTK_OBJECT (widget),
539 ifactory_cb_data_free,
541 gtk_signal_connect (GTK_OBJECT (widget),
543 GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
549 gtk_item_factory_construct (GtkItemFactory *ifactory,
550 GtkType container_type,
552 GtkAccelGroup *accel_group)
554 GtkAccelGroup *menu_group;
557 g_return_if_fail (ifactory != NULL);
558 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
559 g_return_if_fail (ifactory->accel_group == NULL);
560 g_return_if_fail (path != NULL);
561 if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
562 g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
566 if (path[0] != '<' && path[len - 1] != '>')
568 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
574 ifactory->accel_group = accel_group;
575 gtk_accel_group_ref (ifactory->accel_group);
578 ifactory->accel_group = gtk_accel_group_new ();
580 ifactory->path = g_strdup (path);
582 gtk_widget_new (container_type,
583 "GtkObject::signal::destroy", gtk_widget_destroyed, &ifactory->widget,
585 gtk_object_ref (GTK_OBJECT (ifactory));
586 gtk_object_sink (GTK_OBJECT (ifactory));
588 menu_group = gtk_accel_group_new ();
589 gtk_accel_group_attach (menu_group, GTK_OBJECT (ifactory->widget));
592 gtk_signal_connect_object_while_alive (GTK_OBJECT (ifactory->widget),
594 GTK_SIGNAL_FUNC (gtk_object_destroy),
595 GTK_OBJECT (ifactory));
597 gtk_item_factory_add_item (ifactory,
605 gtk_item_factory_from_path (const gchar *path)
607 GtkItemFactoryClass *class;
608 GtkItemFactoryItem *item;
612 g_return_val_if_fail (path != NULL, NULL);
613 g_return_val_if_fail (path[0] == '<', NULL);
615 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
618 while (path[i] && path[i] != '>')
622 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
626 fname = g_new (gchar, i + 2);
627 g_memmove (fname, path, i + 1);
630 item = g_hash_table_lookup (class->item_ht, fname);
634 if (item && item->widgets)
635 return gtk_item_factory_from_widget (item->widgets->data);
641 gtk_item_factory_destroy (GtkObject *object)
643 GtkItemFactory *ifactory;
646 g_return_if_fail (object != NULL);
647 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
649 ifactory = (GtkItemFactory*) object;
651 if (ifactory->widget)
655 dobj = GTK_OBJECT (ifactory->widget);
657 gtk_object_ref (dobj);
658 gtk_object_sink (dobj);
659 gtk_object_destroy (dobj);
660 gtk_object_unref (dobj);
662 ifactory->widget = NULL;
665 for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
666 g_free (slist->data);
667 g_slist_free (ifactory->widgets_by_action);
668 ifactory->widgets_by_action = NULL;
670 parent_class->destroy (object);
674 gtk_item_factory_finalize (GtkObject *object)
676 GtkItemFactory *ifactory;
678 g_return_if_fail (object != NULL);
679 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
681 ifactory = GTK_ITEM_FACTORY (object);
683 gtk_accel_group_unref (ifactory->accel_group);
684 g_free (ifactory->path);
685 g_assert (ifactory->widget == NULL);
687 if (ifactory->translate_data && ifactory->translate_notify)
688 ifactory->translate_notify (ifactory->translate_data);
690 parent_class->finalize (object);
694 gtk_item_factory_from_widget (GtkWidget *widget)
696 g_return_val_if_fail (widget != NULL, NULL);
697 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
699 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
703 gtk_item_factory_path_from_widget (GtkWidget *widget)
705 g_return_val_if_fail (widget != NULL, NULL);
706 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
708 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
712 gtk_item_factory_foreach (gpointer hash_key,
716 GtkItemFactoryItem *item;
720 gchar comment_prefix[2] = "\000\000";
725 if (data->pspec && !gtk_pattern_match_string (data->pspec, item->path))
728 comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
730 name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
731 string = g_strconcat (item->modified ? "" : comment_prefix,
740 data->print_func (data->func_data, string);
746 gtk_item_factory_dump_items (GtkPatternSpec *path_pspec,
747 gboolean modified_only,
748 GtkPrintFunc print_func,
753 g_return_if_fail (print_func != NULL);
755 if (!gtk_item_factory_class)
756 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
758 data.print_func = print_func;
759 data.func_data = func_data;
760 data.modified_only = (modified_only != FALSE);
761 data.pspec = path_pspec;
763 g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
767 gtk_item_factory_print_func (gpointer FILE_pointer,
770 FILE *f_out = FILE_pointer;
772 g_return_if_fail (FILE_pointer != NULL);
773 g_return_if_fail (string != NULL);
775 fputs (string, f_out);
780 gtk_item_factory_dump_rc (const gchar *file_name,
781 GtkPatternSpec *path_pspec,
782 gboolean modified_only)
786 g_return_if_fail (file_name != NULL);
788 f_out = fopen (file_name, "w");
793 if (g_get_prgname ())
794 fputs (g_get_prgname (), f_out);
795 fputs (" GtkItemFactory rc-file -*- scheme -*-\n", f_out);
796 fputs ("; this file is an automated menu-path dump\n", f_out);
797 fputs (";\n", f_out);
799 gtk_item_factory_dump_items (path_pspec,
801 gtk_item_factory_print_func,
808 gtk_item_factory_create_items (GtkItemFactory *ifactory,
810 GtkItemFactoryEntry *entries,
811 gpointer callback_data)
813 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
817 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
819 GtkItemFactoryEntry *entries,
820 gpointer callback_data,
825 g_return_if_fail (ifactory != NULL);
826 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
827 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
832 g_return_if_fail (entries != NULL);
834 for (i = 0; i < n_entries; i++)
835 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
839 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
842 GtkItemFactoryClass *class;
843 GtkItemFactoryItem *item;
845 g_return_val_if_fail (ifactory != NULL, NULL);
846 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
847 g_return_val_if_fail (path != NULL, NULL);
849 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
852 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
857 fpath = g_strconcat (ifactory->path, path, NULL);
858 item = g_hash_table_lookup (class->item_ht, fpath);
866 for (slist = item->widgets; slist; slist = slist->next)
868 if (gtk_item_factory_from_widget (slist->data) == ifactory)
877 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
882 g_return_val_if_fail (ifactory != NULL, NULL);
883 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
885 for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
887 GtkIFActionLink *link;
891 if (link->callback_action == action)
899 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
908 *path = g_strdup (str);
921 *parent_path = g_strdup (*path);
922 p = strrchr (*parent_path, '/');
925 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
930 if (ifactory->translate_func)
931 translation = ifactory->translate_func (str, ifactory->translate_data);
935 p = strrchr (translation, '/');
938 *item = g_strdup (p);
944 gtk_item_factory_create_item (GtkItemFactory *ifactory,
945 GtkItemFactoryEntry *entry,
946 gpointer callback_data,
958 gchar *item_type_path;
959 GtkAccelGroup *parent_accel_group = NULL;
962 g_return_if_fail (ifactory != NULL);
963 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
964 g_return_if_fail (entry != NULL);
965 g_return_if_fail (entry->path != NULL);
966 g_return_if_fail (entry->path[0] == '/');
967 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
969 if (!entry->item_type ||
970 entry->item_type[0] == 0)
972 item_type_path = (gpointer) key_type_item;
973 type_id = quark_type_item;
977 item_type_path = entry->item_type;
978 type_id = gtk_object_data_try_key (item_type_path);
982 if (type_id == quark_type_item)
983 type = GTK_TYPE_MENU_ITEM;
984 else if (type_id == quark_type_title)
985 type = GTK_TYPE_MENU_ITEM;
986 else if (type_id == quark_type_radio_item)
987 type = GTK_TYPE_RADIO_MENU_ITEM;
988 else if (type_id == quark_type_check_item)
989 type = GTK_TYPE_CHECK_MENU_ITEM;
990 else if (type_id == quark_type_tearoff_item)
991 type = GTK_TYPE_TEAROFF_MENU_ITEM;
992 else if (type_id == quark_type_toggle_item)
993 type = GTK_TYPE_CHECK_MENU_ITEM;
994 else if (type_id == quark_type_separator_item)
995 type = GTK_TYPE_MENU_ITEM;
996 else if (type_id == quark_type_branch)
997 type = GTK_TYPE_MENU_ITEM;
998 else if (type_id == quark_type_last_branch)
999 type = GTK_TYPE_MENU_ITEM;
1002 GtkWidget *radio_link;
1004 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
1005 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
1007 type = GTK_TYPE_RADIO_MENU_ITEM;
1008 radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
1012 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1019 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1020 &path, &parent_path, &name))
1023 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1026 GtkItemFactoryEntry pentry;
1029 ppath = g_strdup (entry->path);
1030 p = strrchr (ppath, '/');
1031 g_return_if_fail (p != NULL);
1033 pentry.path = ppath;
1034 pentry.accelerator = NULL;
1035 pentry.callback = NULL;
1036 pentry.callback_action = 0;
1037 pentry.item_type = "<Branch>";
1039 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1042 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1043 g_return_if_fail (parent != NULL);
1045 g_free (parent_path);
1047 g_return_if_fail (parent != NULL);
1049 tmp_list = gtk_accel_groups_from_object (GTK_OBJECT (parent));
1051 parent_accel_group = tmp_list->data;
1053 widget = gtk_widget_new (type,
1054 "GtkWidget::visible", TRUE,
1055 "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
1056 type_id != quark_type_title),
1057 "GtkWidget::parent", parent,
1060 if (type == GTK_TYPE_RADIO_MENU_ITEM)
1061 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1062 if (GTK_IS_CHECK_MENU_ITEM (widget))
1063 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
1065 if ((type_id != quark_type_separator_item) &&
1066 (type_id != quark_type_tearoff_item) &&
1072 gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1073 "GtkWidget::visible", TRUE,
1074 "GtkWidget::parent", widget,
1075 "GtkAccelLabel::accel_widget", widget,
1076 "GtkMisc::xalign", 0.0,
1079 accel_key = gtk_label_parse_uline (GTK_LABEL (label), name);
1081 if ((accel_key != GDK_VoidSymbol) && GTK_IS_MENU_BAR (parent))
1083 gtk_widget_add_accelerator (widget,
1085 ifactory->accel_group,
1086 accel_key, GDK_MOD1_MASK,
1090 if ((accel_key != GDK_VoidSymbol) && parent_accel_group)
1092 gtk_widget_add_accelerator (widget,
1102 if (type_id == quark_type_branch ||
1103 type_id == quark_type_last_branch)
1105 GtkAccelGroup *menu_group;
1107 if (entry->callback)
1108 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1111 menu_group = gtk_accel_group_new ();
1113 if (type_id == quark_type_last_branch)
1114 gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1118 gtk_widget_new (GTK_TYPE_MENU,
1121 gtk_accel_group_attach (menu_group, GTK_OBJECT (widget));
1122 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1125 gtk_item_factory_add_item (ifactory,
1126 path, entry->accelerator,
1127 (type_id == quark_type_branch ||
1128 type_id == quark_type_last_branch) ?
1129 (GtkItemFactoryCallback) NULL : entry->callback,
1130 entry->callback_action, callback_data,
1139 gtk_item_factory_create_menu_entries (guint n_entries,
1140 GtkMenuEntry *entries)
1142 static GtkPatternSpec pspec_separator = { 42, 0 };
1143 static GtkPatternSpec pspec_check = { 42, 0 };
1148 g_return_if_fail (entries != NULL);
1150 if (pspec_separator.pattern_length == 0)
1152 gtk_pattern_spec_init (&pspec_separator, "*<separator>*");
1153 gtk_pattern_spec_init (&pspec_check, "*<check>*");
1156 for (i = 0; i < n_entries; i++)
1158 GtkItemFactory *ifactory;
1159 GtkItemFactoryEntry entry;
1163 path = entries[i].path;
1164 ifactory = gtk_item_factory_from_path (path);
1167 g_warning ("gtk_item_factory_create_menu_entries(): "
1168 "entry[%u] refers to unknown item factory: \"%s\"",
1169 i, entries[i].path);
1173 while (*path != '>')
1179 entry.accelerator = entries[i].accelerator;
1180 entry.callback = entries[i].callback;
1181 entry.callback_action = 0;
1182 if (gtk_pattern_match_string (&pspec_separator, path))
1183 entry.item_type = (gpointer) key_type_separator_item;
1184 else if (!gtk_pattern_match_string (&pspec_check, path))
1185 entry.item_type = NULL;
1188 gboolean in_brace = FALSE;
1191 cpath = g_new (gchar, strlen (path));
1197 else if (*path == '>')
1204 entry.item_type = (gpointer) key_type_toggle_item;
1208 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1209 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1215 gtk_item_factories_path_delete (const gchar *ifactory_path,
1218 GtkItemFactoryClass *class;
1219 GtkItemFactoryItem *item;
1221 g_return_if_fail (path != NULL);
1223 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1226 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1231 g_return_if_fail (ifactory_path != NULL);
1233 fpath = g_strconcat (ifactory_path, path, NULL);
1234 item = g_hash_table_lookup (class->item_ht, fpath);
1240 GSList *widget_list;
1244 for (slist = item->widgets; slist; slist = slist->next)
1248 widget = slist->data;
1249 widget_list = g_slist_prepend (widget_list, widget);
1250 gtk_widget_ref (widget);
1253 for (slist = widget_list; slist; slist = slist->next)
1257 widget = slist->data;
1258 gtk_widget_destroy (widget);
1259 gtk_widget_unref (widget);
1261 g_slist_free (widget_list);
1266 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1269 GtkItemFactoryClass *class;
1270 GtkItemFactoryItem *item;
1273 g_return_if_fail (ifactory != NULL);
1274 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1275 g_return_if_fail (path != NULL);
1277 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
1279 fpath = g_strconcat (ifactory->path, path, NULL);
1280 item = g_hash_table_lookup (class->item_ht, fpath);
1285 GtkWidget *widget = NULL;
1288 for (slist = item->widgets; slist; slist = slist->next)
1290 widget = slist->data;
1292 if (gtk_item_factory_from_widget (widget) == ifactory)
1297 gtk_widget_destroy (widget);
1302 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1303 GtkItemFactoryEntry *entry)
1305 g_return_if_fail (ifactory != NULL);
1306 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1307 g_return_if_fail (entry != NULL);
1309 gtk_item_factory_delete_item (ifactory, entry->path);
1313 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1315 GtkItemFactoryEntry *entries)
1319 g_return_if_fail (ifactory != NULL);
1320 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1322 g_return_if_fail (entries != NULL);
1324 for (i = 0; i < n_entries; i++)
1325 gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1335 gtk_item_factory_menu_pos (GtkMenu *menu,
1340 MenuPos *mpos = func_data;
1347 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1349 GtkItemFactory *ifactory;
1351 g_return_val_if_fail (widget != NULL, NULL);
1352 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1354 ifactory = gtk_item_factory_from_widget (widget);
1356 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1362 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1364 g_return_val_if_fail (ifactory != NULL, NULL);
1365 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1367 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1371 ifactory_delete_popup_data (GtkObject *object,
1372 GtkItemFactory *ifactory)
1374 gtk_signal_disconnect_by_func (object,
1375 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1377 gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1381 gtk_item_factory_popup (GtkItemFactory *ifactory,
1387 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1391 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1392 gpointer popup_data,
1393 GtkDestroyNotify destroy,
1399 g_return_if_fail (ifactory != NULL);
1400 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1401 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1403 if (!GTK_WIDGET_VISIBLE (ifactory->widget))
1407 mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1411 mpos = g_new0 (MenuPos, 1);
1412 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1421 if (popup_data != NULL)
1423 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1427 gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1429 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1433 gtk_menu_popup (GTK_MENU (ifactory->widget),
1435 gtk_item_factory_menu_pos, mpos,
1436 mouse_button, time);
1441 gtk_item_factory_parse_menu_path (GScanner *scanner,
1442 GtkItemFactoryClass *class)
1444 GtkItemFactoryItem *item;
1446 g_scanner_get_next_token (scanner);
1447 if (scanner->token != G_TOKEN_STRING)
1448 return G_TOKEN_STRING;
1450 g_scanner_peek_next_token (scanner);
1451 if (scanner->next_token != G_TOKEN_STRING)
1453 g_scanner_get_next_token (scanner);
1454 return G_TOKEN_STRING;
1457 item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1460 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1462 item->path = g_strdup (scanner->value.v_string);
1463 item->accelerator_key = 0;
1464 item->accelerator_mods = 0;
1465 item->modified = TRUE;
1466 item->in_propagation = FALSE;
1467 item->item_type = NULL;
1468 item->widgets = NULL;
1470 g_hash_table_insert (class->item_ht, item->path, item);
1472 g_scanner_get_next_token (scanner);
1474 if (!item->in_propagation)
1479 old_keyval = item->accelerator_key;
1480 old_mods = item->accelerator_mods;
1481 gtk_accelerator_parse (scanner->value.v_string,
1482 &item->accelerator_key,
1483 &item->accelerator_mods);
1484 if (old_keyval != item->accelerator_key ||
1485 old_mods != item->accelerator_mods)
1487 item->modified = TRUE;
1488 gtk_item_factory_propagate_accelerator (item, NULL);
1492 g_scanner_get_next_token (scanner);
1493 if (scanner->token != ')')
1496 return G_TOKEN_NONE;
1500 gtk_item_factory_parse_statement (GScanner *scanner,
1501 GtkItemFactoryClass *class)
1503 guint expected_token;
1505 g_scanner_get_next_token (scanner);
1507 if (scanner->token == G_TOKEN_SYMBOL)
1509 guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1511 parser_func = scanner->value.v_symbol;
1513 /* check whether this is a GtkItemFactory symbol.
1515 if (parser_func == gtk_item_factory_parse_menu_path)
1516 expected_token = parser_func (scanner, class);
1518 expected_token = G_TOKEN_SYMBOL;
1521 expected_token = G_TOKEN_SYMBOL;
1523 /* skip rest of statement on errrors
1525 if (expected_token != G_TOKEN_NONE)
1527 register guint level;
1530 if (scanner->token == ')')
1532 if (scanner->token == '(')
1535 while (!g_scanner_eof (scanner) && level > 0)
1537 g_scanner_get_next_token (scanner);
1539 if (scanner->token == '(')
1541 else if (scanner->token == ')')
1548 gtk_item_factory_parse_rc_string (const gchar *rc_string)
1552 g_return_if_fail (rc_string != NULL);
1554 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1555 scanner = g_scanner_new (&ifactory_scanner_config);
1557 g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1559 gtk_item_factory_parse_rc_scanner (scanner);
1561 g_scanner_destroy (scanner);
1565 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1567 gpointer saved_symbol;
1569 g_return_if_fail (scanner != NULL);
1571 if (!gtk_item_factory_class)
1572 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1574 saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1575 g_scanner_remove_symbol (scanner, "menu-path");
1576 g_scanner_add_symbol (scanner, "menu-path", gtk_item_factory_parse_menu_path);
1578 g_scanner_peek_next_token (scanner);
1580 while (scanner->next_token == '(')
1582 g_scanner_get_next_token (scanner);
1584 gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1586 g_scanner_peek_next_token (scanner);
1589 g_scanner_remove_symbol (scanner, "menu-path");
1590 g_scanner_add_symbol (scanner, "menu-path", saved_symbol);
1594 gtk_item_factory_parse_rc (const gchar *file_name)
1599 g_return_if_fail (file_name != NULL);
1601 if (!S_ISREG (g_scanner_stat_mode (file_name)))
1604 fd = open (file_name, O_RDONLY);
1608 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1609 scanner = g_scanner_new (&ifactory_scanner_config);
1611 g_scanner_input_file (scanner, fd);
1613 gtk_item_factory_parse_rc_scanner (scanner);
1615 g_scanner_destroy (scanner);
1621 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1622 GtkTranslateFunc func,
1624 GtkDestroyNotify notify)
1626 g_return_if_fail (ifactory != NULL);
1628 if (ifactory->translate_data && ifactory->translate_notify)
1629 ifactory->translate_notify (ifactory->translate_data);
1631 ifactory->translate_func = func;
1632 ifactory->translate_data = data;
1633 ifactory->translate_notify = notify;