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