]> Pileus Git - ~andy/gtk/blob - gtk/gtkitemfactory.c
Call setlocale (LC_ALL, ""). (#60606)
[~andy/gtk] / gtk / gtkitemfactory.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkItemFactory: Flexible item factory with automatic rc handling
5  * Copyright (C) 1998 Tim Janik
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /*
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/. 
28  */
29
30 #include        "config.h"
31
32 #include        "gtkitemfactory.h"
33 #include        "gtk/gtksignal.h"
34 #include        "gtk/gtkoptionmenu.h"
35 #include        "gtk/gtkmenubar.h"
36 #include        "gtk/gtkmenu.h"
37 #include        "gtk/gtkmenuitem.h"
38 #include        "gtk/gtkradiomenuitem.h"
39 #include        "gtk/gtkcheckmenuitem.h"
40 #include        "gtk/gtkimagemenuitem.h"
41 #include        "gtk/gtktearoffmenuitem.h"
42 #include        "gtk/gtkaccellabel.h"
43 #include        "gdk/gdkkeysyms.h"
44 #include        "gtk/gtkimage.h"
45 #include        "gtk/gtkstock.h"
46 #include        "gtk/gtkiconfactory.h"
47 #include        <string.h>
48 #include        <fcntl.h>
49 #ifdef HAVE_UNISTD_H
50 #include        <unistd.h>
51 #endif
52 #include        <stdio.h>
53
54 #ifdef G_OS_WIN32
55 #include        <io.h>          /* For _open and _close */
56
57 #ifndef S_ISREG
58 #define S_ISREG(mode) ((mode)&_S_IFREG)
59 #endif
60 #endif
61
62
63 /* --- defines --- */
64 #define         ITEM_FACTORY_STRING     ((gchar*) item_factory_string)
65 #define         ITEM_BLOCK_SIZE         (128)
66
67
68 /* --- structures --- */
69 typedef struct  _GtkIFCBData            GtkIFCBData;
70 typedef struct  _GtkIFDumpData          GtkIFDumpData;
71 struct _GtkIFCBData
72 {
73   GtkItemFactoryCallback  func;
74   guint                   callback_type;
75   gpointer                func_data;
76   guint                   callback_action;
77 };
78 struct _GtkIFDumpData
79 {
80   GtkPrintFunc   print_func;
81   gpointer       func_data;
82   guint          modified_only : 1;
83   GPatternSpec  *pspec;
84 };
85
86
87 /* --- prototypes --- */
88 static void     gtk_item_factory_class_init             (GtkItemFactoryClass  *klass);
89 static void     gtk_item_factory_init                   (GtkItemFactory       *ifactory);
90 static void     gtk_item_factory_destroy                (GtkObject            *object);
91 static void     gtk_item_factory_finalize               (GObject              *object);
92
93
94 /* --- static variables --- */
95 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
96 static gpointer          parent_class = NULL;
97 static const gchar      *item_factory_string = "Gtk-<ItemFactory>";
98 static GMemChunk        *ifactory_item_chunks = NULL;
99 static GMemChunk        *ifactory_cb_data_chunks = NULL;
100 static GQuark            quark_popup_data = 0;
101 static GQuark            quark_if_menu_pos = 0;
102 static GQuark            quark_item_factory = 0;
103 static GQuark            quark_item_path = 0;
104 static GQuark            quark_action = 0;
105 static GQuark            quark_accel_group = 0;
106 static GQuark            quark_type_item = 0;
107 static GQuark            quark_type_title = 0;
108 static GQuark            quark_type_radio_item = 0;
109 static GQuark            quark_type_check_item = 0;
110 static GQuark            quark_type_toggle_item = 0;
111 static GQuark            quark_type_image_item = 0;
112 static GQuark            quark_type_stock_item = 0;
113 static GQuark            quark_type_tearoff_item = 0;
114 static GQuark            quark_type_separator_item = 0;
115 static GQuark            quark_type_branch = 0;
116 static GQuark            quark_type_last_branch = 0;
117 static  GScannerConfig  ifactory_scanner_config =
118 {
119   (
120    " \t\n"
121    )                    /* cset_skip_characters */,
122   (
123    G_CSET_a_2_z
124    "_"
125    G_CSET_A_2_Z
126    )                    /* cset_identifier_first */,
127   (
128    G_CSET_a_2_z
129    "-+_0123456789"
130    G_CSET_A_2_Z
131    G_CSET_LATINS
132    G_CSET_LATINC
133    )                    /* cset_identifier_nth */,
134   ( ";\n" )             /* cpair_comment_single */,
135   
136   FALSE                 /* case_sensitive */,
137   
138   TRUE                  /* skip_comment_multi */,
139   TRUE                  /* skip_comment_single */,
140   FALSE                 /* scan_comment_multi */,
141   TRUE                  /* scan_identifier */,
142   FALSE                 /* scan_identifier_1char */,
143   FALSE                 /* scan_identifier_NULL */,
144   TRUE                  /* scan_symbols */,
145   TRUE                  /* scan_binary */,
146   TRUE                  /* scan_octal */,
147   TRUE                  /* scan_float */,
148   TRUE                  /* scan_hex */,
149   FALSE                 /* scan_hex_dollar */,
150   TRUE                  /* scan_string_sq */,
151   TRUE                  /* scan_string_dq */,
152   TRUE                  /* numbers_2_int */,
153   FALSE                 /* int_2_float */,
154   FALSE                 /* identifier_2_string */,
155   TRUE                  /* char_2_token */,
156   FALSE                 /* symbol_2_token */,
157 };
158
159
160 /* --- functions --- */
161 GtkType
162 gtk_item_factory_get_type (void)
163 {
164   static GtkType item_factory_type = 0;
165   
166   if (!item_factory_type)
167     {
168       static const GtkTypeInfo item_factory_info =
169       {
170         "GtkItemFactory",
171         sizeof (GtkItemFactory),
172         sizeof (GtkItemFactoryClass),
173         (GtkClassInitFunc) gtk_item_factory_class_init,
174         (GtkObjectInitFunc) gtk_item_factory_init,
175         /* reserved_1 */ NULL,
176         /* reserved_2 */ NULL,
177         (GtkClassInitFunc) NULL,
178       };
179       
180       item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
181     }
182   
183   return item_factory_type;
184 }
185
186 static void
187 gtk_item_factory_class_init (GtkItemFactoryClass  *class)
188 {
189   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
190   GtkObjectClass *object_class;
191
192   gtk_item_factory_class = class;
193
194   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
195
196   object_class = (GtkObjectClass*) class;
197
198   gobject_class->finalize = gtk_item_factory_finalize;
199
200   object_class->destroy = gtk_item_factory_destroy;
201
202   class->cpair_comment_single = g_strdup (";\n");
203
204   class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
205   class->dummy = NULL;
206   ifactory_item_chunks =
207     g_mem_chunk_new ("GtkItemFactoryItem",
208                      sizeof (GtkItemFactoryItem),
209                      sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
210                      G_ALLOC_ONLY);
211   ifactory_cb_data_chunks =
212     g_mem_chunk_new ("GtkIFCBData",
213                      sizeof (GtkIFCBData),
214                      sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
215                      G_ALLOC_AND_FREE);
216
217   quark_popup_data              = g_quark_from_static_string ("GtkItemFactory-popup-data");
218   quark_if_menu_pos             = g_quark_from_static_string ("GtkItemFactory-menu-position");
219   quark_item_factory            = g_quark_from_static_string ("GtkItemFactory");
220   quark_item_path               = g_quark_from_static_string ("GtkItemFactory-path");
221   quark_action                  = g_quark_from_static_string ("GtkItemFactory-action");
222   quark_accel_group             = g_quark_from_static_string ("GtkAccelGroup");
223   quark_type_item               = g_quark_from_static_string ("<Item>");
224   quark_type_title              = g_quark_from_static_string ("<Title>");
225   quark_type_radio_item         = g_quark_from_static_string ("<RadioItem>");
226   quark_type_check_item         = g_quark_from_static_string ("<CheckItem>");
227   quark_type_toggle_item        = g_quark_from_static_string ("<ToggleItem>");
228   quark_type_image_item         = g_quark_from_static_string ("<ImageItem>");
229   quark_type_stock_item         = g_quark_from_static_string ("<StockItem>");
230   quark_type_separator_item     = g_quark_from_static_string ("<Separator>");
231   quark_type_tearoff_item       = g_quark_from_static_string ("<Tearoff>");
232   quark_type_branch             = g_quark_from_static_string ("<Branch>");
233   quark_type_last_branch        = g_quark_from_static_string ("<LastBranch>");
234 }
235
236 static void
237 gtk_item_factory_init (GtkItemFactory       *ifactory)
238 {
239   GtkObject *object;
240
241   object = GTK_OBJECT (ifactory);
242
243   ifactory->path = NULL;
244   ifactory->accel_group = NULL;
245   ifactory->widget = NULL;
246   ifactory->items = NULL;
247   ifactory->translate_func = NULL;
248   ifactory->translate_data = NULL;
249   ifactory->translate_notify = NULL;
250 }
251
252 GtkItemFactory*
253 gtk_item_factory_new (GtkType        container_type,
254                       const gchar   *path,
255                       GtkAccelGroup *accel_group)
256 {
257   GtkItemFactory *ifactory;
258
259   g_return_val_if_fail (path != NULL, NULL);
260
261   ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
262   gtk_item_factory_construct (ifactory, container_type, path, accel_group);
263
264   return ifactory;
265 }
266
267 static void
268 gtk_item_factory_callback_marshal (GtkWidget *widget,
269                                    gpointer   func_data)
270 {
271   GtkIFCBData *data;
272
273   data = func_data;
274
275   if (data->callback_type == 1)
276     {
277       GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
278       func1 (data->func_data, data->callback_action, widget);
279     }
280   else if (data->callback_type == 2)
281     {
282       GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
283       func2 (widget, data->func_data, data->callback_action);
284     }
285 }
286
287 static void
288 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
289                                         GtkWidget          *exclude)
290 {
291   GSList *widget_list;
292   GSList *slist;
293   
294   if (item->in_propagation)
295     return;
296   
297   item->in_propagation = TRUE;
298   
299   widget_list = NULL;
300   for (slist = item->widgets; slist; slist = slist->next)
301     {
302       GtkWidget *widget;
303       
304       widget = slist->data;
305       
306       if (widget != exclude)
307         {
308           gtk_widget_ref (widget);
309           widget_list = g_slist_prepend (widget_list, widget);
310         }
311     }
312   
313   for (slist = widget_list; slist; slist = slist->next)
314     {
315       GtkWidget *widget;
316       GtkAccelGroup *accel_group;
317       guint signal_id;
318       
319       widget = slist->data;
320       
321       accel_group = gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_accel_group);
322       
323       signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
324       if (signal_id && accel_group)
325         {
326           if (item->accelerator_key)
327             gtk_widget_add_accelerator (widget,
328                                         "activate",
329                                         accel_group,
330                                         item->accelerator_key,
331                                         item->accelerator_mods,
332                                         GTK_ACCEL_VISIBLE);
333           else
334             {
335               GSList *work;
336               
337               work = gtk_accel_group_entries_from_object (G_OBJECT (widget));
338               while (work)
339                 {
340                   GtkAccelEntry *ac_entry;
341                   
342                   ac_entry = work->data;
343                   work = work->next;
344                   if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
345                       ac_entry->accel_group == accel_group &&
346                       ac_entry->signal_id == signal_id)
347                     gtk_widget_remove_accelerator (GTK_WIDGET (widget),
348                                                    ac_entry->accel_group,
349                                                    ac_entry->accelerator_key,
350                                                    ac_entry->accelerator_mods);
351                 }
352             }
353         }
354
355       gtk_widget_unref (widget);
356     }
357   
358   g_slist_free (widget_list);
359   
360   item->in_propagation = FALSE;
361 }
362
363 static gint
364 gtk_item_factory_item_add_accelerator (GtkWidget          *widget,
365                                        guint               accel_signal_id,
366                                        GtkAccelGroup      *accel_group,
367                                        guint               accel_key,
368                                        guint               accel_mods,
369                                        GtkAccelFlags       accel_flags,
370                                        GtkItemFactoryItem *item)
371 {
372   if (!item->in_propagation &&
373       g_slist_find (item->widgets, widget) &&
374       accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
375     {
376       item->accelerator_key = accel_key;
377       item->accelerator_mods = accel_mods;
378       item->modified = TRUE;
379       
380       gtk_item_factory_propagate_accelerator (item, widget);
381     }
382
383   return TRUE;
384 }
385
386 static void
387 gtk_item_factory_item_remove_accelerator (GtkWidget          *widget,
388                                           GtkAccelGroup      *accel_group,
389                                           guint               accel_key,
390                                           guint               accel_mods,
391                                           GtkItemFactoryItem *item)
392 {
393   if (!item->in_propagation &&
394       g_slist_find (item->widgets, widget) &&
395       item->accelerator_key == accel_key &&
396       item->accelerator_mods == accel_mods)
397     {
398       item->accelerator_key = 0;
399       item->accelerator_mods = 0;
400       item->modified = TRUE;
401       
402       gtk_item_factory_propagate_accelerator (item, widget);
403     }
404 }
405
406 static void
407 gtk_item_factory_item_remove_widget (GtkWidget          *widget,
408                                      GtkItemFactoryItem *item)
409 {
410   item->widgets = g_slist_remove (item->widgets, widget);
411   gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
412   gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_path);
413 }
414
415 void
416 gtk_item_factory_add_foreign (GtkWidget      *accel_widget,
417                               const gchar    *full_path,
418                               GtkAccelGroup  *accel_group,
419                               guint           keyval,
420                               GdkModifierType modifiers)
421 {
422   GtkItemFactoryClass *class;
423   GtkItemFactoryItem *item;
424
425   g_return_if_fail (GTK_IS_WIDGET (accel_widget));
426   g_return_if_fail (full_path != NULL);
427
428   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
429
430   keyval = keyval != GDK_VoidSymbol ? keyval : 0;
431
432   item = g_hash_table_lookup (class->item_ht, full_path);
433   if (!item)
434     {
435       item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
436
437       item->path = g_strdup (full_path);
438       item->accelerator_key = keyval;
439       item->accelerator_mods = modifiers;
440       item->modified = FALSE;
441       item->in_propagation = FALSE;
442       item->dummy = NULL;
443       item->widgets = NULL;
444       
445       g_hash_table_insert (class->item_ht, item->path, item);
446     }
447
448   item->widgets = g_slist_prepend (item->widgets, accel_widget);
449   gtk_signal_connect (GTK_OBJECT (accel_widget),
450                       "destroy",
451                       GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
452                       item);
453
454   /* set the item path for the widget
455    */
456   gtk_object_set_data_by_id (GTK_OBJECT (accel_widget), quark_item_path, item->path);
457   gtk_widget_set_name (accel_widget, item->path);
458   if (accel_group)
459     {
460       gtk_accel_group_ref (accel_group);
461       gtk_object_set_data_by_id_full (GTK_OBJECT (accel_widget),
462                                       quark_accel_group,
463                                       accel_group,
464                                       (GtkDestroyNotify) gtk_accel_group_unref);
465     }
466   else
467     gtk_object_set_data_by_id (GTK_OBJECT (accel_widget), quark_accel_group, NULL);
468
469   /* install defined accelerators
470    */
471   if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (accel_widget)))
472     {
473       if (item->accelerator_key && accel_group)
474         gtk_widget_add_accelerator (accel_widget,
475                                     "activate",
476                                     accel_group,
477                                     item->accelerator_key,
478                                     item->accelerator_mods,
479                                     GTK_ACCEL_VISIBLE);
480       else
481         gtk_widget_remove_accelerators (accel_widget,
482                                         "activate",
483                                         TRUE);
484     }
485
486   /* keep track of accelerator changes
487    */
488   gtk_signal_connect_after (GTK_OBJECT (accel_widget),
489                             "add-accelerator",
490                             GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
491                             item);
492   gtk_signal_connect_after (GTK_OBJECT (accel_widget),
493                             "remove-accelerator",
494                             GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
495                             item);
496 }
497
498 static void
499 ifactory_cb_data_free (gpointer mem)
500 {
501   g_mem_chunk_free (ifactory_cb_data_chunks, mem);
502 }
503
504 static void
505 gtk_item_factory_add_item (GtkItemFactory               *ifactory,
506                            const gchar                  *path,
507                            const gchar                  *accelerator,
508                            GtkItemFactoryCallback       callback,
509                            guint                        callback_action,
510                            gpointer                     callback_data,
511                            guint                        callback_type,
512                            gchar                        *item_type,
513                            GtkWidget                    *widget)
514 {
515   GtkItemFactoryClass *class;
516   GtkItemFactoryItem *item;
517   gchar *fpath;
518   guint keyval, mods;
519   
520   g_return_if_fail (widget != NULL);
521   g_return_if_fail (item_type != NULL);
522
523   class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
524
525   /* set accelerator group on menu widgets
526    */
527   if (GTK_IS_MENU (widget))
528     gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
529
530   /* connect callback if neccessary
531    */
532   if (callback)
533     {
534       GtkIFCBData *data;
535
536       data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
537       data->func = callback;
538       data->callback_type = callback_type;
539       data->func_data = callback_data;
540       data->callback_action = callback_action;
541
542       gtk_object_weakref (GTK_OBJECT (widget),
543                           ifactory_cb_data_free,
544                           data);
545       gtk_signal_connect (GTK_OBJECT (widget),
546                           "activate",
547                           GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
548                           data);
549     }
550
551   /* link the widget into its item-entry
552    * and keep back pointer on both the item factory and the widget
553    */
554   gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
555   gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
556   if (accelerator)
557     gtk_accelerator_parse (accelerator, &keyval, &mods);
558   else
559     {
560       keyval = 0;
561       mods = 0;
562     }
563   fpath = g_strconcat (ifactory->path, path, NULL);
564   gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
565   item = g_hash_table_lookup (class->item_ht, fpath);
566   g_free (fpath);
567
568   g_return_if_fail (item != NULL);
569
570   if (!g_slist_find (ifactory->items, item))
571     ifactory->items = g_slist_prepend (ifactory->items, item);
572 }
573
574 void
575 gtk_item_factory_construct (GtkItemFactory      *ifactory,
576                             GtkType              container_type,
577                             const gchar         *path,
578                             GtkAccelGroup       *accel_group)
579 {
580   guint len;
581
582   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
583   g_return_if_fail (ifactory->accel_group == NULL);
584   g_return_if_fail (path != NULL);
585   if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
586     g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
587
588   len = strlen (path);
589
590   if (path[0] != '<' && path[len - 1] != '>')
591     {
592       g_warning ("GtkItemFactory: invalid factory path `%s'", path);
593       return;
594     }
595
596   if (accel_group)
597     {
598       ifactory->accel_group = accel_group;
599       gtk_accel_group_ref (ifactory->accel_group);
600     }
601   else
602     ifactory->accel_group = gtk_accel_group_new ();
603
604   ifactory->path = g_strdup (path);
605   ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
606                                        "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
607                                        NULL);
608   gtk_object_ref (GTK_OBJECT (ifactory));
609   gtk_object_sink (GTK_OBJECT (ifactory));
610
611   gtk_item_factory_add_item (ifactory,
612                              "", NULL,
613                              NULL, 0, NULL, 0,
614                              ITEM_FACTORY_STRING,
615                              ifactory->widget);
616 }
617
618 GtkItemFactory*
619 gtk_item_factory_from_path (const gchar      *path)
620 {
621   GtkItemFactoryClass *class;
622   GtkItemFactoryItem *item;
623   gchar *fname;
624   guint i;
625
626   g_return_val_if_fail (path != NULL, NULL);
627   g_return_val_if_fail (path[0] == '<', NULL);
628
629   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
630
631   i = 0;
632   while (path[i] && path[i] != '>')
633     i++;
634   if (path[i] != '>')
635     {
636       g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
637                  path);
638       return NULL;
639     }
640   fname = g_new (gchar, i + 2);
641   g_memmove (fname, path, i + 1);
642   fname[i + 1] = 0;
643
644   item = g_hash_table_lookup (class->item_ht, fname);
645
646   g_free (fname);
647
648   if (item && item->widgets)
649     return gtk_item_factory_from_widget (item->widgets->data);
650
651   return NULL;
652 }
653
654 static void
655 gtk_item_factory_destroy (GtkObject *object)
656 {
657   GtkItemFactory *ifactory;
658   GSList *slist;
659
660   g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
661
662   ifactory = (GtkItemFactory*) object;
663
664   if (ifactory->widget)
665     {
666       GtkObject *dobj;
667
668       dobj = GTK_OBJECT (ifactory->widget);
669
670       gtk_object_ref (dobj);
671       gtk_object_sink (dobj);
672       gtk_object_destroy (dobj);
673       gtk_object_unref (dobj);
674
675       ifactory->widget = NULL;
676     }
677
678   for (slist = ifactory->items; slist; slist = slist->next)
679     {
680       GtkItemFactoryItem *item = slist->data;
681       GSList *link;
682       
683       for (link = item->widgets; link; link = link->next)
684         if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory)
685           gtk_object_remove_data_by_id (link->data, quark_item_factory);
686     }
687   g_slist_free (ifactory->items);
688   ifactory->items = NULL;
689
690   GTK_OBJECT_CLASS (parent_class)->destroy (object);
691 }
692
693 static void
694 gtk_item_factory_finalize (GObject *object)
695 {
696   GtkItemFactory *ifactory;
697
698   g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
699
700   ifactory = GTK_ITEM_FACTORY (object);
701
702   gtk_accel_group_unref (ifactory->accel_group);
703   g_free (ifactory->path);
704   g_assert (ifactory->widget == NULL);
705
706   if (ifactory->translate_notify)
707     ifactory->translate_notify (ifactory->translate_data);
708   
709   G_OBJECT_CLASS (parent_class)->finalize (object);
710 }
711
712 GtkItemFactory*
713 gtk_item_factory_from_widget (GtkWidget        *widget)
714 {
715   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
716
717   return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
718 }
719
720 gchar*
721 gtk_item_factory_path_from_widget (GtkWidget        *widget)
722 {
723   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
724
725   return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_path);
726 }
727
728 static gchar *
729 item_factory_escape_path (const gchar *path)
730 {
731   GString *str = g_string_new (NULL);
732
733   while (*path)
734     {
735       gchar c = *path;
736
737       switch (c)
738         {
739         case '\n':
740           g_string_append (str, "\\n");
741           break;
742         case '\r':
743           g_string_append (str, "\\r");
744           break;
745         case '"':
746         case '\\':
747           g_string_append_c (str, '\\');
748           /* Fall through */
749         default:
750           g_string_append_c (str, c);
751         }
752       
753       path++;
754     }
755
756   return g_string_free (str, FALSE);
757 }
758
759 static void
760 gtk_item_factory_foreach (gpointer hash_key,
761                           gpointer value,
762                           gpointer user_data)
763 {
764   GtkItemFactoryItem *item;
765   GtkIFDumpData *data;
766   gchar *string;
767   gchar *path;
768   gchar *name;
769   gchar comment_prefix[2] = "\000\000";
770
771   item = value;
772   data = user_data;
773
774   if (data->pspec && !g_pattern_match_string (data->pspec, item->path))
775     return;
776
777   comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
778
779   path = item_factory_escape_path (hash_key);
780   name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
781   string = g_strconcat (item->modified ? "" : comment_prefix,
782                         "(menu-path \"",
783                         path,
784                         "\" \"",
785                         name,
786                         "\")",
787                         NULL);
788   g_free (path);
789   g_free (name);
790
791   data->print_func (data->func_data, string);
792
793   g_free (string);
794 }
795
796 void
797 gtk_item_factory_dump_items (GPatternSpec        *path_pspec,
798                              gboolean             modified_only,
799                              GtkPrintFunc         print_func,
800                              gpointer             func_data)
801 {
802   GtkIFDumpData data;
803
804   g_return_if_fail (print_func != NULL);
805
806   if (!gtk_item_factory_class)
807     gtk_type_class (GTK_TYPE_ITEM_FACTORY);
808
809   data.print_func = print_func;
810   data.func_data = func_data;
811   data.modified_only = (modified_only != FALSE);
812   data.pspec = path_pspec;
813
814   g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
815 }
816
817 void
818 gtk_item_factory_print_func (gpointer     FILE_pointer,
819                              const gchar *string)
820 {
821   FILE *f_out = FILE_pointer;
822
823   g_return_if_fail (FILE_pointer != NULL);
824   g_return_if_fail (string != NULL);
825   
826   fputs (string, f_out);
827   fputc ('\n', f_out);
828 }
829
830 void
831 gtk_item_factory_dump_rc (const gchar  *file_name,
832                           GPatternSpec *path_pspec,
833                           gboolean      modified_only)
834 {
835   FILE *f_out;
836
837   g_return_if_fail (file_name != NULL);
838
839   f_out = fopen (file_name, "w");
840   if (!f_out)
841     return;
842
843   fputs ("; ", f_out);
844   if (g_get_prgname ())
845     fputs (g_get_prgname (), f_out);
846   fputs (" GtkItemFactory rc-file         -*- scheme -*-\n", f_out);
847   fputs ("; this file is an automated menu-path dump\n", f_out);
848   fputs (";\n", f_out);
849
850   gtk_item_factory_dump_items (path_pspec,
851                                modified_only,
852                                gtk_item_factory_print_func,
853                                f_out);
854
855   fclose (f_out);
856 }
857
858 void
859 gtk_item_factory_create_items (GtkItemFactory      *ifactory,
860                                guint                n_entries,
861                                GtkItemFactoryEntry *entries,
862                                gpointer             callback_data)
863 {
864   gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
865 }
866
867 void
868 gtk_item_factory_create_items_ac (GtkItemFactory      *ifactory,
869                                   guint                n_entries,
870                                   GtkItemFactoryEntry *entries,
871                                   gpointer             callback_data,
872                                   guint                callback_type)
873 {
874   guint i;
875
876   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
877   g_return_if_fail (callback_type >= 1 && callback_type <= 2);
878
879   if (n_entries == 0)
880     return;
881
882   g_return_if_fail (entries != NULL);
883
884   for (i = 0; i < n_entries; i++)
885     gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
886 }
887
888 GtkWidget*
889 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
890                              const gchar    *path)
891 {
892   GtkItemFactoryClass *class;
893   GtkItemFactoryItem *item;
894
895   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
896   g_return_val_if_fail (path != NULL, NULL);
897
898   class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
899
900   if (path[0] == '<')
901     item = g_hash_table_lookup (class->item_ht, (gpointer) path);
902   else
903     {
904       gchar *fpath;
905
906       fpath = g_strconcat (ifactory->path, path, NULL);
907       item = g_hash_table_lookup (class->item_ht, fpath);
908       g_free (fpath);
909     }
910
911   if (item)
912     {
913       GSList *slist;
914
915       for (slist = item->widgets; slist; slist = slist->next)
916         {
917           if (gtk_item_factory_from_widget (slist->data) == ifactory)
918             return slist->data;
919         }
920     }
921
922   return NULL;
923 }
924
925 GtkWidget*
926 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
927                                        guint           action)
928 {
929   GSList *slist;
930
931   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
932
933   for (slist = ifactory->items; slist; slist = slist->next)
934     {
935       GtkItemFactoryItem *item = slist->data;
936       GSList *link;
937
938       for (link = item->widgets; link; link = link->next)
939         if (gtk_object_get_data_by_id (link->data, quark_item_factory) == ifactory &&
940             gtk_object_get_data_by_id (link->data, quark_action) == GUINT_TO_POINTER (action))
941           return link->data;
942     }
943
944   return NULL;
945 }
946
947 GtkWidget*
948 gtk_item_factory_get_item (GtkItemFactory *ifactory,
949                            const gchar    *path)
950 {
951   GtkWidget *widget;
952
953   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
954   g_return_val_if_fail (path != NULL, NULL);
955
956   widget = gtk_item_factory_get_widget (ifactory, path);
957
958   if (GTK_IS_MENU (widget))
959     widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
960
961   return GTK_IS_ITEM (widget) ? widget : NULL;
962 }
963
964 GtkWidget*
965 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
966                                      guint           action)
967 {
968   GtkWidget *widget;
969
970   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
971
972   widget = gtk_item_factory_get_widget_by_action (ifactory, action);
973
974   if (GTK_IS_MENU (widget))
975     widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
976
977   return GTK_IS_ITEM (widget) ? widget : NULL;
978 }
979
980 static char *
981 item_factory_find_separator_r (char *path)
982 {
983   gchar *result = NULL;
984   gboolean escaped = FALSE;
985
986   while (*path)
987     {
988       if (escaped)
989         escaped = FALSE;
990       else
991         {
992           if (*path == '\\')
993             escaped = TRUE;
994           else if (*path == '/')
995             result = path;
996         }
997       
998       path++;
999     }
1000
1001   return result;
1002 }
1003
1004 static char *
1005 item_factory_unescape_label (const char *label)
1006 {
1007   char *new = g_malloc (strlen (label) + 1);
1008   char *p = new;
1009   gboolean escaped = FALSE;
1010   
1011   while (*label)
1012     {
1013       if (escaped)
1014         {
1015           *p++ = *label;
1016           escaped = FALSE;
1017         }
1018       else
1019         {
1020           if (*label == '\\')
1021             escaped = TRUE;
1022           else
1023             *p++ = *label;
1024         }
1025       
1026       label++;
1027     }
1028
1029   *p = '\0';
1030
1031   return new;
1032 }
1033
1034 static gboolean
1035 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
1036                              gchar          *str,
1037                              gchar         **path,
1038                              gchar         **parent_path,
1039                              gchar         **item)
1040 {
1041   gchar *translation;
1042   gchar *p, *q;
1043   
1044   *path = g_strdup (str);
1045
1046   p = q = *path;
1047   while (*p)
1048     {
1049       if (*p == '_')
1050         {
1051           if (p[1] == '_')
1052             {
1053               p++;
1054               *q++ = '_';
1055             }
1056         }
1057       else
1058         {
1059           *q++ = *p;
1060         }
1061       p++;
1062     }
1063   *q = 0;
1064
1065   *parent_path = g_strdup (*path);
1066   p = item_factory_find_separator_r (*parent_path);
1067   if (!p)
1068     {
1069       g_warning ("GtkItemFactory: invalid entry path `%s'", str);
1070       return FALSE;
1071     }
1072   *p = 0;
1073
1074   if (ifactory->translate_func)
1075     translation = ifactory->translate_func (str, ifactory->translate_data);
1076   else
1077     translation = str;
1078                               
1079   p = item_factory_find_separator_r (translation);
1080   if (p)
1081     p++;
1082   else
1083     p = translation;
1084
1085   *item = item_factory_unescape_label (p);
1086
1087   return TRUE;
1088 }
1089
1090 void
1091 gtk_item_factory_create_item (GtkItemFactory         *ifactory,
1092                               GtkItemFactoryEntry    *entry,
1093                               gpointer                callback_data,
1094                               guint                   callback_type)
1095 {
1096   GtkOptionMenu *option_menu = NULL;
1097   GtkWidget *parent;
1098   GtkWidget *widget;
1099   GtkWidget *image;
1100   GSList *radio_group;
1101   gchar *name;
1102   gchar *parent_path;
1103   gchar *path;
1104   gchar *accelerator;
1105   guint type_id;
1106   GtkType type;
1107   gchar *item_type_path;
1108   GtkStockItem stock_item;
1109       
1110   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1111   g_return_if_fail (entry != NULL);
1112   g_return_if_fail (entry->path != NULL);
1113   g_return_if_fail (entry->path[0] == '/');
1114   g_return_if_fail (callback_type >= 1 && callback_type <= 2);
1115
1116   if (!entry->item_type ||
1117       entry->item_type[0] == 0)
1118     {
1119       item_type_path = "<Item>";
1120       type_id = quark_type_item;
1121     }
1122   else
1123     {
1124       item_type_path = entry->item_type;
1125       type_id = gtk_object_data_try_key (item_type_path);
1126     }
1127
1128   radio_group = NULL;
1129   if (type_id == quark_type_item)
1130     type = GTK_TYPE_MENU_ITEM;
1131   else if (type_id == quark_type_title)
1132     type = GTK_TYPE_MENU_ITEM;
1133   else if (type_id == quark_type_radio_item)
1134     type = GTK_TYPE_RADIO_MENU_ITEM;
1135   else if (type_id == quark_type_check_item)
1136     type = GTK_TYPE_CHECK_MENU_ITEM;
1137   else if (type_id == quark_type_image_item)
1138     type = GTK_TYPE_IMAGE_MENU_ITEM;
1139   else if (type_id == quark_type_stock_item)
1140     type = GTK_TYPE_IMAGE_MENU_ITEM;
1141   else if (type_id == quark_type_tearoff_item)
1142     type = GTK_TYPE_TEAROFF_MENU_ITEM;
1143   else if (type_id == quark_type_toggle_item)
1144     type = GTK_TYPE_CHECK_MENU_ITEM;
1145   else if (type_id == quark_type_separator_item)
1146     type = GTK_TYPE_MENU_ITEM;
1147   else if (type_id == quark_type_branch)
1148     type = GTK_TYPE_MENU_ITEM;
1149   else if (type_id == quark_type_last_branch)
1150     type = GTK_TYPE_MENU_ITEM;
1151   else
1152     {
1153       GtkWidget *radio_link;
1154
1155       radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
1156       if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
1157         {
1158           type = GTK_TYPE_RADIO_MENU_ITEM;
1159           radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
1160         }
1161       else
1162         {
1163           g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1164                      entry->path,
1165                      item_type_path);
1166           return;
1167         }
1168     }
1169
1170   if (!gtk_item_factory_parse_path (ifactory, entry->path, 
1171                                     &path, &parent_path, &name))
1172     return;
1173
1174   parent = gtk_item_factory_get_widget (ifactory, parent_path);
1175   if (!parent)
1176     {
1177       GtkItemFactoryEntry pentry;
1178       gchar *ppath, *p;
1179
1180       ppath = g_strdup (entry->path);
1181       p = item_factory_find_separator_r (ppath);
1182       g_return_if_fail (p != NULL);
1183       *p = 0;
1184       pentry.path = ppath;
1185       pentry.accelerator = NULL;
1186       pentry.callback = NULL;
1187       pentry.callback_action = 0;
1188       pentry.item_type = "<Branch>";
1189
1190       gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1191       g_free (ppath);
1192
1193       parent = gtk_item_factory_get_widget (ifactory, parent_path);
1194       g_return_if_fail (parent != NULL);
1195     }
1196   g_free (parent_path);
1197
1198   if (GTK_IS_OPTION_MENU (parent))
1199     {
1200       option_menu = GTK_OPTION_MENU (parent);
1201       if (!option_menu->menu)
1202         gtk_option_menu_set_menu (option_menu, gtk_widget_new (GTK_TYPE_MENU, NULL));
1203       parent = option_menu->menu;
1204     }
1205                               
1206   g_return_if_fail (GTK_IS_CONTAINER (parent));
1207
1208   accelerator = entry->accelerator;
1209   
1210   widget = gtk_widget_new (type,
1211                            "GtkWidget::visible", TRUE,
1212                            "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
1213                                                     type_id != quark_type_title),
1214                            "GtkWidget::parent", parent,
1215                            NULL);
1216   if (option_menu && !option_menu->menu_item)
1217     gtk_option_menu_set_history (option_menu, 0);
1218
1219   if (type == GTK_TYPE_RADIO_MENU_ITEM)
1220     gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1221   if (GTK_IS_CHECK_MENU_ITEM (widget))
1222     gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
1223   if (type_id == quark_type_image_item)
1224     {
1225       GdkPixbuf *pixbuf = NULL;
1226       image = NULL;
1227
1228       pixbuf = gdk_pixbuf_new_from_inline (-1,
1229                                            entry->extra_data,
1230                                            FALSE,
1231                                            NULL);
1232
1233       if (pixbuf)
1234         image = gtk_image_new_from_pixbuf (pixbuf);
1235
1236       if (image)
1237         {
1238           gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1239
1240           gtk_widget_show (image);
1241         }
1242
1243       if (pixbuf)
1244         g_object_unref (G_OBJECT (pixbuf));
1245     }
1246   if (type_id == quark_type_stock_item)
1247     {
1248       image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1249
1250       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1251
1252       gtk_widget_show (image);
1253
1254       if (gtk_stock_lookup (entry->extra_data, &stock_item))
1255         {
1256           if (!accelerator)
1257             accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1258         }
1259     }
1260   
1261   
1262
1263   /* install underline accelerators for this item
1264    */
1265   if (type_id != quark_type_separator_item && 
1266       type_id != quark_type_tearoff_item &&
1267       *name)
1268     {
1269       GtkWidget *label;
1270       
1271       label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1272                               "GtkWidget::visible", TRUE,
1273                               "GtkWidget::parent", widget,
1274                               "GtkAccelLabel::accel_object", widget,
1275                               "GtkMisc::xalign", 0.0,
1276                               NULL);
1277       
1278       gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1279     }
1280   
1281   g_free (name);
1282   
1283   if (type_id == quark_type_branch ||
1284       type_id == quark_type_last_branch)
1285     {
1286       if (entry->callback)
1287         g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1288                    entry->path);
1289       
1290       if (type_id == quark_type_last_branch)
1291         gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE);
1292       
1293       parent = widget;
1294       widget = gtk_widget_new (GTK_TYPE_MENU,
1295                                NULL);
1296       
1297       gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1298     }      
1299   
1300   gtk_item_factory_add_item (ifactory,
1301                              path, accelerator,
1302                              (type_id == quark_type_branch ||
1303                               type_id == quark_type_last_branch) ?
1304                               (GtkItemFactoryCallback) NULL : entry->callback,
1305                              entry->callback_action, callback_data,
1306                              callback_type,
1307                              item_type_path,
1308                              widget);
1309
1310   if (accelerator != entry->accelerator)
1311     g_free (accelerator);
1312   
1313   g_free (path);
1314 }
1315
1316 void
1317 gtk_item_factory_create_menu_entries (guint              n_entries,
1318                                       GtkMenuEntry      *entries)
1319 {
1320   static GPatternSpec *pspec_separator = NULL;
1321   static GPatternSpec *pspec_check = NULL;
1322   guint i;
1323
1324   if (!n_entries)
1325     return;
1326   g_return_if_fail (entries != NULL);
1327
1328   if (!pspec_separator)
1329     {
1330       pspec_separator = g_pattern_spec_new ("*<separator>*");
1331       pspec_check = g_pattern_spec_new ("*<check>*");
1332     }
1333
1334   for (i = 0; i < n_entries; i++)
1335     {
1336       GtkItemFactory *ifactory;
1337       GtkItemFactoryEntry entry;
1338       gchar *path;
1339       gchar *cpath;
1340
1341       path = entries[i].path;
1342       ifactory = gtk_item_factory_from_path (path);
1343       if (!ifactory)
1344         {
1345           g_warning ("gtk_item_factory_create_menu_entries(): "
1346                      "entry[%u] refers to unknown item factory: \"%s\"",
1347                      i, entries[i].path);
1348           continue;
1349         }
1350
1351       while (*path != '>')
1352         path++;
1353       path++;
1354       cpath = NULL;
1355
1356       entry.path = path;
1357       entry.accelerator = entries[i].accelerator;
1358       entry.callback = entries[i].callback;
1359       entry.callback_action = 0;
1360       if (g_pattern_match_string (pspec_separator, path))
1361         entry.item_type = "<Separator>";
1362       else if (!g_pattern_match_string (pspec_check, path))
1363         entry.item_type = NULL;
1364       else
1365         {
1366           gboolean in_brace = FALSE;
1367           gchar *c;
1368           
1369           cpath = g_new (gchar, strlen (path));
1370           c = cpath;
1371           while (*path != 0)
1372             {
1373               if (*path == '<')
1374                 in_brace = TRUE;
1375               else if (*path == '>')
1376                 in_brace = FALSE;
1377               else if (!in_brace)
1378                 *(c++) = *path;
1379               path++;
1380             }
1381           *c = 0;
1382           entry.item_type = "<ToggleItem>";
1383           entry.path = cpath;
1384         }
1385       
1386       gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1387       entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1388       g_free (cpath);
1389     }
1390 }
1391
1392 void
1393 gtk_item_factories_path_delete (const gchar *ifactory_path,
1394                                 const gchar *path)
1395 {
1396   GtkItemFactoryClass *class;
1397   GtkItemFactoryItem *item;
1398
1399   g_return_if_fail (path != NULL);
1400
1401   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1402
1403   if (path[0] == '<')
1404     item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1405   else
1406     {
1407       gchar *fpath;
1408
1409       g_return_if_fail (ifactory_path != NULL);
1410       
1411       fpath = g_strconcat (ifactory_path, path, NULL);
1412       item = g_hash_table_lookup (class->item_ht, fpath);
1413       g_free (fpath);
1414     }
1415   
1416   if (item)
1417     {
1418       GSList *widget_list;
1419       GSList *slist;
1420
1421       widget_list = NULL;
1422       for (slist = item->widgets; slist; slist = slist->next)
1423         {
1424           GtkWidget *widget;
1425
1426           widget = slist->data;
1427           widget_list = g_slist_prepend (widget_list, widget);
1428           gtk_widget_ref (widget);
1429         }
1430
1431       for (slist = widget_list; slist; slist = slist->next)
1432         {
1433           GtkWidget *widget;
1434
1435           widget = slist->data;
1436           gtk_widget_destroy (widget);
1437           gtk_widget_unref (widget);
1438         }
1439       g_slist_free (widget_list);
1440     }
1441 }
1442
1443 void
1444 gtk_item_factory_delete_item (GtkItemFactory         *ifactory,
1445                               const gchar            *path)
1446 {
1447   GtkItemFactoryClass *class;
1448   GtkWidget *widget;
1449
1450   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1451   g_return_if_fail (path != NULL);
1452
1453   class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
1454
1455   widget = gtk_item_factory_get_widget (ifactory, path);
1456
1457   if (widget)
1458     {
1459       if (GTK_IS_MENU (widget))
1460         widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1461
1462       gtk_widget_destroy (widget);
1463     }
1464 }
1465
1466 void
1467 gtk_item_factory_delete_entry (GtkItemFactory         *ifactory,
1468                                GtkItemFactoryEntry    *entry)
1469 {
1470   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1471   g_return_if_fail (entry != NULL);
1472
1473   gtk_item_factory_delete_item (ifactory, entry->path);
1474 }
1475
1476 void
1477 gtk_item_factory_delete_entries (GtkItemFactory         *ifactory,
1478                                  guint                   n_entries,
1479                                  GtkItemFactoryEntry    *entries)
1480 {
1481   guint i;
1482
1483   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1484   if (n_entries > 0)
1485     g_return_if_fail (entries != NULL);
1486
1487   for (i = 0; i < n_entries; i++)
1488     gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1489 }
1490
1491 typedef struct
1492 {
1493   guint x;
1494   guint y;
1495 } MenuPos;
1496
1497 static void
1498 gtk_item_factory_menu_pos (GtkMenu  *menu,
1499                            gint     *x,
1500                            gint     *y,
1501                            gboolean *push_in,
1502                            gpointer  func_data)
1503 {
1504   MenuPos *mpos = func_data;
1505
1506   *x = mpos->x;
1507   *y = mpos->y;
1508 }
1509
1510 gpointer
1511 gtk_item_factory_popup_data_from_widget (GtkWidget     *widget)
1512 {
1513   GtkItemFactory *ifactory;
1514   
1515   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1516
1517   ifactory = gtk_item_factory_from_widget (widget);
1518   if (ifactory)
1519     return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1520
1521   return NULL;
1522 }
1523
1524 gpointer
1525 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1526 {
1527   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1528
1529   return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1530 }
1531
1532 static void
1533 ifactory_delete_popup_data (GtkObject      *object,
1534                             GtkItemFactory *ifactory)
1535 {
1536   gtk_signal_disconnect_by_func (object,
1537                                  GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1538                                  ifactory);
1539   gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1540 }
1541
1542 void
1543 gtk_item_factory_popup (GtkItemFactory          *ifactory,
1544                         guint                    x,
1545                         guint                    y,
1546                         guint                    mouse_button,
1547                         guint32                  time)
1548 {
1549   gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1550 }
1551
1552 void
1553 gtk_item_factory_popup_with_data (GtkItemFactory        *ifactory,
1554                                   gpointer               popup_data,
1555                                   GtkDestroyNotify       destroy,
1556                                   guint                  x,
1557                                   guint                  y,
1558                                   guint                  mouse_button,
1559                                   guint32                time)
1560 {
1561   MenuPos *mpos;
1562
1563   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1564   g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1565   
1566   mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1567   
1568   if (!mpos)
1569     {
1570       mpos = g_new0 (MenuPos, 1);
1571       gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1572                                       quark_if_menu_pos,
1573                                       mpos,
1574                                       g_free);
1575     }
1576   
1577   mpos->x = x;
1578   mpos->y = y;
1579   
1580   if (popup_data != NULL)
1581     {
1582       gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1583                                       quark_popup_data,
1584                                       popup_data,
1585                                       destroy);
1586       gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1587                           "selection-done",
1588                           GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1589                           ifactory);
1590     }
1591   
1592   gtk_menu_popup (GTK_MENU (ifactory->widget),
1593                   NULL, NULL,
1594                   gtk_item_factory_menu_pos, mpos,
1595                   mouse_button, time);
1596 }
1597
1598 static guint
1599 gtk_item_factory_parse_menu_path (GScanner            *scanner,
1600                                   GtkItemFactoryClass *class)
1601 {
1602   GtkItemFactoryItem *item;
1603   
1604   g_scanner_get_next_token (scanner);
1605   if (scanner->token != G_TOKEN_STRING)
1606     return G_TOKEN_STRING;
1607
1608   g_scanner_peek_next_token (scanner);
1609   if (scanner->next_token != G_TOKEN_STRING)
1610     {
1611       g_scanner_get_next_token (scanner);
1612       return G_TOKEN_STRING;
1613     }
1614
1615   item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1616   if (!item)
1617     {
1618       item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1619
1620       item->path = g_strdup (scanner->value.v_string);
1621       item->accelerator_key = 0;
1622       item->accelerator_mods = 0;
1623       item->modified = TRUE;
1624       item->in_propagation = FALSE;
1625       item->dummy = NULL;
1626       item->widgets = NULL;
1627
1628       g_hash_table_insert (class->item_ht, item->path, item);
1629     }
1630   g_scanner_get_next_token (scanner);
1631   
1632   if (!item->in_propagation)
1633     {
1634       guint old_keyval;
1635       guint old_mods;
1636       
1637       old_keyval = item->accelerator_key;
1638       old_mods = item->accelerator_mods;
1639       gtk_accelerator_parse (scanner->value.v_string,
1640                              &item->accelerator_key,
1641                              &item->accelerator_mods);
1642       if (old_keyval != item->accelerator_key ||
1643           old_mods != item->accelerator_mods)
1644         {
1645           item->modified = TRUE;
1646           gtk_item_factory_propagate_accelerator (item, NULL);
1647         }
1648     }
1649   
1650   g_scanner_get_next_token (scanner);
1651   if (scanner->token != ')')
1652     return ')';
1653   else
1654     return G_TOKEN_NONE;
1655 }
1656
1657 static void
1658 gtk_item_factory_parse_statement (GScanner            *scanner,
1659                                   GtkItemFactoryClass *class)
1660 {
1661   guint expected_token;
1662   
1663   g_scanner_get_next_token (scanner);
1664   
1665   if (scanner->token == G_TOKEN_SYMBOL)
1666     {
1667       guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1668
1669       parser_func = scanner->value.v_symbol;
1670
1671       /* check whether this is a GtkItemFactory symbol.
1672        */
1673       if (parser_func == gtk_item_factory_parse_menu_path)
1674         expected_token = parser_func (scanner, class);
1675       else
1676         expected_token = G_TOKEN_SYMBOL;
1677     }
1678   else
1679     expected_token = G_TOKEN_SYMBOL;
1680
1681   /* skip rest of statement on errrors
1682    */
1683   if (expected_token != G_TOKEN_NONE)
1684     {
1685       register guint level;
1686
1687       level = 1;
1688       if (scanner->token == ')')
1689         level--;
1690       if (scanner->token == '(')
1691         level++;
1692       
1693       while (!g_scanner_eof (scanner) && level > 0)
1694         {
1695           g_scanner_get_next_token (scanner);
1696           
1697           if (scanner->token == '(')
1698             level++;
1699           else if (scanner->token == ')')
1700             level--;
1701         }
1702     }
1703 }
1704
1705 void
1706 gtk_item_factory_parse_rc_string (const gchar    *rc_string)
1707 {
1708   GScanner *scanner;
1709
1710   g_return_if_fail (rc_string != NULL);
1711
1712   if (!gtk_item_factory_class)
1713     gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1714
1715   ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1716   scanner = g_scanner_new (&ifactory_scanner_config);
1717
1718   g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1719
1720   gtk_item_factory_parse_rc_scanner (scanner);
1721
1722   g_scanner_destroy (scanner);
1723 }
1724
1725 void
1726 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1727 {
1728   gpointer saved_symbol;
1729
1730   g_return_if_fail (scanner != NULL);
1731
1732   if (!gtk_item_factory_class)
1733     gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1734
1735   saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1736   g_scanner_scope_remove_symbol (scanner, 0, "menu-path");
1737   g_scanner_scope_add_symbol (scanner, 0, "menu-path", gtk_item_factory_parse_menu_path);
1738
1739   g_scanner_peek_next_token (scanner);
1740
1741   while (scanner->next_token == '(')
1742     {
1743       g_scanner_get_next_token (scanner);
1744
1745       gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1746
1747       g_scanner_peek_next_token (scanner);
1748     }
1749
1750   g_scanner_scope_remove_symbol (scanner, 0, "menu-path");
1751   g_scanner_scope_add_symbol (scanner, 0, "menu-path", saved_symbol);
1752 }
1753
1754 void
1755 gtk_item_factory_parse_rc (const gchar    *file_name)
1756 {
1757   gint fd;
1758   GScanner *scanner;
1759
1760   g_return_if_fail (file_name != NULL);
1761
1762   if (!g_file_test (file_name, G_FILE_TEST_IS_REGULAR))
1763     return;
1764
1765   fd = open (file_name, O_RDONLY);
1766   if (fd < 0)
1767     return;
1768
1769   if (!gtk_item_factory_class)
1770     gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1771
1772   ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1773   scanner = g_scanner_new (&ifactory_scanner_config);
1774
1775   g_scanner_input_file (scanner, fd);
1776
1777   gtk_item_factory_parse_rc_scanner (scanner);
1778
1779   g_scanner_destroy (scanner);
1780
1781   close (fd);
1782 }
1783
1784 void
1785 gtk_item_factory_set_translate_func (GtkItemFactory      *ifactory,
1786                                      GtkTranslateFunc     func,
1787                                      gpointer             data,
1788                                      GtkDestroyNotify     notify)
1789 {
1790   g_return_if_fail (ifactory != NULL);
1791   
1792   if (ifactory->translate_notify)
1793     ifactory->translate_notify (ifactory->translate_data);
1794       
1795   ifactory->translate_func = func;
1796   ifactory->translate_data = data;
1797   ifactory->translate_notify = notify;
1798 }