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