1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkItemFactory: Flexible item factory with automatic rc handling
5 * Copyright (C) 1998 Tim Janik
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
25 * file for a list of people on the GTK+ Team. See the ChangeLog
26 * files for a list of changes. These files are distributed with
27 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
32 #include "gtkitemfactory.h"
33 #include "gtk/gtksignal.h"
34 #include "gtk/gtkoptionmenu.h"
35 #include "gtk/gtkmenubar.h"
36 #include "gtk/gtkmenu.h"
37 #include "gtk/gtkmenuitem.h"
38 #include "gtk/gtkradiomenuitem.h"
39 #include "gtk/gtkcheckmenuitem.h"
40 #include "gtk/gtktearoffmenuitem.h"
41 #include "gtk/gtkaccellabel.h"
42 #include "gdk/gdkkeysyms.h"
52 #include <io.h> /* For _open and _close */
55 #define S_ISREG(mode) ((mode)&_S_IFREG)
61 #define ITEM_FACTORY_STRING ((gchar*) item_factory_string)
62 #define ITEM_BLOCK_SIZE (128)
65 /* --- structures --- */
66 typedef struct _GtkIFCBData GtkIFCBData;
67 typedef struct _GtkIFDumpData GtkIFDumpData;
70 GtkItemFactoryCallback func;
73 guint callback_action;
77 GtkPrintFunc print_func;
79 guint modified_only : 1;
80 GtkPatternSpec *pspec;
84 /* --- prototypes --- */
85 static void gtk_item_factory_class_init (GtkItemFactoryClass *klass);
86 static void gtk_item_factory_init (GtkItemFactory *ifactory);
87 static void gtk_item_factory_destroy (GtkObject *object);
88 static void gtk_item_factory_finalize (GObject *object);
91 /* --- static variables --- */
92 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
93 static gpointer parent_class = NULL;
94 static const gchar *item_factory_string = "Gtk-<ItemFactory>";
95 static GMemChunk *ifactory_item_chunks = NULL;
96 static GMemChunk *ifactory_cb_data_chunks = NULL;
97 static GQuark quark_popup_data = 0;
98 static GQuark quark_if_menu_pos = 0;
99 static GQuark quark_item_factory = 0;
100 static GQuark quark_item_path = 0;
101 static GQuark quark_action = 0;
102 static GQuark quark_accel_group = 0;
103 static GQuark quark_type_item = 0;
104 static GQuark quark_type_title = 0;
105 static GQuark quark_type_radio_item = 0;
106 static GQuark quark_type_check_item = 0;
107 static GQuark quark_type_toggle_item = 0;
108 static GQuark quark_type_tearoff_item = 0;
109 static GQuark quark_type_separator_item = 0;
110 static GQuark quark_type_branch = 0;
111 static GQuark quark_type_last_branch = 0;
112 static GScannerConfig ifactory_scanner_config =
116 ) /* cset_skip_characters */,
121 ) /* cset_identifier_first */,
128 ) /* cset_identifier_nth */,
129 ( ";\n" ) /* cpair_comment_single */,
131 FALSE /* case_sensitive */,
133 TRUE /* skip_comment_multi */,
134 TRUE /* skip_comment_single */,
135 FALSE /* scan_comment_multi */,
136 TRUE /* scan_identifier */,
137 FALSE /* scan_identifier_1char */,
138 FALSE /* scan_identifier_NULL */,
139 TRUE /* scan_symbols */,
140 TRUE /* scan_binary */,
141 TRUE /* scan_octal */,
142 TRUE /* scan_float */,
144 FALSE /* scan_hex_dollar */,
145 TRUE /* scan_string_sq */,
146 TRUE /* scan_string_dq */,
147 TRUE /* numbers_2_int */,
148 FALSE /* int_2_float */,
149 FALSE /* identifier_2_string */,
150 TRUE /* char_2_token */,
151 FALSE /* symbol_2_token */,
155 /* --- functions --- */
157 gtk_item_factory_get_type (void)
159 static GtkType item_factory_type = 0;
161 if (!item_factory_type)
163 static const GtkTypeInfo item_factory_info =
166 sizeof (GtkItemFactory),
167 sizeof (GtkItemFactoryClass),
168 (GtkClassInitFunc) gtk_item_factory_class_init,
169 (GtkObjectInitFunc) gtk_item_factory_init,
170 /* reserved_1 */ NULL,
171 /* reserved_2 */ NULL,
172 (GtkClassInitFunc) NULL,
175 item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
178 return item_factory_type;
182 gtk_item_factory_class_init (GtkItemFactoryClass *class)
184 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
185 GtkObjectClass *object_class;
187 gtk_item_factory_class = class;
189 parent_class = gtk_type_class (GTK_TYPE_OBJECT);
191 object_class = (GtkObjectClass*) class;
193 gobject_class->finalize = gtk_item_factory_finalize;
195 object_class->destroy = gtk_item_factory_destroy;
197 class->cpair_comment_single = g_strdup (";\n");
199 class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
201 ifactory_item_chunks =
202 g_mem_chunk_new ("GtkItemFactoryItem",
203 sizeof (GtkItemFactoryItem),
204 sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
206 ifactory_cb_data_chunks =
207 g_mem_chunk_new ("GtkIFCBData",
208 sizeof (GtkIFCBData),
209 sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
212 quark_popup_data = g_quark_from_static_string ("GtkItemFactory-popup-data");
213 quark_if_menu_pos = g_quark_from_static_string ("GtkItemFactory-menu-position");
214 quark_item_factory = g_quark_from_static_string ("GtkItemFactory");
215 quark_item_path = g_quark_from_static_string ("GtkItemFactory-path");
216 quark_action = g_quark_from_static_string ("GtkItemFactory-action");
217 quark_accel_group = g_quark_from_static_string ("GtkAccelGroup");
218 quark_type_item = g_quark_from_static_string ("<Item>");
219 quark_type_title = g_quark_from_static_string ("<Title>");
220 quark_type_radio_item = g_quark_from_static_string ("<RadioItem>");
221 quark_type_check_item = g_quark_from_static_string ("<CheckItem>");
222 quark_type_toggle_item = g_quark_from_static_string ("<ToggleItem>");
223 quark_type_tearoff_item = g_quark_from_static_string ("<Tearoff>");
224 quark_type_separator_item = g_quark_from_static_string ("<Separator>");
225 quark_type_branch = g_quark_from_static_string ("<Branch>");
226 quark_type_last_branch = g_quark_from_static_string ("<LastBranch>");
230 gtk_item_factory_init (GtkItemFactory *ifactory)
234 object = GTK_OBJECT (ifactory);
236 ifactory->path = NULL;
237 ifactory->accel_group = NULL;
238 ifactory->widget = NULL;
239 ifactory->items = NULL;
240 ifactory->translate_func = NULL;
241 ifactory->translate_data = NULL;
242 ifactory->translate_notify = NULL;
246 gtk_item_factory_new (GtkType container_type,
248 GtkAccelGroup *accel_group)
250 GtkItemFactory *ifactory;
252 g_return_val_if_fail (path != NULL, NULL);
254 ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
255 gtk_item_factory_construct (ifactory, container_type, path, accel_group);
261 gtk_item_factory_callback_marshal (GtkWidget *widget,
268 if (data->callback_type == 1)
270 GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
271 func1 (data->func_data, data->callback_action, widget);
273 else if (data->callback_type == 2)
275 GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
276 func2 (widget, data->func_data, data->callback_action);
281 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
287 if (item->in_propagation)
290 item->in_propagation = TRUE;
293 for (slist = item->widgets; slist; slist = slist->next)
297 widget = slist->data;
299 if (widget != exclude)
301 gtk_widget_ref (widget);
302 widget_list = g_slist_prepend (widget_list, widget);
306 for (slist = widget_list; slist; slist = slist->next)
309 GtkAccelGroup *accel_group;
312 widget = slist->data;
314 accel_group = gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_accel_group);
316 signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
317 if (signal_id && accel_group)
319 if (item->accelerator_key)
320 gtk_widget_add_accelerator (widget,
323 item->accelerator_key,
324 item->accelerator_mods,
330 work = gtk_accel_group_entries_from_object (GTK_OBJECT (widget));
333 GtkAccelEntry *ac_entry;
335 ac_entry = work->data;
337 if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
338 ac_entry->accel_group == accel_group &&
339 ac_entry->signal_id == signal_id)
340 gtk_widget_remove_accelerator (GTK_WIDGET (widget),
341 ac_entry->accel_group,
342 ac_entry->accelerator_key,
343 ac_entry->accelerator_mods);
348 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_path);
409 gtk_item_factory_add_foreign (GtkWidget *accel_widget,
410 const gchar *full_path,
411 GtkAccelGroup *accel_group,
413 GdkModifierType modifiers)
415 GtkItemFactoryClass *class;
416 GtkItemFactoryItem *item;
418 g_return_if_fail (GTK_IS_WIDGET (accel_widget));
419 g_return_if_fail (full_path != NULL);
421 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
423 keyval = keyval != GDK_VoidSymbol ? keyval : 0;
425 item = g_hash_table_lookup (class->item_ht, full_path);
428 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
430 item->path = g_strdup (full_path);
431 item->accelerator_key = keyval;
432 item->accelerator_mods = modifiers;
433 item->modified = FALSE;
434 item->in_propagation = FALSE;
436 item->widgets = NULL;
438 g_hash_table_insert (class->item_ht, item->path, item);
441 item->widgets = g_slist_prepend (item->widgets, accel_widget);
442 gtk_signal_connect (GTK_OBJECT (accel_widget),
444 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
447 /* set the item path for the widget
449 gtk_object_set_data_by_id (GTK_OBJECT (accel_widget), quark_item_path, item->path);
450 gtk_widget_set_name (accel_widget, item->path);
453 gtk_accel_group_ref (accel_group);
454 gtk_object_set_data_by_id_full (GTK_OBJECT (accel_widget),
457 (GtkDestroyNotify) gtk_accel_group_unref);
460 gtk_object_set_data_by_id (GTK_OBJECT (accel_widget), quark_accel_group, NULL);
462 /* install defined accelerators
464 if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (accel_widget)))
466 if (item->accelerator_key && accel_group)
467 gtk_widget_add_accelerator (accel_widget,
470 item->accelerator_key,
471 item->accelerator_mods,
474 gtk_widget_remove_accelerators (accel_widget,
479 /* keep track of accelerator changes
481 gtk_signal_connect_after (GTK_OBJECT (accel_widget),
483 GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
485 gtk_signal_connect_after (GTK_OBJECT (accel_widget),
486 "remove-accelerator",
487 GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
492 ifactory_cb_data_free (gpointer mem)
494 g_mem_chunk_free (ifactory_cb_data_chunks, mem);
498 gtk_item_factory_add_item (GtkItemFactory *ifactory,
500 const gchar *accelerator,
501 GtkItemFactoryCallback callback,
502 guint callback_action,
503 gpointer callback_data,
508 GtkItemFactoryClass *class;
509 GtkItemFactoryItem *item;
513 g_return_if_fail (widget != NULL);
514 g_return_if_fail (item_type != NULL);
516 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
518 /* set accelerator group on menu widgets
520 if (GTK_IS_MENU (widget))
521 gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
523 /* connect callback if neccessary
529 data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
530 data->func = callback;
531 data->callback_type = callback_type;
532 data->func_data = callback_data;
533 data->callback_action = callback_action;
535 gtk_object_weakref (GTK_OBJECT (widget),
536 ifactory_cb_data_free,
538 gtk_signal_connect (GTK_OBJECT (widget),
540 GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
544 /* link the widget into its item-entry
545 * and keep back pointer on both the item factory and the widget
547 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
548 gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
550 gtk_accelerator_parse (accelerator, &keyval, &mods);
556 fpath = g_strconcat (ifactory->path, path, NULL);
557 gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
558 item = g_hash_table_lookup (class->item_ht, fpath);
561 g_return_if_fail (item != NULL);
563 if (!g_slist_find (ifactory->items, item))
564 ifactory->items = g_slist_prepend (ifactory->items, item);
568 gtk_item_factory_construct (GtkItemFactory *ifactory,
569 GtkType container_type,
571 GtkAccelGroup *accel_group)
575 g_return_if_fail (ifactory != NULL);
576 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
577 g_return_if_fail (ifactory->accel_group == NULL);
578 g_return_if_fail (path != NULL);
579 if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
580 g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
584 if (path[0] != '<' && path[len - 1] != '>')
586 g_warning ("GtkItemFactory: invalid factory path `%s'", path);
592 ifactory->accel_group = accel_group;
593 gtk_accel_group_ref (ifactory->accel_group);
596 ifactory->accel_group = gtk_accel_group_new ();
598 ifactory->path = g_strdup (path);
599 ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
600 "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
602 gtk_object_ref (GTK_OBJECT (ifactory));
603 gtk_object_sink (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->items; slist; slist = slist->next)
675 GtkItemFactoryItem *item = slist->data;
678 for (link = item->widgets; link; link = link->next)
679 if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory)
680 gtk_object_remove_data_by_id (link->data, quark_item_factory);
682 g_slist_free (ifactory->items);
683 ifactory->items = NULL;
685 GTK_OBJECT_CLASS (parent_class)->destroy (object);
689 gtk_item_factory_finalize (GObject *object)
691 GtkItemFactory *ifactory;
693 g_return_if_fail (object != NULL);
694 g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
696 ifactory = GTK_ITEM_FACTORY (object);
698 gtk_accel_group_unref (ifactory->accel_group);
699 g_free (ifactory->path);
700 g_assert (ifactory->widget == NULL);
702 if (ifactory->translate_notify)
703 ifactory->translate_notify (ifactory->translate_data);
705 G_OBJECT_CLASS (parent_class)->finalize (object);
709 gtk_item_factory_from_widget (GtkWidget *widget)
711 g_return_val_if_fail (widget != NULL, NULL);
712 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
714 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
718 gtk_item_factory_path_from_widget (GtkWidget *widget)
720 g_return_val_if_fail (widget != NULL, NULL);
721 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
723 return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_path);
727 item_factory_escape_path (const gchar *path)
729 GString *str = g_string_new (NULL);
738 g_string_append (str, "\\n");
741 g_string_append (str, "\\r");
745 g_string_append_c (str, '\\');
748 g_string_append_c (str, c);
754 return g_string_free (str, FALSE);
758 gtk_item_factory_foreach (gpointer hash_key,
762 GtkItemFactoryItem *item;
767 gchar comment_prefix[2] = "\000\000";
772 if (data->pspec && !gtk_pattern_match_string (data->pspec, item->path))
775 comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
777 path = item_factory_escape_path (hash_key);
778 name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
779 string = g_strconcat (item->modified ? "" : comment_prefix,
789 data->print_func (data->func_data, string);
795 gtk_item_factory_dump_items (GtkPatternSpec *path_pspec,
796 gboolean modified_only,
797 GtkPrintFunc print_func,
802 g_return_if_fail (print_func != NULL);
804 if (!gtk_item_factory_class)
805 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
807 data.print_func = print_func;
808 data.func_data = func_data;
809 data.modified_only = (modified_only != FALSE);
810 data.pspec = path_pspec;
812 g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
816 gtk_item_factory_print_func (gpointer FILE_pointer,
819 FILE *f_out = FILE_pointer;
821 g_return_if_fail (FILE_pointer != NULL);
822 g_return_if_fail (string != NULL);
824 fputs (string, f_out);
829 gtk_item_factory_dump_rc (const gchar *file_name,
830 GtkPatternSpec *path_pspec,
831 gboolean modified_only)
835 g_return_if_fail (file_name != NULL);
837 f_out = fopen (file_name, "w");
842 if (g_get_prgname ())
843 fputs (g_get_prgname (), f_out);
844 fputs (" GtkItemFactory rc-file -*- scheme -*-\n", f_out);
845 fputs ("; this file is an automated menu-path dump\n", f_out);
846 fputs (";\n", f_out);
848 gtk_item_factory_dump_items (path_pspec,
850 gtk_item_factory_print_func,
857 gtk_item_factory_create_items (GtkItemFactory *ifactory,
859 GtkItemFactoryEntry *entries,
860 gpointer callback_data)
862 gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
866 gtk_item_factory_create_items_ac (GtkItemFactory *ifactory,
868 GtkItemFactoryEntry *entries,
869 gpointer callback_data,
874 g_return_if_fail (ifactory != NULL);
875 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
876 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
881 g_return_if_fail (entries != NULL);
883 for (i = 0; i < n_entries; i++)
884 gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
888 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
891 GtkItemFactoryClass *class;
892 GtkItemFactoryItem *item;
894 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
895 g_return_val_if_fail (path != NULL, NULL);
897 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
900 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
905 fpath = g_strconcat (ifactory->path, path, NULL);
906 item = g_hash_table_lookup (class->item_ht, fpath);
914 for (slist = item->widgets; slist; slist = slist->next)
916 if (gtk_item_factory_from_widget (slist->data) == ifactory)
925 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
930 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
932 for (slist = ifactory->items; slist; slist = slist->next)
934 GtkItemFactoryItem *item = slist->data;
937 for (link = item->widgets; link; link = link->next)
938 if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory &&
939 gtk_object_get_data_by_id (link->data, quark_action) == GUINT_TO_POINTER (action))
947 gtk_item_factory_get_item (GtkItemFactory *ifactory,
952 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
953 g_return_val_if_fail (path != NULL, NULL);
955 widget = gtk_item_factory_get_widget (ifactory, path);
957 if (GTK_IS_MENU (widget))
958 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
960 return GTK_IS_ITEM (widget) ? widget : NULL;
964 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
969 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
971 widget = gtk_item_factory_get_widget_by_action (ifactory, action);
973 if (GTK_IS_MENU (widget))
974 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
976 return GTK_IS_ITEM (widget) ? widget : NULL;
980 item_factory_find_separator_r (char *path)
982 gchar *result = NULL;
983 gboolean escaped = FALSE;
993 else if (*path == '/')
1004 item_factory_unescape_label (const char *label)
1006 char *new = g_malloc (strlen (label) + 1);
1008 gboolean escaped = FALSE;
1034 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
1037 gchar **parent_path,
1043 *path = g_strdup (str);
1064 *parent_path = g_strdup (*path);
1065 p = item_factory_find_separator_r (*parent_path);
1068 g_warning ("GtkItemFactory: invalid entry path `%s'", str);
1073 if (ifactory->translate_func)
1074 translation = ifactory->translate_func (str, ifactory->translate_data);
1078 p = item_factory_find_separator_r (translation);
1084 *item = item_factory_unescape_label (p);
1090 gtk_item_factory_create_item (GtkItemFactory *ifactory,
1091 GtkItemFactoryEntry *entry,
1092 gpointer callback_data,
1093 guint callback_type)
1095 GtkOptionMenu *option_menu = NULL;
1098 GSList *radio_group;
1105 gchar *item_type_path;
1107 g_return_if_fail (ifactory != NULL);
1108 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1109 g_return_if_fail (entry != NULL);
1110 g_return_if_fail (entry->path != NULL);
1111 g_return_if_fail (entry->path[0] == '/');
1112 g_return_if_fail (callback_type >= 1 && callback_type <= 2);
1114 if (!entry->item_type ||
1115 entry->item_type[0] == 0)
1117 item_type_path = "<Item>";
1118 type_id = quark_type_item;
1122 item_type_path = entry->item_type;
1123 type_id = gtk_object_data_try_key (item_type_path);
1127 if (type_id == quark_type_item)
1128 type = GTK_TYPE_MENU_ITEM;
1129 else if (type_id == quark_type_title)
1130 type = GTK_TYPE_MENU_ITEM;
1131 else if (type_id == quark_type_radio_item)
1132 type = GTK_TYPE_RADIO_MENU_ITEM;
1133 else if (type_id == quark_type_check_item)
1134 type = GTK_TYPE_CHECK_MENU_ITEM;
1135 else if (type_id == quark_type_tearoff_item)
1136 type = GTK_TYPE_TEAROFF_MENU_ITEM;
1137 else if (type_id == quark_type_toggle_item)
1138 type = GTK_TYPE_CHECK_MENU_ITEM;
1139 else if (type_id == quark_type_separator_item)
1140 type = GTK_TYPE_MENU_ITEM;
1141 else if (type_id == quark_type_branch)
1142 type = GTK_TYPE_MENU_ITEM;
1143 else if (type_id == quark_type_last_branch)
1144 type = GTK_TYPE_MENU_ITEM;
1147 GtkWidget *radio_link;
1149 radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
1150 if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
1152 type = GTK_TYPE_RADIO_MENU_ITEM;
1153 radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
1157 g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1164 if (!gtk_item_factory_parse_path (ifactory, entry->path,
1165 &path, &parent_path, &name))
1168 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1171 GtkItemFactoryEntry pentry;
1174 ppath = g_strdup (entry->path);
1175 p = item_factory_find_separator_r (ppath);
1176 g_return_if_fail (p != NULL);
1178 pentry.path = ppath;
1179 pentry.accelerator = NULL;
1180 pentry.callback = NULL;
1181 pentry.callback_action = 0;
1182 pentry.item_type = "<Branch>";
1184 gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1187 parent = gtk_item_factory_get_widget (ifactory, parent_path);
1188 g_return_if_fail (parent != NULL);
1190 g_free (parent_path);
1192 if (GTK_IS_OPTION_MENU (parent))
1194 option_menu = GTK_OPTION_MENU (parent);
1195 if (!option_menu->menu)
1196 gtk_option_menu_set_menu (option_menu, gtk_widget_new (GTK_TYPE_MENU, NULL));
1197 parent = option_menu->menu;
1200 g_return_if_fail (GTK_IS_CONTAINER (parent));
1202 widget = gtk_widget_new (type,
1203 "GtkWidget::visible", TRUE,
1204 "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
1205 type_id != quark_type_title),
1206 "GtkWidget::parent", parent,
1208 if (option_menu && !option_menu->menu_item)
1209 gtk_option_menu_set_history (option_menu, 0);
1211 if (type == GTK_TYPE_RADIO_MENU_ITEM)
1212 gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1213 if (GTK_IS_CHECK_MENU_ITEM (widget))
1214 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
1216 /* install underline accelerators for this item
1218 if (type_id != quark_type_separator_item &&
1219 type_id != quark_type_tearoff_item &&
1224 label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1225 "GtkWidget::visible", TRUE,
1226 "GtkWidget::parent", widget,
1227 "GtkAccelLabel::accel_widget", widget,
1228 "GtkMisc::xalign", 0.0,
1231 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1236 if (type_id == quark_type_branch ||
1237 type_id == quark_type_last_branch)
1239 if (entry->callback)
1240 g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1243 if (type_id == quark_type_last_branch)
1244 gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1247 widget = gtk_widget_new (GTK_TYPE_MENU,
1250 gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1253 gtk_item_factory_add_item (ifactory,
1254 path, entry->accelerator,
1255 (type_id == quark_type_branch ||
1256 type_id == quark_type_last_branch) ?
1257 (GtkItemFactoryCallback) NULL : entry->callback,
1258 entry->callback_action, callback_data,
1267 gtk_item_factory_create_menu_entries (guint n_entries,
1268 GtkMenuEntry *entries)
1270 static GtkPatternSpec pspec_separator = { 42, 0 };
1271 static GtkPatternSpec pspec_check = { 42, 0 };
1276 g_return_if_fail (entries != NULL);
1278 if (pspec_separator.pattern_length == 0)
1280 gtk_pattern_spec_init (&pspec_separator, "*<separator>*");
1281 gtk_pattern_spec_init (&pspec_check, "*<check>*");
1284 for (i = 0; i < n_entries; i++)
1286 GtkItemFactory *ifactory;
1287 GtkItemFactoryEntry entry;
1291 path = entries[i].path;
1292 ifactory = gtk_item_factory_from_path (path);
1295 g_warning ("gtk_item_factory_create_menu_entries(): "
1296 "entry[%u] refers to unknown item factory: \"%s\"",
1297 i, entries[i].path);
1301 while (*path != '>')
1307 entry.accelerator = entries[i].accelerator;
1308 entry.callback = entries[i].callback;
1309 entry.callback_action = 0;
1310 if (gtk_pattern_match_string (&pspec_separator, path))
1311 entry.item_type = "<Separator>";
1312 else if (!gtk_pattern_match_string (&pspec_check, path))
1313 entry.item_type = NULL;
1316 gboolean in_brace = FALSE;
1319 cpath = g_new (gchar, strlen (path));
1325 else if (*path == '>')
1332 entry.item_type = "<ToggleItem>";
1336 gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1337 entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1343 gtk_item_factories_path_delete (const gchar *ifactory_path,
1346 GtkItemFactoryClass *class;
1347 GtkItemFactoryItem *item;
1349 g_return_if_fail (path != NULL);
1351 class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1354 item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1359 g_return_if_fail (ifactory_path != NULL);
1361 fpath = g_strconcat (ifactory_path, path, NULL);
1362 item = g_hash_table_lookup (class->item_ht, fpath);
1368 GSList *widget_list;
1372 for (slist = item->widgets; slist; slist = slist->next)
1376 widget = slist->data;
1377 widget_list = g_slist_prepend (widget_list, widget);
1378 gtk_widget_ref (widget);
1381 for (slist = widget_list; slist; slist = slist->next)
1385 widget = slist->data;
1386 gtk_widget_destroy (widget);
1387 gtk_widget_unref (widget);
1389 g_slist_free (widget_list);
1394 gtk_item_factory_delete_item (GtkItemFactory *ifactory,
1397 GtkItemFactoryClass *class;
1400 g_return_if_fail (ifactory != NULL);
1401 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1402 g_return_if_fail (path != NULL);
1404 class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
1406 widget = gtk_item_factory_get_widget (ifactory, path);
1410 if (GTK_IS_MENU (widget))
1411 widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1413 gtk_widget_destroy (widget);
1418 gtk_item_factory_delete_entry (GtkItemFactory *ifactory,
1419 GtkItemFactoryEntry *entry)
1421 g_return_if_fail (ifactory != NULL);
1422 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1423 g_return_if_fail (entry != NULL);
1425 gtk_item_factory_delete_item (ifactory, entry->path);
1429 gtk_item_factory_delete_entries (GtkItemFactory *ifactory,
1431 GtkItemFactoryEntry *entries)
1435 g_return_if_fail (ifactory != NULL);
1436 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1438 g_return_if_fail (entries != NULL);
1440 for (i = 0; i < n_entries; i++)
1441 gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1451 gtk_item_factory_menu_pos (GtkMenu *menu,
1456 MenuPos *mpos = func_data;
1463 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1465 GtkItemFactory *ifactory;
1467 g_return_val_if_fail (widget != NULL, NULL);
1468 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1470 ifactory = gtk_item_factory_from_widget (widget);
1472 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1478 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1480 g_return_val_if_fail (ifactory != NULL, NULL);
1481 g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1483 return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1487 ifactory_delete_popup_data (GtkObject *object,
1488 GtkItemFactory *ifactory)
1490 gtk_signal_disconnect_by_func (object,
1491 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1493 gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1497 gtk_item_factory_popup (GtkItemFactory *ifactory,
1503 gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1507 gtk_item_factory_popup_with_data (GtkItemFactory *ifactory,
1508 gpointer popup_data,
1509 GtkDestroyNotify destroy,
1517 g_return_if_fail (ifactory != NULL);
1518 g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1519 g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1521 mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1525 mpos = g_new0 (MenuPos, 1);
1526 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1535 if (popup_data != NULL)
1537 gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1541 gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1543 GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1547 gtk_menu_popup (GTK_MENU (ifactory->widget),
1549 gtk_item_factory_menu_pos, mpos,
1550 mouse_button, time);
1554 gtk_item_factory_parse_menu_path (GScanner *scanner,
1555 GtkItemFactoryClass *class)
1557 GtkItemFactoryItem *item;
1559 g_scanner_get_next_token (scanner);
1560 if (scanner->token != G_TOKEN_STRING)
1561 return G_TOKEN_STRING;
1563 g_scanner_peek_next_token (scanner);
1564 if (scanner->next_token != G_TOKEN_STRING)
1566 g_scanner_get_next_token (scanner);
1567 return G_TOKEN_STRING;
1570 item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1573 item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1575 item->path = g_strdup (scanner->value.v_string);
1576 item->accelerator_key = 0;
1577 item->accelerator_mods = 0;
1578 item->modified = TRUE;
1579 item->in_propagation = FALSE;
1581 item->widgets = NULL;
1583 g_hash_table_insert (class->item_ht, item->path, item);
1585 g_scanner_get_next_token (scanner);
1587 if (!item->in_propagation)
1592 old_keyval = item->accelerator_key;
1593 old_mods = item->accelerator_mods;
1594 gtk_accelerator_parse (scanner->value.v_string,
1595 &item->accelerator_key,
1596 &item->accelerator_mods);
1597 if (old_keyval != item->accelerator_key ||
1598 old_mods != item->accelerator_mods)
1600 item->modified = TRUE;
1601 gtk_item_factory_propagate_accelerator (item, NULL);
1605 g_scanner_get_next_token (scanner);
1606 if (scanner->token != ')')
1609 return G_TOKEN_NONE;
1613 gtk_item_factory_parse_statement (GScanner *scanner,
1614 GtkItemFactoryClass *class)
1616 guint expected_token;
1618 g_scanner_get_next_token (scanner);
1620 if (scanner->token == G_TOKEN_SYMBOL)
1622 guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1624 parser_func = scanner->value.v_symbol;
1626 /* check whether this is a GtkItemFactory symbol.
1628 if (parser_func == gtk_item_factory_parse_menu_path)
1629 expected_token = parser_func (scanner, class);
1631 expected_token = G_TOKEN_SYMBOL;
1634 expected_token = G_TOKEN_SYMBOL;
1636 /* skip rest of statement on errrors
1638 if (expected_token != G_TOKEN_NONE)
1640 register guint level;
1643 if (scanner->token == ')')
1645 if (scanner->token == '(')
1648 while (!g_scanner_eof (scanner) && level > 0)
1650 g_scanner_get_next_token (scanner);
1652 if (scanner->token == '(')
1654 else if (scanner->token == ')')
1661 gtk_item_factory_parse_rc_string (const gchar *rc_string)
1665 g_return_if_fail (rc_string != NULL);
1667 if (!gtk_item_factory_class)
1668 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1670 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1671 scanner = g_scanner_new (&ifactory_scanner_config);
1673 g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1675 gtk_item_factory_parse_rc_scanner (scanner);
1677 g_scanner_destroy (scanner);
1681 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1683 gpointer saved_symbol;
1685 g_return_if_fail (scanner != NULL);
1687 if (!gtk_item_factory_class)
1688 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1690 saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1691 g_scanner_remove_symbol (scanner, "menu-path");
1692 g_scanner_add_symbol (scanner, "menu-path", gtk_item_factory_parse_menu_path);
1694 g_scanner_peek_next_token (scanner);
1696 while (scanner->next_token == '(')
1698 g_scanner_get_next_token (scanner);
1700 gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1702 g_scanner_peek_next_token (scanner);
1705 g_scanner_remove_symbol (scanner, "menu-path");
1706 g_scanner_add_symbol (scanner, "menu-path", saved_symbol);
1710 gtk_item_factory_parse_rc (const gchar *file_name)
1715 g_return_if_fail (file_name != NULL);
1717 if (!S_ISREG (g_scanner_stat_mode (file_name)))
1720 fd = open (file_name, O_RDONLY);
1724 if (!gtk_item_factory_class)
1725 gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1727 ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1728 scanner = g_scanner_new (&ifactory_scanner_config);
1730 g_scanner_input_file (scanner, fd);
1732 gtk_item_factory_parse_rc_scanner (scanner);
1734 g_scanner_destroy (scanner);
1740 gtk_item_factory_set_translate_func (GtkItemFactory *ifactory,
1741 GtkTranslateFunc func,
1743 GtkDestroyNotify notify)
1745 g_return_if_fail (ifactory != NULL);
1747 if (ifactory->translate_notify)
1748 ifactory->translate_notify (ifactory->translate_data);
1750 ifactory->translate_func = func;
1751 ifactory->translate_data = data;
1752 ifactory->translate_notify = notify;