source: trunk/third/gtk/gtk/gtkitemfactory.c @ 15781

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