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