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