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