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.
24 * Modified by the GTK+ Team and others 1997-1999. 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/.
30 #include "gtkitemfactory.h"
31 #include "gtk/gtksignal.h"
32 #include "gtk/gtkoptionmenu.h"
33 #include "gtk/gtkmenubar.h"
34 #include "gtk/gtkmenu.h"
35 #include "gtk/gtkmenuitem.h"
36 #include "gtk/gtkradiomenuitem.h"
37 #include "gtk/gtkcheckmenuitem.h"
38 #include "gtk/gtktearoffmenuitem.h"
39 #include "gtk/gtkaccellabel.h"
40 #include "gdk/gdkkeysyms.h"
50 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
51 #define ITEM_BLOCK_SIZE (128)
54 /* --- structures --- */
55 typedef struct _GtkIFCBData GtkIFCBData;
56 typedef struct _GtkIFActionLink GtkIFActionLink;
57 typedef struct _GtkIFDumpData GtkIFDumpData;
60 GtkItemFactoryCallback func;
63 guint callback_action;
65 struct _GtkIFActionLink
68 guint callback_action;
72 GtkPrintFunc print_func;
74 guint modified_only : 1;
75 GtkPatternSpec *pspec;
79 /* --- prototypes --- */
80 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
81 static void gtk_item_factory_init (GtkItemFactory *ifactory);
82 static void gtk_item_factory_destroy (GtkObject *object);
83 static void gtk_item_factory_finalize (GtkObject *object);
86 /* --- static variables --- */
87 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
88 static GtkObjectClass *parent_class = NULL;
89 static const gchar *item_factory_string = "Gtk-<ItemFactory>";
90 static GMemChunk *ifactory_item_chunks = NULL;
91 static GMemChunk *ifactory_cb_data_chunks = NULL;
92 static const gchar *key_popup_data = "GtkItemFactory-popup-data";
93 static GQuark quark_popup_data = 0;
94 static const gchar *key_if_menu_pos = "GtkItemFactory-menu-position";
95 static GQuark quark_if_menu_pos = 0;
96 static const gchar *key_item_factory = "GtkItemFactory";
97 static GQuark quark_item_factory = 0;
98 static const gchar *key_item_factory_path = "GtkItemFactory-path";
99 static GQuark quark_item_factory_path = 0;
100 static const gchar *key_type_item = "<Item>";
101 static GQuark quark_type_item = 0;
102 static const gchar *key_type_title = "<Title>";
103 static GQuark quark_type_title = 0;
104 static const gchar *key_type_radio_item = "<RadioItem>";
105 static GQuark quark_type_radio_item = 0;
106 static const gchar *key_type_check_item = "<CheckItem>";
107 static GQuark quark_type_check_item = 0;
108 static const gchar *key_type_toggle_item = "<ToggleItem>";
109 static GQuark quark_type_toggle_item = 0;
110 static const gchar *key_type_tearoff_item = "<Tearoff>";
111 static GQuark quark_type_tearoff_item = 0;
112 static const gchar *key_type_separator_item = "<Separator>";
113 static GQuark quark_type_separator_item = 0;
114 static const gchar *key_type_branch = "<Branch>";
115 static GQuark quark_type_branch = 0;
116 static const gchar *key_type_last_branch = "<LastBranch>";
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 GtkObjectClass *object_class;
192 gtk_item_factory_class = class;
194 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
196 object_class = (GtkObjectClass*) class;
198 object_class->destroy = gtk_item_factory_destroy;
199 object_class->finalize = gtk_item_factory_finalize;
201 class->cpair_comment_single = g_strdup (";\n");
203 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
204 ifactory_item_chunks =
205 g_mem_chunk_new ("GtkItemFactoryItem",
206 sizeof (GtkItemFactoryItem),
207 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
209 ifactory_cb_data_chunks =
210 g_mem_chunk_new ("GtkIFCBData",
211 sizeof (GtkIFCBData),
212 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
215 quark_popup_data = g_quark_from_static_string (key_popup_data);
216 quark_if_menu_pos = g_quark_from_static_string (key_if_menu_pos);
217 quark_item_factory = g_quark_from_static_string (key_item_factory);
218 quark_item_factory_path = g_quark_from_static_string (key_item_factory_path);
219 quark_type_item = g_quark_from_static_string (key_type_item);
220 quark_type_title = g_quark_from_static_string (key_type_title);
221 quark_type_radio_item = g_quark_from_static_string (key_type_radio_item);
222 quark_type_check_item = g_quark_from_static_string (key_type_check_item);
223 quark_type_toggle_item = g_quark_from_static_string (key_type_toggle_item);
224 quark_type_tearoff_item = g_quark_from_static_string (key_type_tearoff_item);
225 quark_type_separator_item = g_quark_from_static_string (key_type_separator_item);
226 quark_type_branch = g_quark_from_static_string (key_type_branch);
227 quark_type_last_branch = g_quark_from_static_string (key_type_last_branch);
231 gtk_item_factory_init (GtkItemFactory *ifactory)
235 object = GTK_OBJECT (ifactory);
237 ifactory->path = NULL;
238 ifactory->accel_group = NULL;
239 ifactory->widget = NULL;
240 ifactory->widgets_by_action = NULL;
244 gtk_item_factory_new (GtkType container_type,
246 GtkAccelGroup *accel_group)
248 GtkItemFactory *ifactory;
250 g_return_val_if_fail (path != NULL, NULL);
252 ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
253 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
259 gtk_item_factory_callback_marshal (GtkWidget *widget,
266 if (data->callback_type == 1)
268 GtkItemFactoryCallback1 func1 = data->func;
269 func1 (data->func_data, data->callback_action, widget);
271 else if (data->callback_type == 2)
273 GtkItemFactoryCallback2 func2 = data->func;
274 func2 (widget, data->func_data, data->callback_action);
279 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
285 if (item->in_propagation)
288 item->in_propagation = TRUE;
291 for (slist = item->widgets; slist; slist = slist->next)
295 widget = slist->data;
297 if (widget != exclude)
299 gtk_widget_ref (widget);
300 widget_list = g_slist_prepend (widget_list, widget);
304 for (slist = widget_list; slist; slist = slist->next)
307 GtkItemFactory *ifactory;
309 widget = slist->data;
311 ifactory = gtk_item_factory_from_widget (widget);
317 signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
320 if (item->accelerator_key)
321 gtk_widget_add_accelerator (widget,
323 ifactory->accel_group,
324 item->accelerator_key,
325 item->accelerator_mods,
331 work = gtk_accel_group_entries_from_object (GTK_OBJECT (widget));
334 GtkAccelEntry *ac_entry;
336 ac_entry = work->data;
338 if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
339 ac_entry->accel_group == ifactory->accel_group &&
340 ac_entry->signal_id == signal_id)
341 gtk_widget_remove_accelerator (GTK_WIDGET (widget),
342 ac_entry->accel_group,
343 ac_entry->accelerator_key,
344 ac_entry->accelerator_mods);
349 gtk_widget_unref (widget);
351 g_slist_free (widget_list);
353 item->in_propagation = FALSE;
357 gtk_item_factory_item_add_accelerator (GtkWidget *widget,
358 guint accel_signal_id,
359 GtkAccelGroup *accel_group,
362 GtkAccelFlags accel_flags,
363 GtkItemFactoryItem *item)
365 if (!item->in_propagation &&
366 g_slist_find (item->widgets, widget) &&
367 accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
369 item->accelerator_key = accel_key;
370 item->accelerator_mods = accel_mods;
371 item->modified = TRUE;
373 gtk_item_factory_propagate_accelerator (item, widget);
380 gtk_item_factory_item_remove_accelerator (GtkWidget *widget,
381 GtkAccelGroup *accel_group,
384 GtkItemFactoryItem *item)
386 if (!item->in_propagation &&
387 g_slist_find (item->widgets, widget) &&
388 item->accelerator_key == accel_key &&
389 item->accelerator_mods == accel_mods)
391 item->accelerator_key = 0;
392 item->accelerator_mods = 0;
393 item->modified = TRUE;
395 gtk_item_factory_propagate_accelerator (item, widget);
400 gtk_item_factory_item_remove_widget (GtkWidget *widget,
401 GtkItemFactoryItem *item)
403 item->widgets = g_slist_remove (item->widgets, widget);
404 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
405 gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
409 ifactory_cb_data_free (gpointer mem)
411 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
415 gtk_item_factory_add_item (GtkItemFactory *ifactory,
417 const gchar *accelerator,
418 GtkItemFactoryCallback callback,
419 guint callback_action,
420 gpointer callback_data,
425 GtkItemFactoryClass *class;
426 GtkItemFactoryItem *item;
429 g_return_if_fail (widget != NULL);
430 g_return_if_fail (item_type != NULL);
432 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
434 fpath = g_strconcat (ifactory->path, path, NULL);
435 item = g_hash_table_lookup (class->item_ht, fpath);
437 /* link the widget into its item-entry
445 gtk_accelerator_parse (accelerator, &keyval, &mods);
452 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
456 item->accelerator_key = keyval;
457 item->accelerator_mods = mods;
458 item->modified = FALSE;
459 item->in_propagation = FALSE;
460 item->item_type = NULL;
461 item->widgets = NULL;
463 g_hash_table_insert (class->item_ht, item->path, item);
467 if (item->item_type == NULL)
469 g_assert (item->widgets == NULL);
471 if (item_type != ITEM_FACTORY_STRING)
472 item->item_type = g_strdup (item_type);
474 item->item_type = ITEM_FACTORY_STRING;
477 item->widgets = g_slist_prepend (item->widgets, widget);
478 gtk_signal_connect (GTK_OBJECT (widget),
480 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
483 /* set back pointers for the widget
485 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
486 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory_path, item->path);
487 gtk_widget_set_name (widget, item->path);
489 /* set accelerator group on menu widgets
491 if (GTK_IS_MENU (widget))
492 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
494 /* install defined accelerators
496 if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
498 if (item->accelerator_key)
499 gtk_widget_add_accelerator (widget,
501 ifactory->accel_group,
502 item->accelerator_key,
503 item->accelerator_mods,
506 gtk_widget_remove_accelerators (widget,
511 /* keep track of accelerator changes
513 gtk_signal_connect_after (GTK_OBJECT (widget),
515 GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
517 gtk_signal_connect_after (GTK_OBJECT (widget),
518 "remove-accelerator",
519 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
522 /* keep a per-action list of the widgets on the factory
526 GtkIFActionLink *link;
528 link = g_new (GtkIFActionLink, 1);
529 link->widget = widget;
530 link->callback_action = callback_action;
531 ifactory->widgets_by_action = g_slist_prepend (ifactory->widgets_by_action, link);
534 /* connect callback if neccessary
540 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
541 data->func = callback;
542 data->callback_type = callback_type;
543 data->func_data = callback_data;
544 data->callback_action = callback_action;
546 gtk_object_weakref (GTK_OBJECT (widget),
547 ifactory_cb_data_free,
549 gtk_signal_connect (GTK_OBJECT (widget),
551 GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
557 gtk_item_factory_construct (GtkItemFactory *ifactory,
558 GtkType container_type,
560 GtkAccelGroup *accel_group)
562 GtkAccelGroup *menu_group;
565 g_return_if_fail (ifactory != NULL);
566 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
567 g_return_if_fail (ifactory->accel_group == NULL);
568 g_return_if_fail (path != NULL);
569 if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
570 g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
574 if (path[0] != '<' && path[len - 1] != '>')
576 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
582 ifactory->accel_group = accel_group;
583 gtk_accel_group_ref (ifactory->accel_group);
586 ifactory->accel_group = gtk_accel_group_new ();
588 ifactory->path = g_strdup (path);
590 gtk_widget_new (container_type,
591 "GtkObject::signal::destroy", gtk_widget_destroyed, &ifactory->widget,
593 gtk_object_ref (GTK_OBJECT (ifactory));
594 gtk_object_sink (GTK_OBJECT (ifactory));
596 menu_group = gtk_accel_group_new ();
597 gtk_accel_group_attach (menu_group, GTK_OBJECT (ifactory->widget));
600 gtk_signal_connect_object_while_alive (GTK_OBJECT (ifactory->widget),
602 GTK_SIGNAL_FUNC (gtk_object_destroy),
603 GTK_OBJECT (ifactory));
605 gtk_item_factory_add_item (ifactory,
613 gtk_item_factory_from_path (const gchar *path)
615 GtkItemFactoryClass *class;
616 GtkItemFactoryItem *item;
620 g_return_val_if_fail (path != NULL, NULL);
621 g_return_val_if_fail (path[0] == '<', NULL);
623 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
626 while (path[i] && path[i] != '>')
630 g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
634 fname = g_new (gchar, i + 2);
635 g_memmove (fname, path, i + 1);
638 item = g_hash_table_lookup (class->item_ht, fname);
642 if (item && item->widgets)
643 return gtk_item_factory_from_widget (item->widgets->data);
649 gtk_item_factory_destroy (GtkObject *object)
651 GtkItemFactory *ifactory;
654 g_return_if_fail (object != NULL);
655 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
657 ifactory = (GtkItemFactory*) object;
659 if (ifactory->widget)
663 dobj = GTK_OBJECT (ifactory->widget);
665 gtk_object_ref (dobj);
666 gtk_object_sink (dobj);
667 gtk_object_destroy (dobj);
668 gtk_object_unref (dobj);
670 ifactory->widget = NULL;
673 for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
674 g_free (slist->data);
675 g_slist_free (ifactory->widgets_by_action);
676 ifactory->widgets_by_action = NULL;
678 parent_class->destroy (object);
682 gtk_item_factory_finalize (GtkObject *object)
684 GtkItemFactory *ifactory;
686 g_return_if_fail (object != NULL);
687 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
689 ifactory = GTK_ITEM_FACTORY (object);
691 gtk_accel_group_unref (ifactory->accel_group);
692 g_free (ifactory->path);
693 g_assert (ifactory->widget == NULL);
695 if (ifactory->translate_data && ifactory->translate_notify)
696 ifactory->translate_notify (ifactory->translate_data);
698 parent_class->finalize (object);
702 gtk_item_factory_from_widget (GtkWidget *widget)
704 g_return_val_if_fail (widget != NULL, NULL);
705 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
707 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
711 gtk_item_factory_path_from_widget (GtkWidget *widget)
713 g_return_val_if_fail (widget != NULL, NULL);
714 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
716 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
720 gtk_item_factory_foreach (gpointer hash_key,
724 GtkItemFactoryItem *item;
728 gchar comment_prefix[2] = "\000\000";
733 if (data->pspec && !gtk_pattern_match_string (data->pspec, item->path))
736 comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
738 name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
739 string = g_strconcat (item->modified ? "" : comment_prefix,
748 data->print_func (data->func_data, string);
754 gtk_item_factory_dump_items (GtkPatternSpec *path_pspec,
755 gboolean modified_only,
756 GtkPrintFunc print_func,
761 g_return_if_fail (print_func != NULL);
763 if (!gtk_item_factory_class)
764 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
766 data.print_func = print_func;
767 data.func_data = func_data;
768 data.modified_only = (modified_only != FALSE);
769 data.pspec = path_pspec;
771 g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
775 gtk_item_factory_print_func (gpointer FILE_pointer,
778 FILE *f_out = FILE_pointer;
780 g_return_if_fail (FILE_pointer != NULL);
781 g_return_if_fail (string != NULL);
783 fputs (string, f_out);
788 gtk_item_factory_dump_rc (const gchar *file_name,
789 GtkPatternSpec *path_pspec,
790 gboolean modified_only)
794 g_return_if_fail (file_name != NULL);
796 f_out = fopen (file_name, "w");
801 if (g_get_prgname ())
802 fputs (g_get_prgname (), f_out);
803 fputs (" GtkItemFactory rc-file -*- scheme -*-\n", f_out);
804 fputs ("; this file is an automated menu-path dump\n", f_out);
805 fputs (";\n", f_out);
807 gtk_item_factory_dump_items (path_pspec,
809 gtk_item_factory_print_func,
816 gtk_item_factory_create_items (GtkItemFactory *ifactory,
818 GtkItemFactoryEntry *entries,
819 gpointer callback_data)
821 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
825 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
827 GtkItemFactoryEntry *entries,
828 gpointer callback_data,
833 g_return_if_fail (ifactory != NULL);
834 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
835 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
840 g_return_if_fail (entries != NULL);
842 for (i = 0; i < n_entries; i++)
843 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
847 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
850 GtkItemFactoryClass *class;
851 GtkItemFactoryItem *item;
853 g_return_val_if_fail (ifactory != NULL, NULL);
854 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
855 g_return_val_if_fail (path != NULL, NULL);
857 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
860 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
865 fpath = g_strconcat (ifactory->path, path, NULL);
866 item = g_hash_table_lookup (class->item_ht, fpath);
874 for (slist = item->widgets; slist; slist = slist->next)
876 if (gtk_item_factory_from_widget (slist->data) == ifactory)
885 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
890 g_return_val_if_fail (ifactory != NULL, NULL);
891 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
893 for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
895 GtkIFActionLink *link;
899 if (link->callback_action == action)
907 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
916 *path = g_strdup (str);
929 *parent_path = g_strdup (*path);
930 p = strrchr (*parent_path, '/');
933 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
938 if (ifactory->translate_func)
939 translation = ifactory->translate_func (str, ifactory->translate_data);
943 p = strrchr (translation, '/');
946 *item = g_strdup (p);
952 gtk_item_factory_create_item (GtkItemFactory *ifactory,
953 GtkItemFactoryEntry *entry,
954 gpointer callback_data,
966 gchar *item_type_path;
967 GtkAccelGroup *parent_accel_group = NULL;
970 g_return_if_fail (ifactory != NULL);
971 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
972 g_return_if_fail (entry != NULL);
973 g_return_if_fail (entry->path != NULL);
974 g_return_if_fail (entry->path[0] == '/');
975 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
977 if (!entry->item_type ||
978 entry->item_type[0] == 0)
980 item_type_path = (gpointer) key_type_item;
981 type_id = quark_type_item;
985 item_type_path = entry->item_type;
986 type_id = gtk_object_data_try_key (item_type_path);
990 if (type_id == quark_type_item)
991 type = GTK_TYPE_MENU_ITEM;
992 else if (type_id == quark_type_title)
993 type = GTK_TYPE_MENU_ITEM;
994 else if (type_id == quark_type_radio_item)
995 type = GTK_TYPE_RADIO_MENU_ITEM;
996 else if (type_id == quark_type_check_item)
997 type = GTK_TYPE_CHECK_MENU_ITEM;
998 else if (type_id == quark_type_tearoff_item)
999 type = GTK_TYPE_TEAROFF_MENU_ITEM;
1000 else if (type_id == quark_type_toggle_item)
1001 type = GTK_TYPE_CHECK_MENU_ITEM;
1002 else if (type_id == quark_type_separator_item)
1003 type = GTK_TYPE_MENU_ITEM;
1004 else if (type_id == quark_type_branch)
1005 type = GTK_TYPE_MENU_ITEM;
1006 else if (type_id == quark_type_last_branch)
1007 type = GTK_TYPE_MENU_ITEM;
1010 GtkWidget *radio_link;
1012 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
1013 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
1015 type = GTK_TYPE_RADIO_MENU_ITEM;
1016 radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
1020 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1027 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1028 &path, &parent_path, &name))
1031 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1034 GtkItemFactoryEntry pentry;
1037 ppath = g_strdup (entry->path);
1038 p = strrchr (ppath, '/');
1039 g_return_if_fail (p != NULL);
1041 pentry.path = ppath;
1042 pentry.accelerator = NULL;
1043 pentry.callback = NULL;
1044 pentry.callback_action = 0;
1045 pentry.item_type = "<Branch>";
1047 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1050 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1051 g_return_if_fail (parent != NULL);
1053 g_free (parent_path);
1055 g_return_if_fail (parent != NULL);
1057 tmp_list = gtk_accel_groups_from_object (GTK_OBJECT (parent));
1059 parent_accel_group = tmp_list->data;
1061 widget = gtk_widget_new (type,
1062 "GtkWidget::visible", TRUE,
1063 "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
1064 type_id != quark_type_title),
1065 "GtkWidget::parent", parent,
1068 if (type == GTK_TYPE_RADIO_MENU_ITEM)
1069 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1070 if (GTK_IS_CHECK_MENU_ITEM (widget))
1071 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
1073 if ((type_id != quark_type_separator_item) &&
1074 (type_id != quark_type_tearoff_item) &&
1080 gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1081 "GtkWidget::visible", TRUE,
1082 "GtkWidget::parent", widget,
1083 "GtkAccelLabel::accel_widget", widget,
1084 "GtkMisc::xalign", 0.0,
1087 accel_key = gtk_label_parse_uline (GTK_LABEL (label), name);
1089 if ((accel_key != GDK_VoidSymbol) && GTK_IS_MENU_BAR (parent))
1091 gtk_widget_add_accelerator (widget,
1093 ifactory->accel_group,
1094 accel_key, GDK_MOD1_MASK,
1098 if ((accel_key != GDK_VoidSymbol) && parent_accel_group)
1100 gtk_widget_add_accelerator (widget,
1110 if (type_id == quark_type_branch ||
1111 type_id == quark_type_last_branch)
1113 GtkAccelGroup *menu_group;
1115 if (entry->callback)
1116 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1119 menu_group = gtk_accel_group_new ();
1121 if (type_id == quark_type_last_branch)
1122 gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1126 gtk_widget_new (GTK_TYPE_MENU,
1129 gtk_accel_group_attach (menu_group, GTK_OBJECT (widget));
1130 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1133 gtk_item_factory_add_item (ifactory,
1134 path, entry->accelerator,
1135 (type_id == quark_type_branch ||
1136 type_id == quark_type_last_branch) ?
1137 (GtkItemFactoryCallback) NULL : entry->callback,
1138 entry->callback_action, callback_data,
1147 gtk_item_factory_create_menu_entries (guint n_entries,
1148 GtkMenuEntry *entries)
1150 static GtkPatternSpec pspec_separator = { 42, 0 };
1151 static GtkPatternSpec pspec_check = { 42, 0 };
1156 g_return_if_fail (entries != NULL);
1158 if (pspec_separator.pattern_length == 0)
1160 gtk_pattern_spec_init (&pspec_separator, "*<separator>*");
1161 gtk_pattern_spec_init (&pspec_check, "*<check>*");
1164 for (i = 0; i < n_entries; i++)
1166 GtkItemFactory *ifactory;
1167 GtkItemFactoryEntry entry;
1171 path = entries[i].path;
1172 ifactory = gtk_item_factory_from_path (path);
1175 g_warning ("gtk_item_factory_create_menu_entries(): "
1176 "entry[%u] refers to unknown item factory: \"%s\"",
1177 i, entries[i].path);
1181 while (*path != '>')
1187 entry.accelerator = entries[i].accelerator;
1188 entry.callback = entries[i].callback;
1189 entry.callback_action = 0;
1190 if (gtk_pattern_match_string (&pspec_separator, path))
1191 entry.item_type = (gpointer) key_type_separator_item;
1192 else if (!gtk_pattern_match_string (&pspec_check, path))
1193 entry.item_type = NULL;
1196 gboolean in_brace = FALSE;
1199 cpath = g_new (gchar, strlen (path));
1205 else if (*path == '>')
1212 entry.item_type = (gpointer) key_type_toggle_item;
1216 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1217 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1223 gtk_item_factories_path_delete (const gchar *ifactory_path,
1226 GtkItemFactoryClass *class;
1227 GtkItemFactoryItem *item;
1229 g_return_if_fail (path != NULL);
1231 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1234 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1239 g_return_if_fail (ifactory_path != NULL);
1241 fpath = g_strconcat (ifactory_path, path, NULL);
1242 item = g_hash_table_lookup (class->item_ht, fpath);
1248 GSList *widget_list;
1252 for (slist = item->widgets; slist; slist = slist->next)
1256 widget = slist->data;
1257 widget_list = g_slist_prepend (widget_list, widget);
1258 gtk_widget_ref (widget);
1261 for (slist = widget_list; slist; slist = slist->next)
1265 widget = slist->data;
1266 gtk_widget_destroy (widget);
1267 gtk_widget_unref (widget);
1269 g_slist_free (widget_list);
1274 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1277 GtkItemFactoryClass *class;
1278 GtkItemFactoryItem *item;
1281 g_return_if_fail (ifactory != NULL);
1282 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1283 g_return_if_fail (path != NULL);
1285 class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
1287 fpath = g_strconcat (ifactory->path, path, NULL);
1288 item = g_hash_table_lookup (class->item_ht, fpath);
1293 GtkWidget *widget = NULL;
1296 for (slist = item->widgets; slist; slist = slist->next)
1298 widget = slist->data;
1300 if (gtk_item_factory_from_widget (widget) == ifactory)
1305 gtk_widget_destroy (widget);
1310 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1311 GtkItemFactoryEntry *entry)
1313 g_return_if_fail (ifactory != NULL);
1314 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1315 g_return_if_fail (entry != NULL);
1317 gtk_item_factory_delete_item (ifactory, entry->path);
1321 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1323 GtkItemFactoryEntry *entries)
1327 g_return_if_fail (ifactory != NULL);
1328 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1330 g_return_if_fail (entries != NULL);
1332 for (i = 0; i < n_entries; i++)
1333 gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1343 gtk_item_factory_menu_pos (GtkMenu *menu,
1348 MenuPos *mpos = func_data;
1355 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1357 GtkItemFactory *ifactory;
1359 g_return_val_if_fail (widget != NULL, NULL);
1360 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1362 ifactory = gtk_item_factory_from_widget (widget);
1364 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1370 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1372 g_return_val_if_fail (ifactory != NULL, NULL);
1373 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1375 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1379 ifactory_delete_popup_data (GtkObject *object,
1380 GtkItemFactory *ifactory)
1382 gtk_signal_disconnect_by_func (object,
1383 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1385 gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1389 gtk_item_factory_popup (GtkItemFactory *ifactory,
1395 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1399 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1400 gpointer popup_data,
1401 GtkDestroyNotify destroy,
1407 g_return_if_fail (ifactory != NULL);
1408 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1409 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1411 if (!GTK_WIDGET_VISIBLE (ifactory->widget))
1415 mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1419 mpos = g_new0 (MenuPos, 1);
1420 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1429 if (popup_data != NULL)
1431 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1435 gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1437 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1441 gtk_menu_popup (GTK_MENU (ifactory->widget),
1443 gtk_item_factory_menu_pos, mpos,
1444 mouse_button, time);
1449 gtk_item_factory_parse_menu_path (GScanner *scanner,
1450 GtkItemFactoryClass *class)
1452 GtkItemFactoryItem *item;
1454 g_scanner_get_next_token (scanner);
1455 if (scanner->token != G_TOKEN_STRING)
1456 return G_TOKEN_STRING;
1458 g_scanner_peek_next_token (scanner);
1459 if (scanner->next_token != G_TOKEN_STRING)
1461 g_scanner_get_next_token (scanner);
1462 return G_TOKEN_STRING;
1465 item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1468 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1470 item->path = g_strdup (scanner->value.v_string);
1471 item->accelerator_key = 0;
1472 item->accelerator_mods = 0;
1473 item->modified = TRUE;
1474 item->in_propagation = FALSE;
1475 item->item_type = NULL;
1476 item->widgets = NULL;
1478 g_hash_table_insert (class->item_ht, item->path, item);
1480 g_scanner_get_next_token (scanner);
1482 if (!item->in_propagation)
1487 old_keyval = item->accelerator_key;
1488 old_mods = item->accelerator_mods;
1489 gtk_accelerator_parse (scanner->value.v_string,
1490 &item->accelerator_key,
1491 &item->accelerator_mods);
1492 if (old_keyval != item->accelerator_key ||
1493 old_mods != item->accelerator_mods)
1495 item->modified = TRUE;
1496 gtk_item_factory_propagate_accelerator (item, NULL);
1500 g_scanner_get_next_token (scanner);
1501 if (scanner->token != ')')
1504 return G_TOKEN_NONE;
1508 gtk_item_factory_parse_statement (GScanner *scanner,
1509 GtkItemFactoryClass *class)
1511 guint expected_token;
1513 g_scanner_get_next_token (scanner);
1515 if (scanner->token == G_TOKEN_SYMBOL)
1517 guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1519 parser_func = scanner->value.v_symbol;
1521 /* check whether this is a GtkItemFactory symbol.
1523 if (parser_func == gtk_item_factory_parse_menu_path)
1524 expected_token = parser_func (scanner, class);
1526 expected_token = G_TOKEN_SYMBOL;
1529 expected_token = G_TOKEN_SYMBOL;
1531 /* skip rest of statement on errrors
1533 if (expected_token != G_TOKEN_NONE)
1535 register guint level;
1538 if (scanner->token == ')')
1540 if (scanner->token == '(')
1543 while (!g_scanner_eof (scanner) && level > 0)
1545 g_scanner_get_next_token (scanner);
1547 if (scanner->token == '(')
1549 else if (scanner->token == ')')
1556 gtk_item_factory_parse_rc_string (const gchar *rc_string)
1560 g_return_if_fail (rc_string != NULL);
1562 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1563 scanner = g_scanner_new (&ifactory_scanner_config);
1565 g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1567 gtk_item_factory_parse_rc_scanner (scanner);
1569 g_scanner_destroy (scanner);
1573 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1575 gpointer saved_symbol;
1577 g_return_if_fail (scanner != NULL);
1579 if (!gtk_item_factory_class)
1580 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1582 saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1583 g_scanner_remove_symbol (scanner, "menu-path");
1584 g_scanner_add_symbol (scanner, "menu-path", gtk_item_factory_parse_menu_path);
1586 g_scanner_peek_next_token (scanner);
1588 while (scanner->next_token == '(')
1590 g_scanner_get_next_token (scanner);
1592 gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1594 g_scanner_peek_next_token (scanner);
1597 g_scanner_remove_symbol (scanner, "menu-path");
1598 g_scanner_add_symbol (scanner, "menu-path", saved_symbol);
1602 gtk_item_factory_parse_rc (const gchar *file_name)
1607 g_return_if_fail (file_name != NULL);
1609 if (!S_ISREG (g_scanner_stat_mode (file_name)))
1612 fd = open (file_name, O_RDONLY);
1616 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1617 scanner = g_scanner_new (&ifactory_scanner_config);
1619 g_scanner_input_file (scanner, fd);
1621 gtk_item_factory_parse_rc_scanner (scanner);
1623 g_scanner_destroy (scanner);
1629 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1630 GtkTranslateFunc func,
1632 GtkDestroyNotify notify)
1634 g_return_if_fail (ifactory != NULL);
1636 if (ifactory->translate_data && ifactory->translate_notify)
1637 ifactory->translate_notify (ifactory->translate_data);
1639 ifactory->translate_func = func;
1640 ifactory->translate_data = data;
1641 ifactory->translate_notify = notify;