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