]> Pileus Git - ~andy/gtk/blob - gtk/gtkitemfactory.c
Use g_slice instead of mem chunks.
[~andy/gtk] / gtk / gtkitemfactory.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkItemFactory: Flexible item factory with automatic rc handling
5  * Copyright (C) 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 #include        <config.h>
31
32 #include        "gtkitemfactory.h"
33 #include        "gtk/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/gtkimagemenuitem.h"
39 #include        "gtk/gtktearoffmenuitem.h"
40 #include        "gtk/gtkaccelmap.h"
41 #include        "gtk/gtkaccellabel.h"
42 #include        "gdk/gdkkeysyms.h"
43 #include        "gtk/gtkimage.h"
44 #include        "gtk/gtkstock.h"
45 #include        "gtk/gtkiconfactory.h"
46 #include        "gtkintl.h"
47 #include        <string.h>
48 #include        <fcntl.h>
49 #ifdef HAVE_UNISTD_H
50 #include        <unistd.h>
51 #endif
52 #include        <stdio.h>
53
54 #undef GTK_DISABLE_DEPRECATED
55 #include        "gtk/gtkoptionmenu.h"
56 #define GTK_DISABLE_DEPRECATED
57 #include        "gtkalias.h"
58
59 /* --- defines --- */
60 #define         ITEM_FACTORY_STRING     ((gchar*) item_factory_string)
61 #define         ITEM_BLOCK_SIZE         (128)
62
63
64 /* --- structures --- */
65 typedef struct  _GtkIFCBData            GtkIFCBData;
66 typedef struct  _GtkIFDumpData          GtkIFDumpData;
67 struct _GtkIFCBData
68 {
69   GtkItemFactoryCallback  func;
70   guint                   callback_type;
71   gpointer                func_data;
72   guint                   callback_action;
73 };
74
75
76 /* --- prototypes --- */
77 static void     gtk_item_factory_class_init             (GtkItemFactoryClass  *klass);
78 static void     gtk_item_factory_init                   (GtkItemFactory       *ifactory);
79 static void     gtk_item_factory_destroy                (GtkObject            *object);
80 static void     gtk_item_factory_finalize               (GObject              *object);
81
82
83 /* --- static variables --- */
84 static GtkItemFactoryClass *gtk_item_factory_class = NULL;
85 static gpointer          parent_class = NULL;
86 static const gchar       item_factory_string[] = "Gtk-<ItemFactory>";
87 static GQuark            quark_popup_data = 0;
88 static GQuark            quark_if_menu_pos = 0;
89 static GQuark            quark_item_factory = 0;
90 static GQuark            quark_item_path = 0;
91 static GQuark            quark_action = 0;
92 static GQuark            quark_accel_group = 0;
93 static GQuark            quark_type_item = 0;
94 static GQuark            quark_type_title = 0;
95 static GQuark            quark_type_radio_item = 0;
96 static GQuark            quark_type_check_item = 0;
97 static GQuark            quark_type_toggle_item = 0;
98 static GQuark            quark_type_image_item = 0;
99 static GQuark            quark_type_stock_item = 0;
100 static GQuark            quark_type_tearoff_item = 0;
101 static GQuark            quark_type_separator_item = 0;
102 static GQuark            quark_type_branch = 0;
103 static GQuark            quark_type_last_branch = 0;
104
105
106 /* --- functions --- */
107 GType
108 gtk_item_factory_get_type (void)
109 {
110   static GType item_factory_type = 0;
111   
112   if (!item_factory_type)
113     {
114       static const GTypeInfo item_factory_info =
115       {
116         sizeof (GtkItemFactoryClass),
117         NULL,           /* base_init */
118         NULL,           /* base_finalize */
119         (GClassInitFunc) gtk_item_factory_class_init,
120         NULL,           /* class_finalize */
121         NULL,           /* class_data */
122         sizeof (GtkItemFactory),
123         0,
124         (GInstanceInitFunc) gtk_item_factory_init,
125       };
126       
127       item_factory_type =
128         g_type_register_static (GTK_TYPE_OBJECT, I_("GtkItemFactory"),
129                                 &item_factory_info, 0);
130     }
131   
132   return item_factory_type;
133 }
134
135 static void
136 gtk_item_factory_class_init (GtkItemFactoryClass  *class)
137 {
138   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
139   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
140
141   gtk_item_factory_class = class;
142   parent_class = g_type_class_peek_parent (class);
143
144   gobject_class->finalize = gtk_item_factory_finalize;
145
146   object_class->destroy = gtk_item_factory_destroy;
147
148   class->item_ht = g_hash_table_new (g_str_hash, g_str_equal);
149
150   quark_popup_data              = g_quark_from_static_string ("GtkItemFactory-popup-data");
151   quark_if_menu_pos             = g_quark_from_static_string ("GtkItemFactory-menu-position");
152   quark_item_factory            = g_quark_from_static_string ("GtkItemFactory");
153   quark_item_path               = g_quark_from_static_string ("GtkItemFactory-path");
154   quark_action                  = g_quark_from_static_string ("GtkItemFactory-action");
155   quark_accel_group             = g_quark_from_static_string ("GtkAccelGroup");
156   quark_type_item               = g_quark_from_static_string ("<Item>");
157   quark_type_title              = g_quark_from_static_string ("<Title>");
158   quark_type_radio_item         = g_quark_from_static_string ("<RadioItem>");
159   quark_type_check_item         = g_quark_from_static_string ("<CheckItem>");
160   quark_type_toggle_item        = g_quark_from_static_string ("<ToggleItem>");
161   quark_type_image_item         = g_quark_from_static_string ("<ImageItem>");
162   quark_type_stock_item         = g_quark_from_static_string ("<StockItem>");
163   quark_type_separator_item     = g_quark_from_static_string ("<Separator>");
164   quark_type_tearoff_item       = g_quark_from_static_string ("<Tearoff>");
165   quark_type_branch             = g_quark_from_static_string ("<Branch>");
166   quark_type_last_branch        = g_quark_from_static_string ("<LastBranch>");
167 }
168
169 static void
170 gtk_item_factory_init (GtkItemFactory       *ifactory)
171 {
172   ifactory->path = NULL;
173   ifactory->accel_group = NULL;
174   ifactory->widget = NULL;
175   ifactory->items = NULL;
176   ifactory->translate_func = NULL;
177   ifactory->translate_data = NULL;
178   ifactory->translate_notify = NULL;
179 }
180
181 /**
182  * gtk_item_factory_new:
183  * @container_type: the kind of menu to create; can be
184  *    #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
185  * @path: the factory path of the new item factory, a string of the form 
186  *    <literal>"&lt;name&gt;"</literal>
187  * @accel_group: a #GtkAccelGroup to which the accelerators for the
188  *    menu items will be added, or %NULL to create a new one
189  * @returns: a new #GtkItemFactory
190  * 
191  * Creates a new #GtkItemFactory.
192  *
193  * Beware that the returned object does not have a floating reference.
194  */
195 GtkItemFactory*
196 gtk_item_factory_new (GType          container_type,
197                       const gchar   *path,
198                       GtkAccelGroup *accel_group)
199 {
200   GtkItemFactory *ifactory;
201
202   g_return_val_if_fail (path != NULL, NULL);
203
204   ifactory = g_object_new (GTK_TYPE_ITEM_FACTORY, NULL);
205   gtk_item_factory_construct (ifactory, container_type, path, accel_group);
206
207   return ifactory;
208 }
209
210 static void
211 gtk_item_factory_callback_marshal (GtkWidget *widget,
212                                    gpointer   func_data)
213 {
214   GtkIFCBData *data;
215
216   data = func_data;
217
218   if (data->callback_type == 1)
219     {
220       GtkItemFactoryCallback1 func1 = (GtkItemFactoryCallback1) data->func;
221       func1 (data->func_data, data->callback_action, widget);
222     }
223   else if (data->callback_type == 2)
224     {
225       GtkItemFactoryCallback2 func2 = (GtkItemFactoryCallback2) data->func;
226       func2 (widget, data->func_data, data->callback_action);
227     }
228 }
229
230 static void
231 gtk_item_factory_item_remove_widget (GtkWidget          *widget,
232                                      GtkItemFactoryItem *item)
233 {
234   item->widgets = g_slist_remove (item->widgets, widget);
235   g_object_set_qdata (G_OBJECT (widget), quark_item_factory, NULL);
236   g_object_set_qdata (G_OBJECT (widget), quark_item_path, NULL);
237 }
238
239 /**
240  * gtk_item_factory_add_foreign:
241  * @accel_widget:     widget to install an accelerator on 
242  * @full_path:        the full path for the @accel_widget 
243  * @accel_group:      the accelerator group to install the accelerator in
244  * @keyval:           key value of the accelerator
245  * @modifiers:        modifier combination of the accelerator
246  *
247  * Installs an accelerator for @accel_widget in @accel_group, that causes
248  * the ::activate signal to be emitted if the accelerator is activated.
249  * 
250  * This function can be used to make widgets participate in the accel
251  * saving/restoring functionality provided by gtk_accel_map_save() and
252  * gtk_accel_map_load(), even if they haven't been created by an item
253  * factory. 
254  *
255  * Deprecated: The recommended API for this purpose are the functions 
256  * gtk_menu_item_set_accel_path() and gtk_widget_set_accel_path(); don't 
257  * use gtk_item_factory_add_foreign() in new code, since it is likely to
258  * be removed in the future.
259  */
260 void
261 gtk_item_factory_add_foreign (GtkWidget      *accel_widget,
262                               const gchar    *full_path,
263                               GtkAccelGroup  *accel_group,
264                               guint           keyval,
265                               GdkModifierType modifiers)
266 {
267   GtkItemFactoryClass *class;
268   GtkItemFactoryItem *item;
269
270   g_return_if_fail (GTK_IS_WIDGET (accel_widget));
271   g_return_if_fail (full_path != NULL);
272
273   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
274
275   keyval = keyval != GDK_VoidSymbol ? keyval : 0;
276
277   item = g_hash_table_lookup (class->item_ht, full_path);
278   if (!item)
279     {
280       item = g_slice_new (GtkItemFactoryItem);
281
282       item->path = g_strdup (full_path);
283       item->widgets = NULL;
284       
285       g_hash_table_insert (class->item_ht, item->path, item);
286     }
287
288   item->widgets = g_slist_prepend (item->widgets, accel_widget);
289   g_signal_connect (accel_widget,
290                     "destroy",
291                     G_CALLBACK (gtk_item_factory_item_remove_widget),
292                     item);
293
294   /* set the item path for the widget
295    */
296   g_object_set_qdata (G_OBJECT (accel_widget), quark_item_path, item->path);
297   gtk_widget_set_name (accel_widget, item->path);
298   if (accel_group)
299     {
300       g_object_ref (accel_group);
301       g_object_set_qdata_full (G_OBJECT (accel_widget),
302                                quark_accel_group,
303                                accel_group,
304                                g_object_unref);
305     }
306   else
307     g_object_set_qdata (G_OBJECT (accel_widget), quark_accel_group, NULL);
308
309   /* install defined accelerators
310    */
311   if (g_signal_lookup ("activate", G_TYPE_FROM_INSTANCE (accel_widget)))
312     {
313       if (accel_group)
314         {
315           gtk_accel_map_add_entry (full_path, keyval, modifiers);
316           gtk_widget_set_accel_path (accel_widget, full_path, accel_group);
317         }
318     }
319 }
320
321 static void
322 ifactory_cb_data_free (gpointer mem)
323 {
324   g_slice_free (GtkIFCBData, mem);
325 }
326
327 static void
328 gtk_item_factory_add_item (GtkItemFactory               *ifactory,
329                            const gchar                  *path,
330                            const gchar                  *accelerator,
331                            GtkItemFactoryCallback       callback,
332                            guint                        callback_action,
333                            gpointer                     callback_data,
334                            guint                        callback_type,
335                            gchar                        *item_type,
336                            GtkWidget                    *widget)
337 {
338   GtkItemFactoryClass *class;
339   GtkItemFactoryItem *item;
340   gchar *fpath;
341   guint keyval;
342   GdkModifierType mods;
343   
344   g_return_if_fail (widget != NULL);
345   g_return_if_fail (item_type != NULL);
346
347   class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
348
349   /* set accelerator group on menu widgets
350    */
351   if (GTK_IS_MENU (widget))
352     gtk_menu_set_accel_group ((GtkMenu*) widget, ifactory->accel_group);
353
354   /* connect callback if necessary
355    */
356   if (callback)
357     {
358       GtkIFCBData *data;
359
360       data = g_slice_new (GtkIFCBData);
361       data->func = callback;
362       data->callback_type = callback_type;
363       data->func_data = callback_data;
364       data->callback_action = callback_action;
365
366       g_object_weak_ref (G_OBJECT (widget),
367                          (GWeakNotify) ifactory_cb_data_free,
368                          data);
369       g_signal_connect (widget,
370                         "activate",
371                         G_CALLBACK (gtk_item_factory_callback_marshal),
372                         data);
373     }
374
375   /* link the widget into its item-entry
376    * and keep back pointer on both the item factory and the widget
377    */
378   g_object_set_qdata (G_OBJECT (widget), quark_action, GUINT_TO_POINTER (callback_action));
379   g_object_set_qdata (G_OBJECT (widget), quark_item_factory, ifactory);
380   if (accelerator)
381     gtk_accelerator_parse (accelerator, &keyval, &mods);
382   else
383     {
384       keyval = 0;
385       mods = 0;
386     }
387   fpath = g_strconcat (ifactory->path, path, NULL);
388   gtk_item_factory_add_foreign (widget, fpath, ifactory->accel_group, keyval, mods);
389   item = g_hash_table_lookup (class->item_ht, fpath);
390   g_free (fpath);
391
392   g_return_if_fail (item != NULL);
393
394   if (!g_slist_find (ifactory->items, item))
395     ifactory->items = g_slist_prepend (ifactory->items, item);
396 }
397
398 /**
399  * gtk_item_factory_construct:
400  * @ifactory: a #GtkItemFactory
401  * @container_type: the kind of menu to create; can be
402  *    #GTK_TYPE_MENU_BAR, #GTK_TYPE_MENU or #GTK_TYPE_OPTION_MENU
403  * @path: the factory path of @ifactory, a string of the form 
404  *    <literal>"&lt;name&gt;"</literal>
405  * @accel_group: a #GtkAccelGroup to which the accelerators for the
406  *    menu items will be added, or %NULL to create a new one
407  * 
408  * Initializes an item factory.
409  */  
410 void
411 gtk_item_factory_construct (GtkItemFactory      *ifactory,
412                             GType                container_type,
413                             const gchar         *path,
414                             GtkAccelGroup       *accel_group)
415 {
416   guint len;
417
418   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
419   g_return_if_fail (ifactory->accel_group == NULL);
420   g_return_if_fail (path != NULL);
421   if (!g_type_is_a (container_type, GTK_TYPE_OPTION_MENU))
422     g_return_if_fail (g_type_is_a (container_type, GTK_TYPE_MENU_SHELL));
423
424   len = strlen (path);
425
426   if (path[0] != '<' && path[len - 1] != '>')
427     {
428       g_warning ("GtkItemFactory: invalid factory path `%s'", path);
429       return;
430     }
431
432   if (accel_group)
433     {
434       ifactory->accel_group = accel_group;
435       g_object_ref (ifactory->accel_group);
436     }
437   else
438     ifactory->accel_group = gtk_accel_group_new ();
439
440   ifactory->path = g_strdup (path);
441   ifactory->widget = g_object_connect (gtk_widget_new (container_type, NULL),
442                                        "signal::destroy", gtk_widget_destroyed, &ifactory->widget,
443                                        NULL);
444   g_object_ref_sink (ifactory);
445
446   gtk_item_factory_add_item (ifactory,
447                              "", NULL,
448                              NULL, 0, NULL, 0,
449                              ITEM_FACTORY_STRING,
450                              ifactory->widget);
451 }
452
453 /**
454  * gtk_item_factory_from_path:
455  * @path: a string starting with a factory path of the form 
456  *   <literal>"&lt;name&gt;"</literal>
457  * @returns: the #GtkItemFactory created for the given factory path, or %NULL 
458  *
459  * Finds an item factory which has been constructed using the 
460  * <literal>"&lt;name&gt;"</literal> prefix of @path as the @path argument 
461  * for gtk_item_factory_new().
462  */
463 GtkItemFactory*
464 gtk_item_factory_from_path (const gchar      *path)
465 {
466   GtkItemFactoryClass *class;
467   GtkItemFactoryItem *item;
468   gchar *fname;
469   guint i;
470
471   g_return_val_if_fail (path != NULL, NULL);
472   g_return_val_if_fail (path[0] == '<', NULL);
473
474   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
475
476   i = 0;
477   while (path[i] && path[i] != '>')
478     i++;
479   if (path[i] != '>')
480     {
481       g_warning ("gtk_item_factory_from_path(): invalid factory path \"%s\"",
482                  path);
483       return NULL;
484     }
485   fname = g_new (gchar, i + 2);
486   g_memmove (fname, path, i + 1);
487   fname[i + 1] = 0;
488
489   item = g_hash_table_lookup (class->item_ht, fname);
490
491   g_free (fname);
492
493   if (item && item->widgets)
494     return gtk_item_factory_from_widget (item->widgets->data);
495
496   return NULL;
497 }
498
499 static void
500 gtk_item_factory_destroy (GtkObject *object)
501 {
502   GtkItemFactory *ifactory;
503   GSList *slist;
504
505   g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
506
507   ifactory = (GtkItemFactory*) object;
508
509   if (ifactory->widget)
510     {
511       GtkObject *dobj;
512
513       dobj = GTK_OBJECT (ifactory->widget);
514
515       g_object_ref_sink (dobj);
516       gtk_object_destroy (dobj);
517       g_object_unref (dobj);
518
519       ifactory->widget = NULL;
520     }
521
522   for (slist = ifactory->items; slist; slist = slist->next)
523     {
524       GtkItemFactoryItem *item = slist->data;
525       GSList *link;
526       
527       for (link = item->widgets; link; link = link->next)
528         if (g_object_get_qdata (link->data, quark_item_factory) == ifactory)
529           g_object_set_qdata (link->data, quark_item_factory, NULL);
530     }
531   g_slist_free (ifactory->items);
532   ifactory->items = NULL;
533
534   GTK_OBJECT_CLASS (parent_class)->destroy (object);
535 }
536
537 static void
538 gtk_item_factory_finalize (GObject *object)
539 {
540   GtkItemFactory *ifactory;
541
542   g_return_if_fail (GTK_IS_ITEM_FACTORY (object));
543
544   ifactory = GTK_ITEM_FACTORY (object);
545
546   g_object_unref (ifactory->accel_group);
547   g_free (ifactory->path);
548   g_assert (ifactory->widget == NULL);
549
550   if (ifactory->translate_notify)
551     ifactory->translate_notify (ifactory->translate_data);
552   
553   G_OBJECT_CLASS (parent_class)->finalize (object);
554 }
555
556 /**
557  * gtk_item_factory_from_widget:
558  * @widget: a widget
559  * @returns: the item factory from which @widget was created, or %NULL
560  *
561  * Obtains the item factory from which a widget was created.
562  */
563 GtkItemFactory*
564 gtk_item_factory_from_widget (GtkWidget        *widget)
565 {
566   GtkItemFactory *ifactory;
567
568   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
569
570   ifactory = g_object_get_qdata (G_OBJECT (widget), quark_item_factory);
571
572   if (ifactory == NULL && GTK_IS_MENU_ITEM (widget) &&
573       GTK_MENU_ITEM (widget)->submenu != NULL) 
574     {
575       GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
576       ifactory = g_object_get_qdata (G_OBJECT (menu), quark_item_factory);
577     }
578
579   return ifactory;
580 }
581
582 /**
583  * gtk_item_factory_path_from_widget:
584  * @widget: a widget
585  * @returns: the full path to @widget if it has been created by an item
586  *   factory, %NULL otherwise. This value is owned by GTK+ and must not be
587  *   modified or freed.
588  * 
589  * If @widget has been created by an item factory, returns the full path
590  * to it. (The full path of a widget is the concatenation of the factory 
591  * path specified in gtk_item_factory_new() with the path specified in the 
592  * #GtkItemFactoryEntry from which the widget was created.)
593  */
594 G_CONST_RETURN gchar*
595 gtk_item_factory_path_from_widget (GtkWidget        *widget)
596 {
597   gchar* path;
598
599   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
600
601   path = g_object_get_qdata (G_OBJECT (widget), quark_item_path);
602
603   if (path == NULL && GTK_IS_MENU_ITEM (widget) &&
604       GTK_MENU_ITEM (widget)->submenu != NULL) 
605     {
606       GtkWidget *menu = GTK_MENU_ITEM (widget)->submenu;
607       path = g_object_get_qdata (G_OBJECT (menu), quark_item_path);
608     }
609
610   return path;
611 }
612
613 /**
614  * gtk_item_factory_create_items:
615  * @ifactory: a #GtkItemFactory
616  * @n_entries: the length of @entries
617  * @entries: an array of #GtkItemFactoryEntry<!-- -->s whose @callback members
618  *    must by of type #GtkItemFactoryCallback1
619  * @callback_data: data passed to the callback functions of all entries
620  *
621  * Creates the menu items from the @entries.
622  */
623 void
624 gtk_item_factory_create_items (GtkItemFactory      *ifactory,
625                                guint                n_entries,
626                                GtkItemFactoryEntry *entries,
627                                gpointer             callback_data)
628 {
629   gtk_item_factory_create_items_ac (ifactory, n_entries, entries, callback_data, 1);
630 }
631
632 /**
633  * gtk_item_factory_create_items_ac:
634  * @ifactory: a #GtkItemFactory
635  * @n_entries: the length of @entries
636  * @entries: an array of #GtkItemFactoryEntry<!-- -->s 
637  * @callback_data: data passed to the callback functions of all entries
638  * @callback_type: 1 if the callback functions in @entries are of type
639  *    #GtkItemFactoryCallback1, 2 if they are of type #GtkItemFactoryCallback2 
640  *
641  * Creates the menu items from the @entries.
642  */
643 void
644 gtk_item_factory_create_items_ac (GtkItemFactory      *ifactory,
645                                   guint                n_entries,
646                                   GtkItemFactoryEntry *entries,
647                                   gpointer             callback_data,
648                                   guint                callback_type)
649 {
650   guint i;
651
652   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
653   g_return_if_fail (callback_type >= 1 && callback_type <= 2);
654
655   if (n_entries == 0)
656     return;
657
658   g_return_if_fail (entries != NULL);
659
660   for (i = 0; i < n_entries; i++)
661     gtk_item_factory_create_item (ifactory, entries + i, callback_data, callback_type);
662 }
663
664 /**
665  * gtk_item_factory_get_widget:
666  * @ifactory: a #GtkItemFactory
667  * @path: the path to the widget
668  * @returns: the widget for the given path, or %NULL if @path doesn't lead
669  *   to a widget
670  *
671  * Obtains the widget which corresponds to @path. 
672  *
673  * If the widget corresponding to @path is a menu item which opens a 
674  * submenu, then the submenu is returned. If you are interested in the menu 
675  * item, use gtk_item_factory_get_item() instead.
676  */
677 GtkWidget*
678 gtk_item_factory_get_widget (GtkItemFactory *ifactory,
679                              const gchar    *path)
680 {
681   GtkItemFactoryClass *class;
682   GtkItemFactoryItem *item;
683
684   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
685   g_return_val_if_fail (path != NULL, NULL);
686
687   class = GTK_ITEM_FACTORY_GET_CLASS (ifactory);
688
689   if (path[0] == '<')
690     item = g_hash_table_lookup (class->item_ht, (gpointer) path);
691   else
692     {
693       gchar *fpath;
694
695       fpath = g_strconcat (ifactory->path, path, NULL);
696       item = g_hash_table_lookup (class->item_ht, fpath);
697       g_free (fpath);
698     }
699
700   if (item)
701     {
702       GSList *slist;
703
704       for (slist = item->widgets; slist; slist = slist->next)
705         {
706           if (gtk_item_factory_from_widget (slist->data) == ifactory)
707             return slist->data;
708         }
709     }
710
711   return NULL;
712 }
713
714 /**
715  * gtk_item_factory_get_widget_by_action:
716  * @ifactory: a #GtkItemFactory
717  * @action: an action as specified in the @callback_action field
718  *   of #GtkItemFactoryEntry
719  * @returns: the widget which corresponds to the given action, or %NULL
720  *   if no widget was found
721  *
722  * Obtains the widget which was constructed from the #GtkItemFactoryEntry
723  * with the given @action.
724  *
725  * If there are multiple items with the same action, the result is 
726  * undefined.
727  */
728 GtkWidget*
729 gtk_item_factory_get_widget_by_action (GtkItemFactory *ifactory,
730                                        guint           action)
731 {
732   GSList *slist;
733
734   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
735
736   for (slist = ifactory->items; slist; slist = slist->next)
737     {
738       GtkItemFactoryItem *item = slist->data;
739       GSList *link;
740
741       for (link = item->widgets; link; link = link->next)
742         if (g_object_get_qdata (link->data, quark_item_factory) == ifactory &&
743             g_object_get_qdata (link->data, quark_action) == GUINT_TO_POINTER (action))
744           return link->data;
745     }
746
747   return NULL;
748 }
749
750 /** 
751  * gtk_item_factory_get_item:
752  * @ifactory: a #GtkItemFactory
753  * @path: the path to the menu item
754  * @returns: the menu item for the given path, or %NULL if @path doesn't
755  *   lead to a menu item
756  *
757  * Obtains the menu item which corresponds to @path. 
758  *
759  * If the widget corresponding to @path is a menu item which opens a 
760  * submenu, then the item is returned. If you are interested in the submenu, 
761  * use gtk_item_factory_get_widget() instead.
762  */
763 GtkWidget*
764 gtk_item_factory_get_item (GtkItemFactory *ifactory,
765                            const gchar    *path)
766 {
767   GtkWidget *widget;
768
769   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
770   g_return_val_if_fail (path != NULL, NULL);
771
772   widget = gtk_item_factory_get_widget (ifactory, path);
773
774   if (GTK_IS_MENU (widget))
775     widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
776
777   return GTK_IS_ITEM (widget) ? widget : NULL;
778 }
779
780
781 /**
782  * gtk_item_factory_get_item_by_action:
783  * @ifactory: a #GtkItemFactory
784  * @action: an action as specified in the @callback_action field
785  *   of #GtkItemFactoryEntry
786  * @returns: the menu item which corresponds to the given action, or %NULL
787  *   if no menu item was found
788  *
789  * Obtains the menu item which was constructed from the first 
790  * #GtkItemFactoryEntry with the given @action.
791  */
792 GtkWidget*
793 gtk_item_factory_get_item_by_action (GtkItemFactory *ifactory,
794                                      guint           action)
795 {
796   GtkWidget *widget;
797
798   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
799
800   widget = gtk_item_factory_get_widget_by_action (ifactory, action);
801
802   if (GTK_IS_MENU (widget))
803     widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
804
805   return GTK_IS_ITEM (widget) ? widget : NULL;
806 }
807
808 static char *
809 item_factory_find_separator_r (char *path)
810 {
811   gchar *result = NULL;
812   gboolean escaped = FALSE;
813
814   while (*path)
815     {
816       if (escaped)
817         escaped = FALSE;
818       else
819         {
820           if (*path == '\\')
821             escaped = TRUE;
822           else if (*path == '/')
823             result = path;
824         }
825       
826       path++;
827     }
828
829   return result;
830 }
831
832 static char *
833 item_factory_unescape_label (const char *label)
834 {
835   char *new = g_malloc (strlen (label) + 1);
836   char *p = new;
837   gboolean escaped = FALSE;
838   
839   while (*label)
840     {
841       if (escaped)
842         {
843           *p++ = *label;
844           escaped = FALSE;
845         }
846       else
847         {
848           if (*label == '\\')
849             escaped = TRUE;
850           else
851             *p++ = *label;
852         }
853       
854       label++;
855     }
856
857   *p = '\0';
858
859   return new;
860 }
861
862 static gboolean
863 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
864                              gchar          *str,
865                              gchar         **path,
866                              gchar         **parent_path,
867                              gchar         **item)
868 {
869   gchar *translation;
870   gchar *p, *q;
871   
872   *path = g_strdup (str);
873
874   p = q = *path;
875   while (*p)
876     {
877       if (*p == '_')
878         {
879           if (p[1] == '_')
880             {
881               p++;
882               *q++ = '_';
883             }
884         }
885       else
886         {
887           *q++ = *p;
888         }
889       p++;
890     }
891   *q = 0;
892
893   *parent_path = g_strdup (*path);
894   p = item_factory_find_separator_r (*parent_path);
895   if (!p)
896     {
897       g_warning ("GtkItemFactory: invalid entry path `%s'", str);
898       return FALSE;
899     }
900   *p = 0;
901
902   if (ifactory->translate_func)
903     translation = ifactory->translate_func (str, ifactory->translate_data);
904   else
905     translation = str;
906                               
907   p = item_factory_find_separator_r (translation);
908   if (p)
909     p++;
910   else
911     p = translation;
912
913   *item = item_factory_unescape_label (p);
914
915   return TRUE;
916 }
917
918 /**
919  * gtk_item_factory_create_item:
920  * @ifactory: a #GtkItemFactory
921  * @entry: the #GtkItemFactoryEntry to create an item for
922  * @callback_data: data passed to the callback function of @entry
923  * @callback_type: 1 if the callback function of @entry is of type
924  *    #GtkItemFactoryCallback1, 2 if it is of type #GtkItemFactoryCallback2 
925  *
926  * Creates an item for @entry.
927  */
928 void
929 gtk_item_factory_create_item (GtkItemFactory         *ifactory,
930                               GtkItemFactoryEntry    *entry,
931                               gpointer                callback_data,
932                               guint                   callback_type)
933 {
934   GtkOptionMenu *option_menu = NULL;
935   GtkWidget *parent;
936   GtkWidget *widget;
937   GtkWidget *image;
938   GSList *radio_group;
939   gchar *name;
940   gchar *parent_path;
941   gchar *path;
942   gchar *accelerator;
943   guint type_id;
944   GType type;
945   gchar *item_type_path;
946   GtkStockItem stock_item;
947       
948   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
949   g_return_if_fail (entry != NULL);
950   g_return_if_fail (entry->path != NULL);
951   g_return_if_fail (entry->path[0] == '/');
952   g_return_if_fail (callback_type >= 1 && callback_type <= 2);
953
954   if (!entry->item_type ||
955       entry->item_type[0] == 0)
956     {
957       item_type_path = "<Item>";
958       type_id = quark_type_item;
959     }
960   else
961     {
962       item_type_path = entry->item_type;
963       type_id = g_quark_try_string (item_type_path);
964     }
965
966   radio_group = NULL;
967   if (type_id == quark_type_item)
968     type = GTK_TYPE_MENU_ITEM;
969   else if (type_id == quark_type_title)
970     type = GTK_TYPE_MENU_ITEM;
971   else if (type_id == quark_type_radio_item)
972     type = GTK_TYPE_RADIO_MENU_ITEM;
973   else if (type_id == quark_type_check_item)
974     type = GTK_TYPE_CHECK_MENU_ITEM;
975   else if (type_id == quark_type_image_item)
976     type = GTK_TYPE_IMAGE_MENU_ITEM;
977   else if (type_id == quark_type_stock_item)
978     type = GTK_TYPE_IMAGE_MENU_ITEM;
979   else if (type_id == quark_type_tearoff_item)
980     type = GTK_TYPE_TEAROFF_MENU_ITEM;
981   else if (type_id == quark_type_toggle_item)
982     type = GTK_TYPE_CHECK_MENU_ITEM;
983   else if (type_id == quark_type_separator_item)
984     type = GTK_TYPE_MENU_ITEM;
985   else if (type_id == quark_type_branch)
986     type = GTK_TYPE_MENU_ITEM;
987   else if (type_id == quark_type_last_branch)
988     type = GTK_TYPE_MENU_ITEM;
989   else
990     {
991       GtkWidget *radio_link;
992
993       radio_link = gtk_item_factory_get_widget (ifactory, item_type_path);
994       if (radio_link && GTK_IS_RADIO_MENU_ITEM (radio_link))
995         {
996           type = GTK_TYPE_RADIO_MENU_ITEM;
997           radio_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radio_link));
998         }
999       else
1000         {
1001           g_warning ("GtkItemFactory: entry path `%s' has invalid type `%s'",
1002                      entry->path,
1003                      item_type_path);
1004           return;
1005         }
1006     }
1007
1008   if (!gtk_item_factory_parse_path (ifactory, entry->path, 
1009                                     &path, &parent_path, &name))
1010     return;
1011
1012   parent = gtk_item_factory_get_widget (ifactory, parent_path);
1013   if (!parent)
1014     {
1015       GtkItemFactoryEntry pentry;
1016       gchar *ppath, *p;
1017
1018       ppath = g_strdup (entry->path);
1019       p = item_factory_find_separator_r (ppath);
1020       g_return_if_fail (p != NULL);
1021       *p = 0;
1022       pentry.path = ppath;
1023       pentry.accelerator = NULL;
1024       pentry.callback = NULL;
1025       pentry.callback_action = 0;
1026       pentry.item_type = "<Branch>";
1027
1028       gtk_item_factory_create_item (ifactory, &pentry, NULL, 1);
1029       g_free (ppath);
1030
1031       parent = gtk_item_factory_get_widget (ifactory, parent_path);
1032       g_return_if_fail (parent != NULL);
1033     }
1034
1035   if (GTK_IS_OPTION_MENU (parent))
1036     {
1037       option_menu = GTK_OPTION_MENU (parent);
1038       if (!option_menu->menu)
1039         {
1040           GtkWidget *menu = g_object_new (GTK_TYPE_MENU, NULL);
1041           gchar *p = g_strconcat (ifactory->path, parent_path, NULL);
1042
1043           gtk_menu_set_accel_path (GTK_MENU (menu), p);
1044           g_free (p);
1045           gtk_option_menu_set_menu (option_menu, menu);
1046         }
1047       parent = option_menu->menu;
1048     }
1049   g_free (parent_path);
1050                               
1051   g_return_if_fail (GTK_IS_CONTAINER (parent));
1052
1053   accelerator = entry->accelerator;
1054   
1055   widget = gtk_widget_new (type,
1056                            "visible", TRUE,
1057                            "sensitive", (type_id != quark_type_separator_item &&
1058                                          type_id != quark_type_title),
1059                            "parent", parent,
1060                            NULL);
1061   if (option_menu && !option_menu->menu_item)
1062     gtk_option_menu_set_history (option_menu, 0);
1063
1064   if (GTK_IS_RADIO_MENU_ITEM (widget))
1065     gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (widget), radio_group);
1066   if (type_id == quark_type_image_item)
1067     {
1068       GdkPixbuf *pixbuf = NULL;
1069       image = NULL;
1070       if (entry->extra_data)
1071         {
1072           pixbuf = gdk_pixbuf_new_from_inline (-1,
1073                                                entry->extra_data,
1074                                                FALSE,
1075                                                NULL);
1076           if (pixbuf)
1077             image = gtk_image_new_from_pixbuf (pixbuf);
1078         }
1079       if (image)
1080         {
1081           gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1082           gtk_widget_show (image);
1083         }
1084       if (pixbuf)
1085         g_object_unref (pixbuf);
1086     }
1087   if (type_id == quark_type_stock_item)
1088     {
1089       image = gtk_image_new_from_stock (entry->extra_data, GTK_ICON_SIZE_MENU);
1090       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (widget), image);
1091       gtk_widget_show (image);
1092
1093       if (gtk_stock_lookup (entry->extra_data, &stock_item))
1094         {
1095           if (!accelerator)
1096             accelerator = gtk_accelerator_name (stock_item.keyval, stock_item.modifier);
1097         }
1098     }
1099
1100   /* install underline accelerators for this item
1101    */
1102   if (type_id != quark_type_separator_item && 
1103       type_id != quark_type_tearoff_item &&
1104       *name)
1105     {
1106       GtkWidget *label;
1107       
1108       label = gtk_widget_new (GTK_TYPE_ACCEL_LABEL,
1109                               "visible", TRUE,
1110                               "parent", widget,
1111                               "accel-widget", widget,
1112                               "xalign", 0.0,
1113                               NULL);
1114       gtk_label_set_text_with_mnemonic (GTK_LABEL (label), name);
1115     }
1116   
1117   g_free (name);
1118   
1119   if (type_id == quark_type_branch ||
1120       type_id == quark_type_last_branch)
1121     {
1122       gchar *p;
1123
1124       if (entry->callback)
1125         g_warning ("gtk_item_factory_create_item(): Can't specify a callback on a branch: \"%s\"",
1126                    entry->path);
1127       if (type_id == quark_type_last_branch)
1128         gtk_menu_item_set_right_justified (GTK_MENU_ITEM (widget), TRUE);
1129       
1130       parent = widget;
1131       widget = gtk_widget_new (GTK_TYPE_MENU, NULL);
1132       p = g_strconcat (ifactory->path, path, NULL);
1133       gtk_menu_set_accel_path (GTK_MENU (widget), p);
1134       g_free (p);
1135       
1136       gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent), widget);
1137     }      
1138   
1139   gtk_item_factory_add_item (ifactory,
1140                              path, accelerator,
1141                              (type_id == quark_type_branch ||
1142                               type_id == quark_type_last_branch) ?
1143                               (GtkItemFactoryCallback) NULL : entry->callback,
1144                              entry->callback_action, callback_data,
1145                              callback_type,
1146                              item_type_path,
1147                              widget);
1148   if (accelerator != entry->accelerator)
1149     g_free (accelerator);
1150   g_free (path);
1151 }
1152
1153 /**
1154  * gtk_item_factory_create_menu_entries:
1155  * @n_entries: the length of @entries
1156  * @entries: an array of #GtkMenuEntry<!-- -->s 
1157  *
1158  * Creates the menu items from the @entries.
1159  */
1160 void
1161 gtk_item_factory_create_menu_entries (guint              n_entries,
1162                                       GtkMenuEntry      *entries)
1163 {
1164   static GPatternSpec *pspec_separator = NULL;
1165   static GPatternSpec *pspec_check = NULL;
1166   guint i;
1167
1168   if (!n_entries)
1169     return;
1170   g_return_if_fail (entries != NULL);
1171
1172   if (!pspec_separator)
1173     {
1174       pspec_separator = g_pattern_spec_new ("*<separator>*");
1175       pspec_check = g_pattern_spec_new ("*<check>*");
1176     }
1177
1178   for (i = 0; i < n_entries; i++)
1179     {
1180       GtkItemFactory *ifactory;
1181       GtkItemFactoryEntry entry;
1182       gchar *path;
1183       gchar *cpath;
1184
1185       path = entries[i].path;
1186       ifactory = gtk_item_factory_from_path (path);
1187       if (!ifactory)
1188         {
1189           g_warning ("gtk_item_factory_create_menu_entries(): "
1190                      "entry[%u] refers to unknown item factory: \"%s\"",
1191                      i, entries[i].path);
1192           continue;
1193         }
1194
1195       while (*path != '>')
1196         path++;
1197       path++;
1198       cpath = NULL;
1199
1200       entry.path = path;
1201       entry.accelerator = entries[i].accelerator;
1202       entry.callback = entries[i].callback;
1203       entry.callback_action = 0;
1204       if (g_pattern_match_string (pspec_separator, path))
1205         entry.item_type = "<Separator>";
1206       else if (!g_pattern_match_string (pspec_check, path))
1207         entry.item_type = NULL;
1208       else
1209         {
1210           gboolean in_brace = FALSE;
1211           gchar *c;
1212           
1213           cpath = g_new (gchar, strlen (path));
1214           c = cpath;
1215           while (*path != 0)
1216             {
1217               if (*path == '<')
1218                 in_brace = TRUE;
1219               else if (*path == '>')
1220                 in_brace = FALSE;
1221               else if (!in_brace)
1222                 *(c++) = *path;
1223               path++;
1224             }
1225           *c = 0;
1226           entry.item_type = "<ToggleItem>";
1227           entry.path = cpath;
1228         }
1229       
1230       gtk_item_factory_create_item (ifactory, &entry, entries[i].callback_data, 2);
1231       entries[i].widget = gtk_item_factory_get_widget (ifactory, entries[i].path);
1232       g_free (cpath);
1233     }
1234 }
1235
1236 /**
1237  * gtk_item_factories_path_delete:
1238  * @ifactory_path: a factory path to prepend to @path. May be %NULL if @path
1239  *   starts with a factory path
1240  * @path: a path 
1241  * 
1242  * Deletes all widgets constructed from the specified path.
1243  */
1244 void
1245 gtk_item_factories_path_delete (const gchar *ifactory_path,
1246                                 const gchar *path)
1247 {
1248   GtkItemFactoryClass *class;
1249   GtkItemFactoryItem *item;
1250
1251   g_return_if_fail (path != NULL);
1252
1253   class = gtk_type_class (GTK_TYPE_ITEM_FACTORY);
1254
1255   if (path[0] == '<')
1256     item = g_hash_table_lookup (class->item_ht, (gpointer) path);
1257   else
1258     {
1259       gchar *fpath;
1260
1261       g_return_if_fail (ifactory_path != NULL);
1262       
1263       fpath = g_strconcat (ifactory_path, path, NULL);
1264       item = g_hash_table_lookup (class->item_ht, fpath);
1265       g_free (fpath);
1266     }
1267   
1268   if (item)
1269     {
1270       GSList *widget_list;
1271       GSList *slist;
1272
1273       widget_list = NULL;
1274       for (slist = item->widgets; slist; slist = slist->next)
1275         {
1276           GtkWidget *widget;
1277
1278           widget = slist->data;
1279           widget_list = g_slist_prepend (widget_list, widget);
1280           g_object_ref (widget);
1281         }
1282
1283       for (slist = widget_list; slist; slist = slist->next)
1284         {
1285           GtkWidget *widget;
1286
1287           widget = slist->data;
1288           gtk_widget_destroy (widget);
1289           g_object_unref (widget);
1290         }
1291       g_slist_free (widget_list);
1292     }
1293 }
1294
1295 /**
1296  * gtk_item_factory_delete_item:
1297  * @ifactory: a #GtkItemFactory
1298  * @path: a path
1299  *
1300  * Deletes the menu item which was created for @path by the given
1301  * item factory.
1302  */
1303 void
1304 gtk_item_factory_delete_item (GtkItemFactory         *ifactory,
1305                               const gchar            *path)
1306 {
1307   GtkWidget *widget;
1308
1309   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1310   g_return_if_fail (path != NULL);
1311
1312   widget = gtk_item_factory_get_widget (ifactory, path);
1313
1314   if (widget)
1315     {
1316       if (GTK_IS_MENU (widget))
1317         widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
1318
1319       gtk_widget_destroy (widget);
1320     }
1321 }
1322
1323 /**
1324  * gtk_item_factory_delete_entry:
1325  * @ifactory: a #GtkItemFactory
1326  * @entry: a #GtkItemFactoryEntry
1327  *
1328  * Deletes the menu item which was created from @entry by the given
1329  * item factory.
1330  */
1331 void
1332 gtk_item_factory_delete_entry (GtkItemFactory         *ifactory,
1333                                GtkItemFactoryEntry    *entry)
1334 {
1335   gchar *path;
1336   gchar *parent_path;
1337   gchar *name;
1338
1339   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1340   g_return_if_fail (entry != NULL);
1341   g_return_if_fail (entry->path != NULL);
1342   g_return_if_fail (entry->path[0] == '/');
1343
1344   if (!gtk_item_factory_parse_path (ifactory, entry->path, 
1345                                     &path, &parent_path, &name))
1346     return;
1347   
1348   gtk_item_factory_delete_item (ifactory, path);
1349
1350   g_free (path);
1351   g_free (parent_path);
1352   g_free (name);
1353 }
1354
1355 /**
1356  * gtk_item_factory_delete_entries:
1357  * @ifactory: a #GtkItemFactory
1358  * @n_entries: the length of @entries
1359  * @entries: an array of #GtkItemFactoryEntry<!-- -->s 
1360  *
1361  * Deletes the menu items which were created from the @entries by the given
1362  * item factory.
1363  */
1364 void
1365 gtk_item_factory_delete_entries (GtkItemFactory         *ifactory,
1366                                  guint                   n_entries,
1367                                  GtkItemFactoryEntry    *entries)
1368 {
1369   guint i;
1370
1371   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1372   if (n_entries > 0)
1373     g_return_if_fail (entries != NULL);
1374
1375   for (i = 0; i < n_entries; i++)
1376     gtk_item_factory_delete_entry (ifactory, entries + i);
1377 }
1378
1379 typedef struct
1380 {
1381   guint x;
1382   guint y;
1383 } MenuPos;
1384
1385 static void
1386 gtk_item_factory_menu_pos (GtkMenu  *menu,
1387                            gint     *x,
1388                            gint     *y,
1389                            gboolean *push_in,
1390                            gpointer  func_data)
1391 {
1392   MenuPos *mpos = func_data;
1393
1394   *x = mpos->x;
1395   *y = mpos->y;
1396 }
1397
1398 /**
1399  * gtk_item_factory_popup_data_from_widget:
1400  * @widget: a widget
1401  * @returns: @popup_data associated with the item factory from
1402  *   which @widget was created, or %NULL if @widget wasn't created
1403  *   by an item factory
1404  *
1405  * Obtains the @popup_data which was passed to 
1406  * gtk_item_factory_popup_with_data(). This data is available until the menu
1407  * is popped down again.
1408  */
1409 gpointer
1410 gtk_item_factory_popup_data_from_widget (GtkWidget *widget)
1411 {
1412   GtkItemFactory *ifactory;
1413   
1414   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1415
1416   ifactory = gtk_item_factory_from_widget (widget);
1417   if (ifactory)
1418     return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1419
1420   return NULL;
1421 }
1422
1423 /**
1424  * gtk_item_factory_popup_data:
1425  * @ifactory: a #GtkItemFactory
1426  * @returns: @popup_data associated with @ifactory
1427  *
1428  * Obtains the @popup_data which was passed to 
1429  * gtk_item_factory_popup_with_data(). This data is available until the menu
1430  * is popped down again.
1431  */
1432 gpointer
1433 gtk_item_factory_popup_data (GtkItemFactory *ifactory)
1434 {
1435   g_return_val_if_fail (GTK_IS_ITEM_FACTORY (ifactory), NULL);
1436
1437   return g_object_get_qdata (G_OBJECT (ifactory), quark_popup_data);
1438 }
1439
1440 static void
1441 ifactory_delete_popup_data (GtkObject      *object,
1442                             GtkItemFactory *ifactory)
1443 {
1444   g_signal_handlers_disconnect_by_func (object,
1445                                         ifactory_delete_popup_data,
1446                                         ifactory);
1447   g_object_set_qdata (G_OBJECT (ifactory), quark_popup_data, NULL);
1448 }
1449
1450 /**
1451  * gtk_item_factory_popup:
1452  * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1453  * @x: the x position 
1454  * @y: the y position
1455  * @mouse_button: the mouse button which was pressed to initiate the popup
1456  * @time_: the time at which the activation event occurred
1457  *
1458  * Pops up the menu constructed from the item factory at (@x, @y).
1459  *
1460  * The @mouse_button parameter should be the mouse button pressed to initiate
1461  * the menu popup. If the menu popup was initiated by something other than
1462  * a mouse button press, such as a mouse button release or a keypress,
1463  * @mouse_button should be 0.
1464  *
1465  * The @time_ parameter should be the time stamp of the event that
1466  * initiated the popup. If such an event is not available, use
1467  * gtk_get_current_event_time() instead.
1468  *
1469  * The operation of the @mouse_button and the @time_ parameter is the same
1470  * as the @button and @activation_time parameters for gtk_menu_popup().
1471  */
1472 void
1473 gtk_item_factory_popup (GtkItemFactory          *ifactory,
1474                         guint                    x,
1475                         guint                    y,
1476                         guint                    mouse_button,
1477                         guint32                  time)
1478 {
1479   gtk_item_factory_popup_with_data (ifactory, NULL, NULL, x, y, mouse_button, time);
1480 }
1481
1482 /**
1483  * gtk_item_factory_popup_with_data:
1484  * @ifactory: a #GtkItemFactory of type #GTK_TYPE_MENU (see gtk_item_factory_new())
1485  * @popup_data: data available for callbacks while the menu is posted
1486  * @destroy: a #GtkDestroyNotify function to be called on @popup_data when
1487  *  the menu is unposted
1488  * @x: the x position 
1489  * @y: the y position
1490  * @mouse_button: the mouse button which was pressed to initiate the popup
1491  * @time_: the time at which the activation event occurred
1492  *
1493  * Pops up the menu constructed from the item factory at (@x, @y). Callbacks
1494  * can access the @popup_data while the menu is posted via 
1495  * gtk_item_factory_popup_data() and gtk_item_factory_popup_data_from_widget().
1496  *
1497  * The @mouse_button parameter should be the mouse button pressed to initiate
1498  * the menu popup. If the menu popup was initiated by something other than
1499  * a mouse button press, such as a mouse button release or a keypress,
1500  * @mouse_button should be 0.
1501  *
1502  * The @time_ parameter should be the time stamp of the event that
1503  * initiated the popup. If such an event is not available, use
1504  * gtk_get_current_event_time() instead.
1505  *
1506  * The operation of the @mouse_button and the @time_ parameters is the same
1507  * as the @button and @activation_time parameters for gtk_menu_popup().
1508  */
1509 void
1510 gtk_item_factory_popup_with_data (GtkItemFactory        *ifactory,
1511                                   gpointer               popup_data,
1512                                   GtkDestroyNotify       destroy,
1513                                   guint                  x,
1514                                   guint                  y,
1515                                   guint                  mouse_button,
1516                                   guint32                time)
1517 {
1518   MenuPos *mpos;
1519
1520   g_return_if_fail (GTK_IS_ITEM_FACTORY (ifactory));
1521   g_return_if_fail (GTK_IS_MENU (ifactory->widget));
1522   
1523   mpos = g_object_get_qdata (G_OBJECT (ifactory->widget), quark_if_menu_pos);
1524   
1525   if (!mpos)
1526     {
1527       mpos = g_new0 (MenuPos, 1);
1528       g_object_set_qdata_full (G_OBJECT (ifactory->widget),
1529                                quark_if_menu_pos,
1530                                mpos,
1531                                g_free);
1532     }
1533   
1534   mpos->x = x;
1535   mpos->y = y;
1536   
1537   if (popup_data != NULL)
1538     {
1539       g_object_set_qdata_full (G_OBJECT (ifactory),
1540                                quark_popup_data,
1541                                popup_data,
1542                                destroy);
1543       g_signal_connect (ifactory->widget,
1544                         "selection-done",
1545                         G_CALLBACK (ifactory_delete_popup_data),
1546                         ifactory);
1547     }
1548   
1549   gtk_menu_popup (GTK_MENU (ifactory->widget),
1550                   NULL, NULL,
1551                   gtk_item_factory_menu_pos, mpos,
1552                   mouse_button, time);
1553 }
1554
1555 /**
1556  * gtk_item_factory_set_translate_func:
1557  * @ifactory: a #GtkItemFactory
1558  * @func: the #GtkTranslateFunc function to be used to translate path elements 
1559  * @data: data to pass to @func and @notify
1560  * @notify: a #GtkDestroyNotify function to be called when @ifactory is 
1561  *   destroyed and when the translation function is changed again
1562  * 
1563  * Sets a function to be used for translating the path elements before they
1564  * are displayed. 
1565  */ 
1566 void
1567 gtk_item_factory_set_translate_func (GtkItemFactory      *ifactory,
1568                                      GtkTranslateFunc     func,
1569                                      gpointer             data,
1570                                      GtkDestroyNotify     notify)
1571 {
1572   g_return_if_fail (ifactory != NULL);
1573   
1574   if (ifactory->translate_notify)
1575     ifactory->translate_notify (ifactory->translate_data);
1576       
1577   ifactory->translate_func = func;
1578   ifactory->translate_data = data;
1579   ifactory->translate_notify = notify;
1580 }
1581
1582 #define __GTK_ITEM_FACTORY_C__
1583 #include "gtkaliasdef.c"