]> Pileus Git - ~andy/gtk/blob - gtk/gtkitemfactory.c
changed reversed_[12] to reserved_[12] in gtk_*_get_type functions.
[~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 Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
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  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #include        "gtkitemfactory.h"
23 #include        "gtk/gtksignal.h"
24 #include        "gtk/gtkoptionmenu.h"
25 #include        "gtk/gtkmenubar.h"
26 #include        "gtk/gtkmenu.h"
27 #include        "gtk/gtkmenuitem.h"
28 #include        "gtk/gtkradiomenuitem.h"
29 #include        "gtk/gtkcheckmenuitem.h"
30 #include        "gtk/gtkaccellabel.h"
31 #include        "gdk/gdkprivate.h" /* for gdk_progname */
32 #include        <string.h>
33 #include        <sys/stat.h>
34 #include        <fcntl.h>
35 #include        <unistd.h>
36 #include        <stdio.h>
37
38
39
40 /* --- defines --- */
41 #define         ITEM_FACTORY_STRING     ((gchar*) item_factory_string)
42 #define         ITEM_BLOCK_SIZE         (128)
43
44
45 /* --- structures --- */
46 typedef struct  _GtkIFCBData            GtkIFCBData;
47 typedef struct  _GtkIFActionLink        GtkIFActionLink;
48 typedef struct  _GtkIFDumpData          GtkIFDumpData;
49 struct _GtkIFCBData
50 {
51   GtkItemFactoryCallback  func;
52   guint                   callback_type;
53   gpointer                func_data;
54   guint                   callback_action;
55 };
56 struct _GtkIFActionLink
57 {
58   GtkWidget *widget;
59   guint callback_action;
60 };
61 struct _GtkIFDumpData
62 {
63   GtkPrintFunc           print_func;
64   gpointer               func_data;
65   guint                  modified_only : 1;
66   GtkPatternSpec        *pspec;
67 };
68
69
70 /* --- prototypes --- */
71 static void     gtk_item_factory_class_init             (GtkItemFactoryClass  *klass);
72 static void     gtk_item_factory_init                   (GtkItemFactory       *ifactory);
73 static void     gtk_item_factory_destroy                (GtkObject            *object);
74 static void     gtk_item_factory_finalize               (GtkObject            *object);
75
76
77 /* --- static variables --- */
78 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
79 static GtkObjectClass   *parent_class = NULL;
80 static const gchar      *item_factory_string = "Gtk-<ItemFactory>";
81 static GMemChunk        *ifactory_item_chunks = NULL;
82 static GMemChunk        *ifactory_cb_data_chunks = NULL;
83 static const gchar      *key_popup_data = "GtkItemFactory-popup-data";
84 static GQuark            quark_popup_data = 0;
85 static const gchar      *key_if_menu_pos = "GtkItemFactory-menu-position";
86 static GQuark            quark_if_menu_pos = 0;
87 static const gchar      *key_item_factory = "GtkItemFactory";
88 static GQuark            quark_item_factory = 0;
89 static const gchar      *key_item_factory_path = "GtkItemFactory-path";
90 static GQuark            quark_item_factory_path = 0;
91 static const gchar      *key_type_item = "<Item>";
92 static GQuark            quark_type_item = 0;
93 static const gchar      *key_type_title = "<Title>";
94 static GQuark            quark_type_title = 0;
95 static const gchar      *key_type_radio_item = "<RadioItem>";
96 static GQuark            quark_type_radio_item = 0;
97 static const gchar      *key_type_check_item = "<CheckItem>";
98 static GQuark            quark_type_check_item = 0;
99 static const gchar      *key_type_toggle_item = "<ToggleItem>";
100 static GQuark            quark_type_toggle_item = 0;
101 static const gchar      *key_type_separator_item = "<Separator>";
102 static GQuark            quark_type_separator_item = 0;
103 static const gchar      *key_type_branch = "<Branch>";
104 static GQuark            quark_type_branch = 0;
105 static const gchar      *key_type_last_branch = "<LastBranch>";
106 static GQuark            quark_type_last_branch = 0;
107 static  GScannerConfig  ifactory_scanner_config =
108 {
109   (
110    " \t\n"
111    )                    /* cset_skip_characters */,
112   (
113    G_CSET_a_2_z
114    "_"
115    G_CSET_A_2_Z
116    )                    /* cset_identifier_first */,
117   (
118    G_CSET_a_2_z
119    "-+_0123456789"
120    G_CSET_A_2_Z
121    G_CSET_LATINS
122    G_CSET_LATINC
123    )                    /* cset_identifier_nth */,
124   ( ";\n" )             /* cpair_comment_single */,
125   
126   FALSE                 /* case_sensitive */,
127   
128   TRUE                  /* skip_comment_multi */,
129   TRUE                  /* skip_comment_single */,
130   FALSE                 /* scan_comment_multi */,
131   TRUE                  /* scan_identifier */,
132   FALSE                 /* scan_identifier_1char */,
133   FALSE                 /* scan_identifier_NULL */,
134   TRUE                  /* scan_symbols */,
135   TRUE                  /* scan_binary */,
136   TRUE                  /* scan_octal */,
137   TRUE                  /* scan_float */,
138   TRUE                  /* scan_hex */,
139   FALSE                 /* scan_hex_dollar */,
140   TRUE                  /* scan_string_sq */,
141   TRUE                  /* scan_string_dq */,
142   TRUE                  /* numbers_2_int */,
143   FALSE                 /* int_2_float */,
144   FALSE                 /* identifier_2_string */,
145   TRUE                  /* char_2_token */,
146   FALSE                 /* symbol_2_token */,
147 };
148
149
150 /* --- functions --- */
151 GtkType
152 gtk_item_factory_get_type (void)
153 {
154   static GtkType item_factory_type = 0;
155   
156   if (!item_factory_type)
157     {
158       GtkTypeInfo item_factory_info =
159       {
160         "GtkItemFactory",
161         sizeof (GtkItemFactory),
162         sizeof (GtkItemFactoryClass),
163         (GtkClassInitFunc) gtk_item_factory_class_init,
164         (GtkObjectInitFunc) gtk_item_factory_init,
165         /* reserved_1 */ NULL,
166         /* reserved_2 */ NULL,
167         (GtkClassInitFunc) NULL,
168       };
169       
170       item_factory_type = gtk_type_unique (GTK_TYPE_OBJECT, &item_factory_info);
171     }
172   
173   return item_factory_type;
174 }
175
176 static void
177 gtk_item_factory_class_init (GtkItemFactoryClass  *class)
178 {
179   GtkObjectClass *object_class;
180
181   gtk_item_factory_class = class;
182
183   parent_class = gtk_type_class (GTK_TYPE_OBJECT);
184
185   object_class = (GtkObjectClass*) class;
186
187   object_class->destroy = gtk_item_factory_destroy;
188   object_class->finalize = gtk_item_factory_finalize;
189
190   class->cpair_comment_single = g_strdup (";\n");
191
192   class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
193   ifactory_item_chunks =
194     g_mem_chunk_new ("GtkItemFactoryItem",
195                      sizeof (GtkItemFactoryItem),
196                      sizeof (GtkItemFactoryItem) * ITEM_BLOCK_SIZE,
197                      G_ALLOC_ONLY);
198   ifactory_cb_data_chunks =
199     g_mem_chunk_new ("GtkIFCBData",
200                      sizeof (GtkIFCBData),
201                      sizeof (GtkIFCBData) * ITEM_BLOCK_SIZE,
202                      G_ALLOC_AND_FREE);
203
204   quark_popup_data = g_quark_from_static_string (key_popup_data);
205   quark_if_menu_pos = g_quark_from_static_string (key_if_menu_pos);
206   quark_item_factory = g_quark_from_static_string (key_item_factory);
207   quark_item_factory_path = g_quark_from_static_string (key_item_factory_path);
208   quark_type_item = g_quark_from_static_string (key_type_item);
209   quark_type_title = g_quark_from_static_string (key_type_title);
210   quark_type_radio_item = g_quark_from_static_string (key_type_radio_item);
211   quark_type_check_item = g_quark_from_static_string (key_type_check_item);
212   quark_type_toggle_item = g_quark_from_static_string (key_type_toggle_item);
213   quark_type_separator_item = g_quark_from_static_string (key_type_separator_item);
214   quark_type_branch = g_quark_from_static_string (key_type_branch);
215   quark_type_last_branch = g_quark_from_static_string (key_type_last_branch);
216 }
217
218 static void
219 gtk_item_factory_init (GtkItemFactory       *ifactory)
220 {
221   GtkObject *object;
222
223   object = GTK_OBJECT (ifactory);
224
225   ifactory->path = NULL;
226   ifactory->accel_group = NULL;
227   ifactory->widget = NULL;
228   ifactory->widgets_by_action = NULL;
229 }
230
231 GtkItemFactory*
232 gtk_item_factory_new (GtkType        container_type,
233                       const gchar   *path,
234                       GtkAccelGroup *accel_group)
235 {
236   GtkItemFactory *ifactory;
237
238   g_return_val_if_fail (path != NULL, NULL);
239
240   ifactory = gtk_type_new (GTK_TYPE_ITEM_FACTORY);
241   gtk_item_factory_construct (ifactory, container_type, path, accel_group);
242
243   return ifactory;
244 }
245
246 static void
247 gtk_item_factory_callback_marshal (GtkWidget *widget,
248                                    gpointer   func_data)
249 {
250   GtkIFCBData *data;
251
252   data = func_data;
253
254   if (data->callback_type == 1)
255     {
256       GtkItemFactoryCallback1 func1 = data->func;
257       func1 (data->func_data, data->callback_action, widget);
258     }
259   else if (data->callback_type == 2)
260     {
261       GtkItemFactoryCallback2 func2 = data->func;
262       func2 (widget, data->func_data, data->callback_action);
263     }
264 }
265
266 static void
267 gtk_item_factory_propagate_accelerator (GtkItemFactoryItem *item,
268                                         GtkWidget          *exclude)
269 {
270   GSList *widget_list;
271   GSList *slist;
272   
273   if (item->in_propagation)
274     return;
275   
276   item->in_propagation = TRUE;
277   
278   widget_list = NULL;
279   for (slist = item->widgets; slist; slist = slist->next)
280     {
281       GtkWidget *widget;
282       
283       widget = slist->data;
284       
285       if (widget != exclude)
286         {
287           gtk_widget_ref (widget);
288           widget_list = g_slist_prepend (widget_list, widget);
289         }
290     }
291   
292   for (slist = widget_list; slist; slist = slist->next)
293     {
294       GtkWidget *widget;
295       GtkItemFactory *ifactory;
296       
297       widget = slist->data;
298       
299       ifactory = gtk_item_factory_from_widget (widget);
300       
301       if (ifactory)
302         {
303           guint signal_id;
304           
305           signal_id = gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget));
306           if (signal_id)
307             {
308               if (item->accelerator_key)
309                 gtk_widget_add_accelerator (widget,
310                                             "activate",
311                                             ifactory->accel_group,
312                                             item->accelerator_key,
313                                             item->accelerator_mods,
314                                             GTK_ACCEL_VISIBLE);
315               else
316                 {
317                   GSList *slist;
318                   
319                   slist = gtk_accel_group_entries_from_object (GTK_OBJECT (widget));
320                   while (slist)
321                     {
322                       GtkAccelEntry *ac_entry;
323                       
324                       ac_entry = slist->data;
325                       slist = slist->next;
326                       if (ac_entry->accel_flags & GTK_ACCEL_VISIBLE &&
327                           ac_entry->accel_group == ifactory->accel_group &&
328                           ac_entry->signal_id == signal_id)
329                         gtk_widget_remove_accelerator (GTK_WIDGET (widget),
330                                                        ac_entry->accel_group,
331                                                        ac_entry->accelerator_key,
332                                                        ac_entry->accelerator_mods);
333                     }
334                 }
335             }
336         }
337       gtk_widget_unref (widget);
338     }
339   g_slist_free (widget_list);
340   
341   item->in_propagation = FALSE;
342 }
343
344 static gint
345 gtk_item_factory_item_add_accelerator (GtkWidget          *widget,
346                                        guint               accel_signal_id,
347                                        GtkAccelGroup      *accel_group,
348                                        guint               accel_key,
349                                        guint               accel_mods,
350                                        GtkAccelFlags       accel_flags,
351                                        GtkItemFactoryItem *item)
352 {
353   if (!item->in_propagation &&
354       g_slist_find (item->widgets, widget) &&
355       accel_signal_id == gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
356     {
357       item->accelerator_key = accel_key;
358       item->accelerator_mods = accel_mods;
359       item->modified = TRUE;
360       
361       gtk_item_factory_propagate_accelerator (item, widget);
362     }
363
364   return TRUE;
365 }
366
367 static void
368 gtk_item_factory_item_remove_accelerator (GtkWidget          *widget,
369                                           GtkAccelGroup      *accel_group,
370                                           guint               accel_key,
371                                           guint               accel_mods,
372                                           GtkItemFactoryItem *item)
373 {
374   if (!item->in_propagation &&
375       g_slist_find (item->widgets, widget) &&
376       item->accelerator_key == accel_key &&
377       item->accelerator_mods == accel_mods)
378     {
379       item->accelerator_key = 0;
380       item->accelerator_mods = 0;
381       item->modified = TRUE;
382       
383       gtk_item_factory_propagate_accelerator (item, widget);
384     }
385 }
386
387 static void
388 gtk_item_factory_item_remove_widget (GtkWidget          *widget,
389                                      GtkItemFactoryItem *item)
390 {
391   item->widgets = g_slist_remove (item->widgets, widget);
392   gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory);
393   gtk_object_remove_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
394 }
395
396 static void
397 ifactory_cb_data_free (gpointer mem)
398 {
399   g_mem_chunk_free (ifactory_cb_data_chunks, mem);
400 }
401
402 static void
403 gtk_item_factory_add_item (GtkItemFactory               *ifactory,
404                            const gchar                  *path,
405                            const gchar                  *accelerator,
406                            GtkItemFactoryCallback       callback,
407                            guint                        callback_action,
408                            gpointer                     callback_data,
409                            guint                        callback_type,
410                            gchar                        *item_type,
411                            GtkWidget                    *widget)
412 {
413   GtkItemFactoryClass *class;
414   GtkItemFactoryItem *item;
415   gchar *fpath;
416   
417   g_return_if_fail (widget != NULL);
418   g_return_if_fail (item_type != NULL);
419
420   class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
421
422   fpath = g_strconcat (ifactory->path, path, NULL);
423   item = g_hash_table_lookup (class->item_ht, fpath);
424
425   /* link the widget into its item-entry
426    */
427   if (!item)
428     {
429       guint keyval;
430       guint mods;
431
432       if (accelerator)
433         gtk_accelerator_parse (accelerator, &keyval, &mods);
434       else
435         {
436           keyval = 0;
437           mods = 0;
438         }
439
440       item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
441
442       item->path = fpath;
443       fpath = NULL;
444       item->accelerator_key = keyval;
445       item->accelerator_mods = mods;
446       item->modified = FALSE;
447       item->in_propagation = FALSE;
448       item->item_type = NULL;
449       item->widgets = NULL;
450       
451       g_hash_table_insert (class->item_ht, item->path, item);
452     }
453   g_free (fpath);
454
455   if (item->item_type == NULL)
456     {
457       g_assert (item->widgets == NULL);
458       
459       if (item_type != ITEM_FACTORY_STRING)
460         item->item_type = g_strdup (item_type);
461       else
462         item->item_type = ITEM_FACTORY_STRING;
463     }
464
465   item->widgets = g_slist_prepend (item->widgets, widget);
466   gtk_signal_connect (GTK_OBJECT (widget),
467                       "destroy",
468                       GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_widget),
469                       item);
470
471   /* set back pointers for the widget
472    */
473   gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory, ifactory);
474   gtk_object_set_data_by_id (GTK_OBJECT (widget), quark_item_factory_path, item->path);
475   gtk_widget_set_name (widget, item->path);
476
477   /* set accelerator group on menu widgets
478    */
479   if (GTK_IS_MENU (widget))
480     gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
481
482   /* install defined accelerators
483    */
484   if (gtk_signal_lookup ("activate", GTK_OBJECT_TYPE (widget)))
485     {
486       if (item->accelerator_key)
487         gtk_widget_add_accelerator (widget,
488                                     "activate",
489                                     ifactory->accel_group,
490                                     item->accelerator_key,
491                                     item->accelerator_mods,
492                                     GTK_ACCEL_VISIBLE);
493       else
494         gtk_widget_remove_accelerators (widget,
495                                         "activate",
496                                         TRUE);
497     }
498
499   /* keep track of accelerator changes
500    */
501   gtk_signal_connect_after (GTK_OBJECT (widget),
502                             "add-accelerator",
503                             GTK_SIGNAL_FUNC (gtk_item_factory_item_add_accelerator),
504                             item);
505   gtk_signal_connect_after (GTK_OBJECT (widget),
506                             "remove-accelerator",
507                             GTK_SIGNAL_FUNC (gtk_item_factory_item_remove_accelerator),
508                             item);
509
510   /* keep a per-action list of the widgets on the factory
511    */
512   if (callback_action)
513     {
514       GtkIFActionLink *link;
515
516       link = g_new (GtkIFActionLink, 1);
517       link->widget = widget;
518       link->callback_action = callback_action;
519       ifactory->widgets_by_action = g_slist_prepend (ifactory->widgets_by_action, link);
520     }
521
522   /* connect callback if neccessary
523    */
524   if (callback)
525     {
526       GtkIFCBData *data;
527
528       data = g_chunk_new (GtkIFCBData, ifactory_cb_data_chunks);
529       data->func = callback;
530       data->callback_type = callback_type;
531       data->func_data = callback_data;
532       data->callback_action = callback_action;
533
534       gtk_object_weakref (GTK_OBJECT (widget),
535                           ifactory_cb_data_free,
536                           data);
537       gtk_signal_connect (GTK_OBJECT (widget),
538                           "activate",
539                           GTK_SIGNAL_FUNC (gtk_item_factory_callback_marshal),
540                           data);
541     }
542 }
543
544 void
545 gtk_item_factory_construct (GtkItemFactory      *ifactory,
546                             GtkType              container_type,
547                             const gchar         *path,
548                             GtkAccelGroup       *accel_group)
549 {
550   guint len;
551
552   g_return_if_fail (ifactory != NULL);
553   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
554   g_return_if_fail (ifactory->accel_group == NULL);
555   g_return_if_fail (path != NULL);
556   if (!gtk_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
557     g_return_if_fail (gtk_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
558
559   len = strlen (path);
560
561   if (path[0] != '<' && path[len - 1] != '>')
562     {
563       g_warning ("GtkItemFactory: invalid factory path `%s'", path);
564       return;
565     }
566
567   if (accel_group)
568     {
569       ifactory->accel_group = accel_group;
570       gtk_accel_group_ref (ifactory->accel_group);
571     }
572   else
573     ifactory->accel_group = gtk_accel_group_new ();
574
575   ifactory->path = g_strdup (path);
576   ifactory->widget =
577     gtk_widget_new (container_type,
578                     "GtkObject::signal::destroy", gtk_widget_destroyed, &ifactory->widget,
579                     NULL);
580   gtk_object_ref (GTK_OBJECT (ifactory));
581   gtk_object_sink (GTK_OBJECT (ifactory));
582   /*
583     gtk_signal_connect_object_while_alive (GTK_OBJECT (ifactory->widget),
584                                          "destroy",
585                                          GTK_SIGNAL_FUNC (gtk_object_destroy),
586                                          GTK_OBJECT (ifactory));
587   */
588   gtk_item_factory_add_item (ifactory,
589                              "", NULL,
590                              NULL, 0, NULL, 0,
591                              ITEM_FACTORY_STRING,
592                              ifactory->widget);
593 }
594
595 GtkItemFactory*
596 gtk_item_factory_from_path (const gchar      *path)
597 {
598   GtkItemFactoryClass *class;
599   GtkItemFactoryItem *item;
600   gchar *fname;
601   guint i;
602
603   g_return_val_if_fail (path != NULL, NULL);
604   g_return_val_if_fail (path[0] == '<', NULL);
605
606   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
607
608   i = 0;
609   while (path[i] && path[i] != '>')
610     i++;
611   if (path[i] != '>')
612     {
613       g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
614                  path);
615       return NULL;
616     }
617   fname = g_new (gchar, i + 2);
618   g_memmove (fname, path, i + 1);
619   fname[i + 1] = 0;
620
621   item = g_hash_table_lookup (class->item_ht, fname);
622   if (item && item->widgets)
623     return gtk_item_factory_from_widget (item->widgets->data);
624
625   return NULL;
626 }
627
628 static void
629 gtk_item_factory_destroy (GtkObject              *object)
630 {
631   GtkItemFactory *ifactory;
632   GSList *slist;
633
634   g_return_if_fail (object != NULL);
635   g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
636
637   ifactory = (GtkItemFactory*) object;
638
639   if (ifactory->widget)
640     {
641       GtkObject *object;
642
643       object = GTK_OBJECT (ifactory->widget);
644
645       gtk_object_ref (object);
646       gtk_object_sink (object);
647       gtk_object_destroy (object);
648       gtk_object_unref (object);
649
650       ifactory->widget = NULL;
651     }
652
653   for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
654     g_free (slist->data);
655   g_slist_free (ifactory->widgets_by_action);
656   ifactory->widgets_by_action = NULL;
657
658   parent_class->destroy (object);
659 }
660
661 static void
662 gtk_item_factory_finalize (GtkObject              *object)
663 {
664   GtkItemFactory *ifactory;
665
666   g_return_if_fail (object != NULL);
667   g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
668
669   ifactory = GTK_ITEM_FACTORY (object);
670
671   gtk_accel_group_unref (ifactory->accel_group);
672   g_free (ifactory->path);
673   g_assert (ifactory->widget == NULL);
674
675   parent_class->finalize (object);
676 }
677
678 GtkItemFactory*
679 gtk_item_factory_from_widget (GtkWidget        *widget)
680 {
681   g_return_val_if_fail (widget != NULL, NULL);
682   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
683
684   return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory);
685 }
686
687 gchar*
688 gtk_item_factory_path_from_widget (GtkWidget        *widget)
689 {
690   g_return_val_if_fail (widget != NULL, NULL);
691   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
692
693   return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_factory_path);
694 }
695
696 static void
697 gtk_item_factory_foreach (gpointer hash_key,
698                           gpointer value,
699                           gpointer user_data)
700 {
701   GtkItemFactoryItem *item;
702   GtkIFDumpData *data;
703   gchar *string;
704   gchar *name;
705   gchar comment_prefix[2] = "\000\000";
706
707   item = value;
708   data = user_data;
709
710   if (data->pspec && !gtk_pattern_match_string (data->pspec, item->path))
711     return;
712
713   comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
714
715   name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
716   string = g_strconcat (item->modified ? "" : comment_prefix,
717                         "(menu-path \"",
718                         hash_key,
719                         "\" \"",
720                         name,
721                         "\")",
722                         NULL);
723   g_free (name);
724
725   data->print_func (data->func_data, string);
726
727   g_free (string);
728 }
729
730 void
731 gtk_item_factory_dump_items (GtkPatternSpec      *path_pspec,
732                              gboolean             modified_only,
733                              GtkPrintFunc         print_func,
734                              gpointer             func_data)
735 {
736   GtkIFDumpData data;
737
738   g_return_if_fail (print_func != NULL);
739
740   if (!gtk_item_factory_class)
741     gtk_type_class (GTK_TYPE_ITEM_FACTORY);
742
743   data.print_func = print_func;
744   data.func_data = func_data;
745   data.modified_only = (modified_only != FALSE);
746   data.pspec = path_pspec;
747
748   g_hash_table_foreach (gtk_item_factory_class->item_ht, gtk_item_factory_foreach, &data);
749 }
750
751 void
752 gtk_item_factory_print_func (gpointer FILE_pointer,
753                              gchar   *string)
754 {
755   FILE *f_out = FILE_pointer;
756
757   g_return_if_fail (FILE_pointer != NULL);
758   g_return_if_fail (string != NULL);
759   
760   fputs (string, f_out);
761   fputc ('\n', f_out);
762 }
763
764 void
765 gtk_item_factory_dump_rc (const gchar            *file_name,
766                           GtkPatternSpec         *path_pspec,
767                           gboolean                modified_only)
768 {
769   FILE *f_out;
770
771   g_return_if_fail (file_name != NULL);
772
773   f_out = fopen (file_name, "w");
774   if (!f_out)
775     return;
776
777   fputs ("; ", f_out);
778   if (gdk_progname)
779     fputs (gdk_progname, f_out);
780   fputs (" GtkItemFactory rc-file         -*- scheme -*-\n", f_out);
781   fputs ("; this file is an automated menu-path dump\n", f_out);
782   fputs (";\n", f_out);
783
784   gtk_item_factory_dump_items (path_pspec,
785                                modified_only,
786                                gtk_item_factory_print_func,
787                                f_out);
788
789   fclose (f_out);
790 }
791
792 void
793 gtk_item_factory_create_items (GtkItemFactory         *ifactory,
794                                guint                   n_entries,
795                                GtkItemFactoryEntry    *entries,
796                                gpointer                callback_data)
797 {
798   gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
799 }
800
801 void
802 gtk_item_factory_create_items_ac (GtkItemFactory       *ifactory,
803                                   guint                 n_entries,
804                                   GtkItemFactoryEntry  *entries,
805                                   gpointer              callback_data,
806                                   guint                 callback_type)
807 {
808   guint i;
809
810   g_return_if_fail (ifactory != NULL);
811   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
812   g_return_if_fail (callback_type >= 1 && callback_type <= 2);
813
814   if (n_entries == 0)
815     return;
816
817   g_return_if_fail (entries != NULL);
818
819   for (i = 0; i < n_entries; i++)
820     gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
821 }
822
823 GtkWidget*
824 gtk_item_factory_get_widget (GtkItemFactory   *ifactory,
825                              const gchar      *path)
826 {
827   GtkItemFactoryClass *class;
828   GtkItemFactoryItem *item;
829
830   g_return_val_if_fail (ifactory != NULL, NULL);
831   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
832   g_return_val_if_fail (path != NULL, NULL);
833
834   class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
835
836   if (path[0] == '<')
837     item = g_hash_table_lookup (class->item_ht, (gpointer) path);
838   else
839     {
840       gchar *fpath;
841
842       fpath = g_strconcat (ifactory->path, path, NULL);
843       item = g_hash_table_lookup (class->item_ht, fpath);
844       g_free (fpath);
845     }
846
847   if (item)
848     {
849       GSList *slist;
850
851       for (slist = item->widgets; slist; slist = slist->next)
852         {
853           if (gtk_item_factory_from_widget (slist->data) == ifactory)
854             return slist->data;
855         }
856     }
857
858   return NULL;
859 }
860
861 GtkWidget*
862 gtk_item_factory_get_widget_by_action (GtkItemFactory   *ifactory,
863                                        guint             action)
864 {
865   GSList *slist;
866
867   g_return_val_if_fail (ifactory != NULL, NULL);
868   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
869
870   for (slist = ifactory->widgets_by_action; slist; slist = slist->next)
871     {
872       GtkIFActionLink *link;
873
874       link = slist->data;
875
876       if (link->callback_action == action)
877         return link->widget;
878     }
879
880   return NULL;
881 }
882
883 void
884 gtk_item_factory_create_item (GtkItemFactory         *ifactory,
885                               GtkItemFactoryEntry    *entry,
886                               gpointer                callback_data,
887                               guint                   callback_type)
888 {
889   GtkWidget *parent;
890   GtkWidget *widget;
891   GSList *radio_group;
892   gchar *parent_path;
893   gchar *p;
894   guint type_id;
895   GtkType type;
896   gchar *item_type_path;
897
898   g_return_if_fail (ifactory != NULL);
899   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
900   g_return_if_fail (entry != NULL);
901   g_return_if_fail (entry->path != NULL);
902   g_return_if_fail (entry->path[0] == '/');
903   g_return_if_fail (callback_type >= 1 && callback_type <= 2);
904
905   if (!entry->item_type ||
906       entry->item_type[0] == 0)
907     {
908       item_type_path = (gpointer) key_type_item;
909       type_id = quark_type_item;
910     }
911   else
912     {
913       item_type_path = entry->item_type;
914       type_id = gtk_object_data_try_key (item_type_path);
915     }
916
917   radio_group = NULL;
918   if (type_id == quark_type_item)
919     type = GTK_TYPE_MENU_ITEM;
920   else if (type_id == quark_type_title)
921     type = GTK_TYPE_MENU_ITEM;
922   else if (type_id == quark_type_radio_item)
923     type = GTK_TYPE_RADIO_MENU_ITEM;
924   else if (type_id == quark_type_check_item)
925     type = GTK_TYPE_CHECK_MENU_ITEM;
926   else if (type_id == quark_type_toggle_item)
927     type = GTK_TYPE_CHECK_MENU_ITEM;
928   else if (type_id == quark_type_separator_item)
929     type = GTK_TYPE_MENU_ITEM;
930   else if (type_id == quark_type_branch)
931     type = GTK_TYPE_MENU_ITEM;
932   else if (type_id == quark_type_last_branch)
933     type = GTK_TYPE_MENU_ITEM;
934   else
935     {
936       GtkWidget *radio_link;
937
938       radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
939       if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
940         {
941           type = GTK_TYPE_RADIO_MENU_ITEM;
942           radio_group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (radio_link));
943         }
944       else
945         {
946           g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
947                      entry->path,
948                      item_type_path);
949           return;
950         }
951     }
952   
953   parent_path = g_strdup (entry->path);
954   p = strrchr (parent_path, '/');
955   if (!p)
956     {
957       g_warning ("GtkItemFactory: invalid entry path `%s'", entry->path);
958       return;
959     }
960   *p = 0;
961
962   parent = gtk_item_factory_get_widget (ifactory, parent_path);
963   if (!parent)
964     {
965       GtkItemFactoryEntry pentry;
966
967       pentry.path = parent_path;
968       pentry.accelerator = NULL;
969       pentry.callback = NULL;
970       pentry.callback_action = 0;
971       pentry.item_type = "<Branch>";
972
973       gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
974
975       parent = gtk_item_factory_get_widget (ifactory, parent_path);
976     }
977   g_free (parent_path);
978
979   g_return_if_fail (parent != NULL);
980   
981   p = strrchr (entry->path, '/');
982   p++;
983   
984   widget = gtk_widget_new (type,
985                            "GtkWidget::visible", TRUE,
986                            "GtkWidget::sensitive", (type_id != quark_type_separator_item &&
987                                                     type_id != quark_type_title),
988                            "GtkWidget::parent", parent,
989                            NULL);
990
991   if (type == GTK_TYPE_RADIO_MENU_ITEM)
992     gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
993   if (GTK_IS_CHECK_MENU_ITEM (widget))
994     gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
995     
996   if (type_id != quark_type_separator_item && *p)
997     {
998       GtkWidget *label;
999       
1000       label =
1001         gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1002                         "GtkLabel::label", p,
1003                         "GtkWidget::visible", TRUE,
1004                         "GtkWidget::parent", widget,
1005                         "GtkAccelLabel::accel_widget", widget,
1006                         "GtkMisc::xalign", 0.0,
1007                         NULL);
1008     }
1009   if (type_id == quark_type_branch ||
1010       type_id == quark_type_last_branch)
1011     {
1012       if (type_id == quark_type_last_branch)
1013         gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1014         
1015       parent = widget;
1016       widget =
1017         gtk_widget_new (GTK_TYPE_MENU,
1018                         NULL);
1019       gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1020     }      
1021   
1022   gtk_item_factory_add_item (ifactory,
1023                              entry->path, entry->accelerator,
1024                              entry->callback, entry->callback_action, callback_data,
1025                              callback_type,
1026                              item_type_path,
1027                              widget);
1028 }
1029
1030 void
1031 gtk_item_factory_create_menu_entries (guint              n_entries,
1032                                       GtkMenuEntry      *entries)
1033 {
1034   static GtkPatternSpec pspec_separator = { 42, 0 };
1035   static GtkPatternSpec pspec_check = { 42, 0 };
1036   guint i;
1037
1038   if (!n_entries)
1039     return;
1040   g_return_if_fail (entries != NULL);
1041
1042   if (pspec_separator.pattern_length == 0)
1043     {
1044       gtk_pattern_spec_init (&pspec_separator, "*<separator>*");
1045       gtk_pattern_spec_init (&pspec_check, "*<check>*");
1046     }
1047
1048   for (i = 0; i < n_entries; i++)
1049     {
1050       GtkItemFactory *ifactory;
1051       GtkItemFactoryEntry entry;
1052       gchar *path;
1053       gchar *cpath;
1054
1055       path = entries[i].path;
1056       ifactory = gtk_item_factory_from_path (path);
1057       if (!ifactory)
1058         {
1059           g_warning ("gtk_item_factory_create_menu_entries(): "
1060                      "entry[%u] refers to unknown item factory: \"%s\"",
1061                      i, entries[i].path);
1062           continue;
1063         }
1064
1065       while (*path != '>')
1066         path++;
1067       path++;
1068       cpath = NULL;
1069
1070       entry.path = path;
1071       entry.accelerator = entries[i].accelerator;
1072       entry.callback = entries[i].callback;
1073       entry.callback_action = 0;
1074       if (gtk_pattern_match_string (&pspec_separator, path))
1075         entry.item_type = (gpointer) key_type_separator_item;
1076       else if (!gtk_pattern_match_string (&pspec_check, path))
1077         entry.item_type = NULL;
1078       else
1079         {
1080           gboolean in_brace = FALSE;
1081           gchar *c;
1082           
1083           cpath = g_new (gchar, strlen (path));
1084           c = cpath;
1085           while (*path != 0)
1086             {
1087               if (*path == '<')
1088                 in_brace = TRUE;
1089               else if (*path == '>')
1090                 in_brace = FALSE;
1091               else if (!in_brace)
1092                 *(c++) = *path;
1093               path++;
1094             }
1095           *c = 0;
1096           entry.item_type = (gpointer) key_type_toggle_item;
1097           entry.path = cpath;
1098         }
1099       
1100       gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1101       entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1102       g_free (cpath);
1103     }
1104 }
1105
1106 void
1107 gtk_item_factories_path_delete (const gchar *ifactory_path,
1108                                 const gchar *path)
1109 {
1110   GtkItemFactoryClass *class;
1111   GtkItemFactoryItem *item;
1112
1113   g_return_if_fail (path != NULL);
1114
1115   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1116
1117   if (path[0] == '<')
1118     item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1119   else
1120     {
1121       gchar *fpath;
1122
1123       g_return_if_fail (ifactory_path != NULL);
1124       
1125       fpath = g_strconcat (ifactory_path, path, NULL);
1126       item = g_hash_table_lookup (class->item_ht, fpath);
1127       g_free (fpath);
1128     }
1129   
1130   if (item)
1131     {
1132       GSList *widget_list;
1133       GSList *slist;
1134
1135       widget_list = NULL;
1136       for (slist = item->widgets; slist; slist = slist->next)
1137         {
1138           GtkWidget *widget;
1139
1140           widget = slist->data;
1141           widget_list = g_slist_prepend (widget_list, widget);
1142           gtk_widget_ref (widget);
1143         }
1144
1145       for (slist = widget_list; slist; slist = slist->next)
1146         {
1147           GtkWidget *widget;
1148
1149           widget = slist->data;
1150           gtk_widget_destroy (widget);
1151           gtk_widget_unref (widget);
1152         }
1153       g_slist_free (widget_list);
1154     }
1155 }
1156
1157 void
1158 gtk_item_factory_delete_item (GtkItemFactory         *ifactory,
1159                               const gchar            *path)
1160 {
1161   GtkItemFactoryClass *class;
1162   GtkItemFactoryItem *item;
1163   gchar *fpath;
1164
1165   g_return_if_fail (ifactory != NULL);
1166   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1167   g_return_if_fail (path != NULL);
1168
1169   class = GTK_ITEM_FACTORY_CLASS (GTK_OBJECT (ifactory)->klass);
1170
1171   fpath = g_strconcat (ifactory->path, path, NULL);
1172   item = g_hash_table_lookup (class->item_ht, fpath);
1173   g_free (fpath);
1174
1175   if (item)
1176     {
1177       GtkWidget *widget = NULL;
1178       GSList *slist;
1179
1180       for (slist = item->widgets; slist; slist = slist->next)
1181         {
1182           widget = slist->data;
1183
1184           if (gtk_item_factory_from_widget (widget) == ifactory)
1185             break;
1186         }
1187
1188       if (slist)
1189         gtk_widget_destroy (widget);
1190     }
1191 }
1192
1193 void
1194 gtk_item_factory_delete_entry (GtkItemFactory         *ifactory,
1195                                GtkItemFactoryEntry    *entry)
1196 {
1197   g_return_if_fail (ifactory != NULL);
1198   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1199   g_return_if_fail (entry != NULL);
1200
1201   gtk_item_factory_delete_item (ifactory, entry->path);
1202 }
1203
1204 void
1205 gtk_item_factory_delete_entries (GtkItemFactory         *ifactory,
1206                                  guint                   n_entries,
1207                                  GtkItemFactoryEntry    *entries)
1208 {
1209   guint i;
1210
1211   g_return_if_fail (ifactory != NULL);
1212   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1213   if (n_entries > 0)
1214     g_return_if_fail (entries != NULL);
1215
1216   for (i = 0; i < n_entries; i++)
1217     gtk_item_factory_delete_item (ifactory, (entries + i)->path);
1218 }
1219
1220 typedef struct
1221 {
1222   guint x;
1223   guint y;
1224 } MenuPos;
1225
1226 static void
1227 gtk_item_factory_menu_pos (GtkMenu  *menu,
1228                            gint     *x,
1229                            gint     *y,
1230                            gpointer  func_data)
1231 {
1232   MenuPos *mpos = func_data;
1233
1234   *x = mpos->x;
1235   *y = mpos->y;
1236 }
1237
1238 gpointer
1239 gtk_item_factory_popup_data_from_widget (GtkWidget     *widget)
1240 {
1241   GtkItemFactory *ifactory;
1242   
1243   g_return_val_if_fail (widget != NULL, NULL);
1244   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1245
1246   ifactory = gtk_item_factory_from_widget (widget);
1247   if (ifactory)
1248     return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1249
1250   return NULL;
1251 }
1252
1253 gpointer
1254 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1255 {
1256   g_return_val_if_fail (ifactory != NULL, NULL);
1257   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1258
1259   return gtk_object_get_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1260 }
1261
1262 static void
1263 ifactory_delete_popup_data (GtkObject      *object,
1264                             GtkItemFactory *ifactory)
1265 {
1266   gtk_signal_disconnect_by_func (object,
1267                                  GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1268                                  ifactory);
1269   gtk_object_remove_data_by_id (GTK_OBJECT (ifactory), quark_popup_data);
1270 }
1271
1272 void
1273 gtk_item_factory_popup (GtkItemFactory          *ifactory,
1274                         guint                    x,
1275                         guint                    y,
1276                         guint                    mouse_button,
1277                         guint32                  time)
1278 {
1279   gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1280 }
1281
1282 void
1283 gtk_item_factory_popup_with_data (GtkItemFactory        *ifactory,
1284                                   gpointer               popup_data,
1285                                   GtkDestroyNotify       destroy,
1286                                   guint                  x,
1287                                   guint                  y,
1288                                   guint                  mouse_button,
1289                                   guint32                time)
1290 {
1291   g_return_if_fail (ifactory != NULL);
1292   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1293   g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1294
1295   if (!GTK_WIDGET_VISIBLE (ifactory->widget))
1296     {
1297       MenuPos *mpos;
1298
1299       mpos = gtk_object_get_data_by_id (GTK_OBJECT (ifactory->widget), quark_if_menu_pos);
1300
1301       if (!mpos)
1302         {
1303           mpos = g_new0 (MenuPos, 1);
1304           gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory->widget),
1305                                           quark_if_menu_pos,
1306                                           mpos,
1307                                           g_free);
1308         }
1309
1310       mpos->x = x;
1311       mpos->y = y;
1312
1313       if (popup_data != NULL)
1314         {
1315           gtk_object_set_data_by_id_full (GTK_OBJECT (ifactory),
1316                                           quark_popup_data,
1317                                           popup_data,
1318                                           destroy);
1319           gtk_signal_connect (GTK_OBJECT (ifactory->widget),
1320                               "selection-done",
1321                               GTK_SIGNAL_FUNC (ifactory_delete_popup_data),
1322                               ifactory);
1323         }
1324
1325       gtk_menu_popup (GTK_MENU (ifactory->widget),
1326                       NULL, NULL,
1327                       gtk_item_factory_menu_pos, mpos,
1328                       mouse_button, time);
1329     }
1330 }
1331
1332 static guint
1333 gtk_item_factory_parse_menu_path (GScanner            *scanner,
1334                                   GtkItemFactoryClass *class)
1335 {
1336   GtkItemFactoryItem *item;
1337   
1338   g_scanner_get_next_token (scanner);
1339   if (scanner->token != G_TOKEN_STRING)
1340     return G_TOKEN_STRING;
1341
1342   g_scanner_peek_next_token (scanner);
1343   if (scanner->next_token != G_TOKEN_STRING)
1344     {
1345       g_scanner_get_next_token (scanner);
1346       return G_TOKEN_STRING;
1347     }
1348
1349   item = g_hash_table_lookup (class->item_ht, scanner->value.v_string);
1350   if (!item)
1351     {
1352       item = g_chunk_new (GtkItemFactoryItem, ifactory_item_chunks);
1353
1354       item->path = g_strdup (scanner->value.v_string);
1355       item->accelerator_key = 0;
1356       item->accelerator_mods = 0;
1357       item->modified = TRUE;
1358       item->in_propagation = FALSE;
1359       item->item_type = NULL;
1360       item->widgets = NULL;
1361
1362       g_hash_table_insert (class->item_ht, item->path, item);
1363     }
1364   g_scanner_get_next_token (scanner);
1365   
1366   if (!item->in_propagation)
1367     {
1368       guint old_keyval;
1369       guint old_mods;
1370       
1371       old_keyval = item->accelerator_key;
1372       old_mods = item->accelerator_mods;
1373       gtk_accelerator_parse (scanner->value.v_string,
1374                              &item->accelerator_key,
1375                              &item->accelerator_mods);
1376       if (old_keyval != item->accelerator_key ||
1377           old_mods != item->accelerator_mods)
1378         {
1379           item->modified = TRUE;
1380           gtk_item_factory_propagate_accelerator (item, NULL);
1381         }
1382     }
1383   
1384   g_scanner_get_next_token (scanner);
1385   if (scanner->token != ')')
1386     return ')';
1387   else
1388     return G_TOKEN_NONE;
1389 }
1390
1391 static void
1392 gtk_item_factory_parse_statement (GScanner            *scanner,
1393                                   GtkItemFactoryClass *class)
1394 {
1395   guint expected_token;
1396   
1397   g_scanner_get_next_token (scanner);
1398   
1399   if (scanner->token == G_TOKEN_SYMBOL)
1400     {
1401       guint (*parser_func) (GScanner*, GtkItemFactoryClass*);
1402
1403       parser_func = scanner->value.v_symbol;
1404
1405       /* check whether this is a GtkItemFactory symbol...
1406        */
1407       if (parser_func == gtk_item_factory_parse_menu_path)
1408         expected_token = parser_func (scanner, class);
1409       else
1410         expected_token = G_TOKEN_SYMBOL;
1411     }
1412   else
1413     expected_token = G_TOKEN_SYMBOL;
1414
1415   /* skip rest of statement on errrors
1416    */
1417   if (expected_token != G_TOKEN_NONE)
1418     {
1419       register guint level;
1420
1421       level = 1;
1422       if (scanner->token == ')')
1423         level--;
1424       if (scanner->token == '(')
1425         level++;
1426       
1427       while (!g_scanner_eof (scanner) && level > 0)
1428         {
1429           g_scanner_get_next_token (scanner);
1430           
1431           if (scanner->token == '(')
1432             level++;
1433           else if (scanner->token == ')')
1434             level--;
1435         }
1436     }
1437 }
1438
1439 void
1440 gtk_item_factory_parse_rc_string (const gchar    *rc_string)
1441 {
1442   GScanner *scanner;
1443
1444   g_return_if_fail (rc_string != NULL);
1445
1446   ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1447   scanner = g_scanner_new (&ifactory_scanner_config);
1448
1449   g_scanner_input_text (scanner, rc_string, strlen (rc_string));
1450
1451   gtk_item_factory_parse_rc_scanner (scanner);
1452
1453   g_scanner_destroy (scanner);
1454 }
1455
1456 void
1457 gtk_item_factory_parse_rc_scanner (GScanner *scanner)
1458 {
1459   gpointer saved_symbol;
1460
1461   g_return_if_fail (scanner != NULL);
1462
1463   if (!gtk_item_factory_class)
1464     gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1465
1466   saved_symbol = g_scanner_lookup_symbol (scanner, "menu-path");
1467   g_scanner_remove_symbol (scanner, "menu-path");
1468   g_scanner_add_symbol (scanner, "menu-path", gtk_item_factory_parse_menu_path);
1469
1470   g_scanner_peek_next_token (scanner);
1471
1472   while (scanner->next_token == '(')
1473     {
1474       g_scanner_get_next_token (scanner);
1475
1476       gtk_item_factory_parse_statement (scanner, gtk_item_factory_class);
1477
1478       g_scanner_peek_next_token (scanner);
1479     }
1480
1481   g_scanner_remove_symbol (scanner, "menu-path");
1482   g_scanner_add_symbol (scanner, "menu-path", saved_symbol);
1483 }
1484
1485 void
1486 gtk_item_factory_parse_rc (const gchar    *file_name)
1487 {
1488   gint fd;
1489   GScanner *scanner;
1490
1491   g_return_if_fail (file_name != NULL);
1492
1493   if (!S_ISREG (g_scanner_stat_mode (file_name)))
1494     return;
1495
1496   fd = open (file_name, O_RDONLY);
1497   if (fd < 0)
1498     return;
1499
1500   ifactory_scanner_config.cpair_comment_single = gtk_item_factory_class->cpair_comment_single;
1501   scanner = g_scanner_new (&ifactory_scanner_config);
1502
1503   g_scanner_input_file (scanner, fd);
1504
1505   gtk_item_factory_parse_rc_scanner (scanner);
1506
1507   g_scanner_destroy (scanner);
1508
1509   close (fd);
1510 }