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/gtkaccellabel.h"
31 #include "gdk/gdkprivate.h" /* for gdk_progname */
41 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
42 #define ITEM_BLOCK_SIZE (128)
45 /* --- structures --- */
46 typedef struct _GtkIFCBData GtkIFCBData;
47 typedef struct _GtkIFActionLink GtkIFActionLink;
48 typedef struct _GtkIFDumpData GtkIFDumpData;
51 GtkItemFactoryCallback func;
54 guint callback_action;
56 struct _GtkIFActionLink
59 guint callback_action;
63 GtkPrintFunc print_func;
65 guint modified_only : 1;
66 GtkPatternSpec *pspec;
70 /* --- prototypes --- */
71 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
72 static void gtk_item_factory_init (GtkItemFactory *ifactory);
73 static void gtk_item_factory_destroy (GtkObject *object);
74 static void gtk_item_factory_finalize (GtkObject *object);
77 /* --- static variables --- */
78 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
79 static GtkObjectClass *parent_class = NULL;
80 static const gchar *item_factory_string = "Gtk-<ItemFactory>";
81 static GMemChunk *ifactory_item_chunks = NULL;
82 static GMemChunk *ifactory_cb_data_chunks = NULL;
83 static const gchar *key_popup_data = "GtkItemFactory-popup-data";
84 static GQuark quark_popup_data = 0;
85 static const gchar *key_if_menu_pos = "GtkItemFactory-menu-position";
86 static GQuark quark_if_menu_pos = 0;
87 static const gchar *key_item_factory = "GtkItemFactory";
88 static GQuark quark_item_factory = 0;
89 static const gchar *key_item_factory_path = "GtkItemFactory-path";
90 static GQuark quark_item_factory_path = 0;
91 static const gchar *key_type_item = "<Item>";
92 static GQuark quark_type_item = 0;
93 static const gchar *key_type_title = "<Title>";
94 static GQuark quark_type_title = 0;
95 static const gchar *key_type_radio_item = "<RadioItem>";
96 static GQuark quark_type_radio_item = 0;
97 static const gchar *key_type_check_item = "<CheckItem>";
98 static GQuark quark_type_check_item = 0;
99 static const gchar *key_type_toggle_item = "<ToggleItem>";
100 static GQuark quark_type_toggle_item = 0;
101 static const gchar *key_type_separator_item = "<Separator>";
102 static GQuark quark_type_separator_item = 0;
103 static const gchar *key_type_branch = "<Branch>";
104 static GQuark quark_type_branch = 0;
105 static const gchar *key_type_last_branch = "<LastBranch>";
106 static GQuark quark_type_last_branch = 0;
107 static GScannerConfig ifactory_scanner_config =
111 ) /* cset_skip_characters */,
116 ) /* cset_identifier_first */,
123 ) /* cset_identifier_nth */,
124 ( ";\n" ) /* cpair_comment_single */,
126 FALSE /* case_sensitive */,
128 TRUE /* skip_comment_multi */,
129 TRUE /* skip_comment_single */,
130 FALSE /* scan_comment_multi */,
131 TRUE /* scan_identifier */,
132 FALSE /* scan_identifier_1char */,
133 FALSE /* scan_identifier_NULL */,
134 TRUE /* scan_symbols */,
135 TRUE /* scan_binary */,
136 TRUE /* scan_octal */,
137 TRUE /* scan_float */,
139 FALSE /* scan_hex_dollar */,
140 TRUE /* scan_string_sq */,
141 TRUE /* scan_string_dq */,
142 TRUE /* numbers_2_int */,
143 FALSE /* int_2_float */,
144 FALSE /* identifier_2_string */,
145 TRUE /* char_2_token */,
146 FALSE /* symbol_2_token */,
150 /* --- functions --- */
152 gtk_item_factory_get_type (void)
154 static GtkType item_factory_type = 0;
156 if (!item_factory_type)
158 GtkTypeInfo item_factory_info =
161 sizeof (GtkItemFactory),
162 sizeof (GtkItemFactoryClass),
163 (GtkClassInitFunc) gtk_item_factory_class_init,
164 (GtkObjectInitFunc) gtk_item_factory_init,
165 /* reserved_1 */ NULL,
166 /* reserved_2 */ NULL,
167 (GtkClassInitFunc) NULL,
170 item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
173 return item_factory_type;
177 gtk_item_factory_class_init (GtkItemFactoryClass *class)
179 GtkObjectClass *object_class;
181 gtk_item_factory_class = class;
183 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
185 object_class = (GtkObjectClass*) class;
187 object_class->destroy = gtk_item_factory_destroy;
188 object_class->finalize = gtk_item_factory_finalize;
190 class->cpair_comment_single = g_strdup (";\n");
192 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
193 ifactory_item_chunks =
194 g_mem_chunk_new ("GtkItemFactoryItem",
195 sizeof (GtkItemFactoryItem),
196 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
198 ifactory_cb_data_chunks =
199 g_mem_chunk_new ("GtkIFCBData",
200 sizeof (GtkIFCBData),
201 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
204 quark_popup_data = g_quark_from_static_string (key_popup_data);
205 quark_if_menu_pos = g_quark_from_static_string (key_if_menu_pos);
206 quark_item_factory = g_quark_from_static_string (key_item_factory);
207 quark_item_factory_path = g_quark_from_static_string (key_item_factory_path);
208 quark_type_item = g_quark_from_static_string (key_type_item);
209 quark_type_title = g_quark_from_static_string (key_type_title);
210 quark_type_radio_item = g_quark_from_static_string (key_type_radio_item);
211 quark_type_check_item = g_quark_from_static_string (key_type_check_item);
212 quark_type_toggle_item = g_quark_from_static_string (key_type_toggle_item);
213 quark_type_separator_item = g_quark_from_static_string (key_type_separator_item);
214 quark_type_branch = g_quark_from_static_string (key_type_branch);
215 quark_type_last_branch = g_quark_from_static_string (key_type_last_branch);
219 gtk_item_factory_init (GtkItemFactory *ifactory)
223 object = GTK_OBJECT (ifactory);
225 ifactory->path = NULL;
226 ifactory->accel_group = NULL;
227 ifactory->widget = NULL;
228 ifactory->widgets_by_action = NULL;
232 gtk_item_factory_new (GtkType container_type,
234 GtkAccelGroup *accel_group)
236 GtkItemFactory *ifactory;
238 g_return_val_if_fail (path != NULL, NULL);
240 ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
241 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
247 gtk_item_factory_callback_marshal (GtkWidget *widget,
254 if (data->callback_type == 1)
256 GtkItemFactoryCallback1 func1 = data->func;
257 func1 (data->func_data, data->callback_action, widget);
259 else if (data->callback_type == 2)
261 GtkItemFactoryCallback2 func2 = data->func;
262 func2 (widget, data->func_data, data->callback_action);
267 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
273 if (item->in_propagation)
276 item->in_propagation = TRUE;
279 for (slist = item->widgets; slist; slist = slist->next)
283 widget = slist->data;
285 if (widget != exclude)
287 gtk_widget_ref (widget);
288 widget_list = g_slist_prepend (widget_list, widget);
292 for (slist = widget_list; slist; slist = slist->next)
295 GtkItemFactory *ifactory;
297 widget = slist->data;
299 ifactory = gtk_item_factory_from_widget (widget);
305 signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
308 if (item->accelerator_key)
309 gtk_widget_add_accelerator (widget,
311 ifactory->accel_group,
312 item->accelerator_key,
313 item->accelerator_mods,
319 slist = gtk_accel_group_entries_from_object (GTK_OBJECT (widget));
322 GtkAccelEntry *ac_entry;
324 ac_entry = slist->data;
326 if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
327 ac_entry->accel_group == ifactory->accel_group &&
328 ac_entry->signal_id == signal_id)
329 gtk_widget_remove_accelerator (GTK_WIDGET (widget),
330 ac_entry->accel_group,
331 ac_entry->accelerator_key,
332 ac_entry->accelerator_mods);
337 gtk_widget_unref (widget);
339 g_slist_free (widget_list);
341 item->in_propagation = FALSE;
345 gtk_item_factory_item_add_accelerator (GtkWidget *widget,
346 guint accel_signal_id,
347 GtkAccelGroup *accel_group,
350 GtkAccelFlags accel_flags,
351 GtkItemFactoryItem *item)
353 if (!item->in_propagation &&
354 g_slist_find (item->widgets, widget) &&
355 accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
357 item->accelerator_key = accel_key;
358 item->accelerator_mods = accel_mods;
359 item->modified = TRUE;
361 gtk_item_factory_propagate_accelerator (item, widget);
368 gtk_item_factory_item_remove_accelerator (GtkWidget *widget,
369 GtkAccelGroup *accel_group,
372 GtkItemFactoryItem *item)
374 if (!item->in_propagation &&
375 g_slist_find (item->widgets, widget) &&
376 item->accelerator_key == accel_key &&
377 item->accelerator_mods == accel_mods)
379 item->accelerator_key = 0;
380 item->accelerator_mods = 0;
381 item->modified = TRUE;
383 gtk_item_factory_propagate_accelerator (item, widget);
388 gtk_item_factory_item_remove_widget (GtkWidget *widget,
389 GtkItemFactoryItem *item)
391 item->widgets = g_slist_remove (item->widgets, widget);
392 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
393 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
397 ifactory_cb_data_free (gpointer mem)
399 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
403 gtk_item_factory_add_item (GtkItemFactory *ifactory,
405 const gchar *accelerator,
406 GtkItemFactoryCallback callback,
407 guint callback_action,
408 gpointer callback_data,
413 GtkItemFactoryClass *class;
414 GtkItemFactoryItem *item;
417 g_return_if_fail (widget != NULL);
418 g_return_if_fail (item_type != NULL);
420 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
422 fpath = g_strconcat (ifactory->path, path, NULL);
423 item = g_hash_table_lookup (class->item_ht, fpath);
425 /* link the widget into its item-entry
433 gtk_accelerator_parse (accelerator, &keyval, &mods);
440 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
444 item->accelerator_key = keyval;
445 item->accelerator_mods = mods;
446 item->modified = FALSE;
447 item->in_propagation = FALSE;
448 item->item_type = NULL;
449 item->widgets = NULL;
451 g_hash_table_insert (class->item_ht, item->path, item);
455 if (item->item_type == NULL)
457 g_assert (item->widgets == NULL);
459 if (item_type != ITEM_FACTORY_STRING)
460 item->item_type = g_strdup (item_type);
462 item->item_type = ITEM_FACTORY_STRING;
465 item->widgets = g_slist_prepend (item->widgets, widget);
466 gtk_signal_connect (GTK_OBJECT (widget),
468 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
471 /* set back pointers for the widget
473 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
474 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory_path, item->path);
475 gtk_widget_set_name (widget, item->path);
477 /* set accelerator group on menu widgets
479 if (GTK_IS_MENU (widget))
480 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
482 /* install defined accelerators
484 if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
486 if (item->accelerator_key)
487 gtk_widget_add_accelerator (widget,
489 ifactory->accel_group,
490 item->accelerator_key,
491 item->accelerator_mods,
494 gtk_widget_remove_accelerators (widget,
499 /* keep track of accelerator changes
501 gtk_signal_connect_after (GTK_OBJECT (widget),
503 GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
505 gtk_signal_connect_after (GTK_OBJECT (widget),
506 "remove-accelerator",
507 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
510 /* keep a per-action list of the widgets on the factory
514 GtkIFActionLink *link;
516 link = g_new (GtkIFActionLink, 1);
517 link->widget = widget;
518 link->callback_action = callback_action;
519 ifactory->widgets_by_action = g_slist_prepend (ifactory->widgets_by_action, link);
522 /* connect callback if neccessary
528 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
529 data->func = callback;
530 data->callback_type = callback_type;
531 data->func_data = callback_data;
532 data->callback_action = callback_action;
534 gtk_object_weakref (GTK_OBJECT (widget),
535 ifactory_cb_data_free,
537 gtk_signal_connect (GTK_OBJECT (widget),
539 GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
545 gtk_item_factory_construct (GtkItemFactory *ifactory,
546 GtkType container_type,
548 GtkAccelGroup *accel_group)
552 g_return_if_fail (ifactory != NULL);
553 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
554 g_return_if_fail (ifactory->accel_group == NULL);
555 g_return_if_fail (path != NULL);
556 if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
557 g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
561 if (path[0] != '<' && path[len - 1] != '>')
563 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
569 ifactory->accel_group = accel_group;
570 gtk_accel_group_ref (ifactory->accel_group);
573 ifactory->accel_group = gtk_accel_group_new ();
575 ifactory->path = g_strdup (path);
577 gtk_widget_new (container_type,
578 "GtkObject::signal::destroy", gtk_widget_destroyed, &ifactory->widget,
580 gtk_object_ref (GTK_OBJECT (ifactory));
581 gtk_object_sink (GTK_OBJECT (ifactory));
583 gtk_signal_connect_object_while_alive (GTK_OBJECT (ifactory->widget),
585 GTK_SIGNAL_FUNC (gtk_object_destroy),
586 GTK_OBJECT (ifactory));
588 gtk_item_factory_add_item (ifactory,
596 gtk_item_factory_from_path (const gchar *path)
598 GtkItemFactoryClass *class;
599 GtkItemFactoryItem *item;
603 g_return_val_if_fail (path != NULL, NULL);
604 g_return_val_if_fail (path[0] == '<', NULL);
606 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
609 while (path[i] && path[i] != '>')
613 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
617 fname = g_new (gchar, i + 2);
618 g_memmove (fname, path, i + 1);
621 item = g_hash_table_lookup (class->item_ht, fname);
622 if (item && item->widgets)
623 return gtk_item_factory_from_widget (item->widgets->data);
629 gtk_item_factory_destroy (GtkObject *object)
631 GtkItemFactory *ifactory;
634 g_return_if_fail (object != NULL);
635 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
637 ifactory = (GtkItemFactory*) object;
639 if (ifactory->widget)
643 object = GTK_OBJECT (ifactory->widget);
645 gtk_object_ref (object);
646 gtk_object_sink (object);
647 gtk_object_destroy (object);
648 gtk_object_unref (object);
650 ifactory->widget = NULL;
653 for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
654 g_free (slist->data);
655 g_slist_free (ifactory->widgets_by_action);
656 ifactory->widgets_by_action = NULL;
658 parent_class->destroy (object);
662 gtk_item_factory_finalize (GtkObject *object)
664 GtkItemFactory *ifactory;
666 g_return_if_fail (object != NULL);
667 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
669 ifactory = GTK_ITEM_FACTORY (object);
671 gtk_accel_group_unref (ifactory->accel_group);
672 g_free (ifactory->path);
673 g_assert (ifactory->widget == NULL);
675 parent_class->finalize (object);
679 gtk_item_factory_from_widget (GtkWidget *widget)
681 g_return_val_if_fail (widget != NULL, NULL);
682 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
684 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
688 gtk_item_factory_path_from_widget (GtkWidget *widget)
690 g_return_val_if_fail (widget != NULL, NULL);
691 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
693 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
697 gtk_item_factory_foreach (gpointer hash_key,
701 GtkItemFactoryItem *item;
705 gchar comment_prefix[2] = "\000\000";
710 if (data->pspec && !gtk_pattern_match_string (data->pspec, item->path))
713 comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
715 name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
716 string = g_strconcat (item->modified ? "" : comment_prefix,
725 data->print_func (data->func_data, string);
731 gtk_item_factory_dump_items (GtkPatternSpec *path_pspec,
732 gboolean modified_only,
733 GtkPrintFunc print_func,
738 g_return_if_fail (print_func != NULL);
740 if (!gtk_item_factory_class)
741 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
743 data.print_func = print_func;
744 data.func_data = func_data;
745 data.modified_only = (modified_only != FALSE);
746 data.pspec = path_pspec;
748 g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
752 gtk_item_factory_print_func (gpointer FILE_pointer,
755 FILE *f_out = FILE_pointer;
757 g_return_if_fail (FILE_pointer != NULL);
758 g_return_if_fail (string != NULL);
760 fputs (string, f_out);
765 gtk_item_factory_dump_rc (const gchar *file_name,
766 GtkPatternSpec *path_pspec,
767 gboolean modified_only)
771 g_return_if_fail (file_name != NULL);
773 f_out = fopen (file_name, "w");
779 fputs (gdk_progname, f_out);
780 fputs (" GtkItemFactory rc-file -*- scheme -*-\n", f_out);
781 fputs ("; this file is an automated menu-path dump\n", f_out);
782 fputs (";\n", f_out);
784 gtk_item_factory_dump_items (path_pspec,
786 gtk_item_factory_print_func,
793 gtk_item_factory_create_items (GtkItemFactory *ifactory,
795 GtkItemFactoryEntry *entries,
796 gpointer callback_data)
798 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
802 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
804 GtkItemFactoryEntry *entries,
805 gpointer callback_data,
810 g_return_if_fail (ifactory != NULL);
811 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
812 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
817 g_return_if_fail (entries != NULL);
819 for (i = 0; i < n_entries; i++)
820 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
824 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
827 GtkItemFactoryClass *class;
828 GtkItemFactoryItem *item;
830 g_return_val_if_fail (ifactory != NULL, NULL);
831 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
832 g_return_val_if_fail (path != NULL, NULL);
834 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
837 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
842 fpath = g_strconcat (ifactory->path, path, NULL);
843 item = g_hash_table_lookup (class->item_ht, fpath);
851 for (slist = item->widgets; slist; slist = slist->next)
853 if (gtk_item_factory_from_widget (slist->data) == ifactory)
862 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
867 g_return_val_if_fail (ifactory != NULL, NULL);
868 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
870 for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
872 GtkIFActionLink *link;
876 if (link->callback_action == action)
884 gtk_item_factory_create_item (GtkItemFactory *ifactory,
885 GtkItemFactoryEntry *entry,
886 gpointer callback_data,
896 gchar *item_type_path;
898 g_return_if_fail (ifactory != NULL);
899 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
900 g_return_if_fail (entry != NULL);
901 g_return_if_fail (entry->path != NULL);
902 g_return_if_fail (entry->path[0] == '/');
903 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
905 if (!entry->item_type ||
906 entry->item_type[0] == 0)
908 item_type_path = (gpointer) key_type_item;
909 type_id = quark_type_item;
913 item_type_path = entry->item_type;
914 type_id = gtk_object_data_try_key (item_type_path);
918 if (type_id == quark_type_item)
919 type = GTK_TYPE_MENU_ITEM;
920 else if (type_id == quark_type_title)
921 type = GTK_TYPE_MENU_ITEM;
922 else if (type_id == quark_type_radio_item)
923 type = GTK_TYPE_RADIO_MENU_ITEM;
924 else if (type_id == quark_type_check_item)
925 type = GTK_TYPE_CHECK_MENU_ITEM;
926 else if (type_id == quark_type_toggle_item)
927 type = GTK_TYPE_CHECK_MENU_ITEM;
928 else if (type_id == quark_type_separator_item)
929 type = GTK_TYPE_MENU_ITEM;
930 else if (type_id == quark_type_branch)
931 type = GTK_TYPE_MENU_ITEM;
932 else if (type_id == quark_type_last_branch)
933 type = GTK_TYPE_MENU_ITEM;
936 GtkWidget *radio_link;
938 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
939 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
941 type = GTK_TYPE_RADIO_MENU_ITEM;
942 radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
946 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
953 parent_path = g_strdup (entry->path);
954 p = strrchr (parent_path, '/');
957 g_warning ("GtkItemFactory: invalid entry path `%s'", entry->path);
962 parent = gtk_item_factory_get_widget (ifactory, parent_path);
965 GtkItemFactoryEntry pentry;
967 pentry.path = parent_path;
968 pentry.accelerator = NULL;
969 pentry.callback = NULL;
970 pentry.callback_action = 0;
971 pentry.item_type = "<Branch>";
973 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
975 parent = gtk_item_factory_get_widget (ifactory, parent_path);
977 g_free (parent_path);
979 g_return_if_fail (parent != NULL);
981 p = strrchr (entry->path, '/');
984 widget = gtk_widget_new (type,
985 "GtkWidget::visible", TRUE,
986 "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
987 type_id != quark_type_title),
988 "GtkWidget::parent", parent,
991 if (type == GTK_TYPE_RADIO_MENU_ITEM)
992 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
993 if (GTK_IS_CHECK_MENU_ITEM (widget))
994 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
996 if (type_id != quark_type_separator_item && *p)
1001 gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1002 "GtkLabel::label", p,
1003 "GtkWidget::visible", TRUE,
1004 "GtkWidget::parent", widget,
1005 "GtkAccelLabel::accel_widget", widget,
1006 "GtkMisc::xalign", 0.0,
1009 if (type_id == quark_type_branch ||
1010 type_id == quark_type_last_branch)
1012 if (type_id == quark_type_last_branch)
1013 gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1017 gtk_widget_new (GTK_TYPE_MENU,
1019 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1022 gtk_item_factory_add_item (ifactory,
1023 entry->path, entry->accelerator,
1024 entry->callback, entry->callback_action, callback_data,
1031 gtk_item_factory_create_menu_entries (guint n_entries,
1032 GtkMenuEntry *entries)
1034 static GtkPatternSpec pspec_separator = { 42, 0 };
1035 static GtkPatternSpec pspec_check = { 42, 0 };
1040 g_return_if_fail (entries != NULL);
1042 if (pspec_separator.pattern_length == 0)
1044 gtk_pattern_spec_init (&pspec_separator, "*<separator>*");
1045 gtk_pattern_spec_init (&pspec_check, "*<check>*");
1048 for (i = 0; i < n_entries; i++)
1050 GtkItemFactory *ifactory;
1051 GtkItemFactoryEntry entry;
1055 path = entries[i].path;
1056 ifactory = gtk_item_factory_from_path (path);
1059 g_warning ("gtk_item_factory_create_menu_entries(): "
1060 "entry[%u] refers to unknown item factory: \"%s\"",
1061 i, entries[i].path);
1065 while (*path != '>')
1071 entry.accelerator = entries[i].accelerator;
1072 entry.callback = entries[i].callback;
1073 entry.callback_action = 0;
1074 if (gtk_pattern_match_string (&pspec_separator, path))
1075 entry.item_type = (gpointer) key_type_separator_item;
1076 else if (!gtk_pattern_match_string (&pspec_check, path))
1077 entry.item_type = NULL;
1080 gboolean in_brace = FALSE;
1083 cpath = g_new (gchar, strlen (path));
1089 else if (*path == '>')
1096 entry.item_type = (gpointer) key_type_toggle_item;
1100 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1101 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1107 gtk_item_factories_path_delete (const gchar *ifactory_path,
1110 GtkItemFactoryClass *class;
1111 GtkItemFactoryItem *item;
1113 g_return_if_fail (path != NULL);
1115 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1118 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1123 g_return_if_fail (ifactory_path != NULL);
1125 fpath = g_strconcat (ifactory_path, path, NULL);
1126 item = g_hash_table_lookup (class->item_ht, fpath);
1132 GSList *widget_list;
1136 for (slist = item->widgets; slist; slist = slist->next)
1140 widget = slist->data;
1141 widget_list = g_slist_prepend (widget_list, widget);
1142 gtk_widget_ref (widget);
1145 for (slist = widget_list; slist; slist = slist->next)
1149 widget = slist->data;
1150 gtk_widget_destroy (widget);
1151 gtk_widget_unref (widget);
1153 g_slist_free (widget_list);
1158 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1161 GtkItemFactoryClass *class;
1162 GtkItemFactoryItem *item;
1165 g_return_if_fail (ifactory != NULL);
1166 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1167 g_return_if_fail (path != NULL);
1169 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
1171 fpath = g_strconcat (ifactory->path, path, NULL);
1172 item = g_hash_table_lookup (class->item_ht, fpath);
1177 GtkWidget *widget = NULL;
1180 for (slist = item->widgets; slist; slist = slist->next)
1182 widget = slist->data;
1184 if (gtk_item_factory_from_widget (widget) == ifactory)
1189 gtk_widget_destroy (widget);
1194 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1195 GtkItemFactoryEntry *entry)
1197 g_return_if_fail (ifactory != NULL);
1198 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1199 g_return_if_fail (entry != NULL);
1201 gtk_item_factory_delete_item (ifactory, entry->path);
1205 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1207 GtkItemFactoryEntry *entries)
1211 g_return_if_fail (ifactory != NULL);
1212 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1214 g_return_if_fail (entries != NULL);
1216 for (i = 0; i < n_entries; i++)
1217 gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1227 gtk_item_factory_menu_pos (GtkMenu *menu,
1232 MenuPos *mpos = func_data;
1239 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1241 GtkItemFactory *ifactory;
1243 g_return_val_if_fail (widget != NULL, NULL);
1244 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1246 ifactory = gtk_item_factory_from_widget (widget);
1248 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1254 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1256 g_return_val_if_fail (ifactory != NULL, NULL);
1257 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1259 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1263 ifactory_delete_popup_data (GtkObject *object,
1264 GtkItemFactory *ifactory)
1266 gtk_signal_disconnect_by_func (object,
1267 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1269 gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1273 gtk_item_factory_popup (GtkItemFactory *ifactory,
1279 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1283 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1284 gpointer popup_data,
1285 GtkDestroyNotify destroy,
1291 g_return_if_fail (ifactory != NULL);
1292 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1293 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1295 if (!GTK_WIDGET_VISIBLE (ifactory->widget))
1299 mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1303 mpos = g_new0 (MenuPos, 1);
1304 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1313 if (popup_data != NULL)
1315 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1319 gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1321 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1325 gtk_menu_popup (GTK_MENU (ifactory->widget),
1327 gtk_item_factory_menu_pos, mpos,
1328 mouse_button, time);
1333 gtk_item_factory_parse_menu_path (GScanner *scanner,
1334 GtkItemFactoryClass *class)
1336 GtkItemFactoryItem *item;
1338 g_scanner_get_next_token (scanner);
1339 if (scanner->token != G_TOKEN_STRING)
1340 return G_TOKEN_STRING;
1342 g_scanner_peek_next_token (scanner);
1343 if (scanner->next_token != G_TOKEN_STRING)
1345 g_scanner_get_next_token (scanner);
1346 return G_TOKEN_STRING;
1349 item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1352 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1354 item->path = g_strdup (scanner->value.v_string);
1355 item->accelerator_key = 0;
1356 item->accelerator_mods = 0;
1357 item->modified = TRUE;
1358 item->in_propagation = FALSE;
1359 item->item_type = NULL;
1360 item->widgets = NULL;
1362 g_hash_table_insert (class->item_ht, item->path, item);
1364 g_scanner_get_next_token (scanner);
1366 if (!item->in_propagation)
1371 old_keyval = item->accelerator_key;
1372 old_mods = item->accelerator_mods;
1373 gtk_accelerator_parse (scanner->value.v_string,
1374 &item->accelerator_key,
1375 &item->accelerator_mods);
1376 if (old_keyval != item->accelerator_key ||
1377 old_mods != item->accelerator_mods)
1379 item->modified = TRUE;
1380 gtk_item_factory_propagate_accelerator (item, NULL);
1384 g_scanner_get_next_token (scanner);
1385 if (scanner->token != ')')
1388 return G_TOKEN_NONE;
1392 gtk_item_factory_parse_statement (GScanner *scanner,
1393 GtkItemFactoryClass *class)
1395 guint expected_token;
1397 g_scanner_get_next_token (scanner);
1399 if (scanner->token == G_TOKEN_SYMBOL)
1401 guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1403 parser_func = scanner->value.v_symbol;
1405 /* check whether this is a GtkItemFactory symbol...
1407 if (parser_func == gtk_item_factory_parse_menu_path)
1408 expected_token = parser_func (scanner, class);
1410 expected_token = G_TOKEN_SYMBOL;
1413 expected_token = G_TOKEN_SYMBOL;
1415 /* skip rest of statement on errrors
1417 if (expected_token != G_TOKEN_NONE)
1419 register guint level;
1422 if (scanner->token == ')')
1424 if (scanner->token == '(')
1427 while (!g_scanner_eof (scanner) && level > 0)
1429 g_scanner_get_next_token (scanner);
1431 if (scanner->token == '(')
1433 else if (scanner->token == ')')
1440 gtk_item_factory_parse_rc_string (const gchar *rc_string)
1444 g_return_if_fail (rc_string != NULL);
1446 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1447 scanner = g_scanner_new (&ifactory_scanner_config);
1449 g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1451 gtk_item_factory_parse_rc_scanner (scanner);
1453 g_scanner_destroy (scanner);
1457 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1459 gpointer saved_symbol;
1461 g_return_if_fail (scanner != NULL);
1463 if (!gtk_item_factory_class)
1464 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1466 saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1467 g_scanner_remove_symbol (scanner, "menu-path");
1468 g_scanner_add_symbol (scanner, "menu-path", gtk_item_factory_parse_menu_path);
1470 g_scanner_peek_next_token (scanner);
1472 while (scanner->next_token == '(')
1474 g_scanner_get_next_token (scanner);
1476 gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1478 g_scanner_peek_next_token (scanner);
1481 g_scanner_remove_symbol (scanner, "menu-path");
1482 g_scanner_add_symbol (scanner, "menu-path", saved_symbol);
1486 gtk_item_factory_parse_rc (const gchar *file_name)
1491 g_return_if_fail (file_name != NULL);
1493 if (!S_ISREG (g_scanner_stat_mode (file_name)))
1496 fd = open (file_name, O_RDONLY);
1500 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1501 scanner = g_scanner_new (&ifactory_scanner_config);
1503 g_scanner_input_file (scanner, fd);
1505 gtk_item_factory_parse_rc_scanner (scanner);
1507 g_scanner_destroy (scanner);