]> Pileus Git - ~andy/gtk/blob - gtk/gtkaction.c
Bug 535608 – do not string-copy accel paths in the menu code
[~andy/gtk] / gtk / gtkaction.c
1 /*
2  * GTK - The GIMP Toolkit
3  * Copyright (C) 1998, 1999 Red Hat, Inc.
4  * All rights reserved.
5  *
6  * This Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
18  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * Author: James Henstridge <james@daa.com.au>
24  *
25  * Modified by the GTK+ Team and others 2003.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
29  */
30
31 #include <config.h>
32
33 #include "gtkaction.h"
34 #include "gtkactiongroup.h"
35 #include "gtkaccellabel.h"
36 #include "gtkbutton.h"
37 #include "gtkiconfactory.h"
38 #include "gtkimage.h"
39 #include "gtkimagemenuitem.h"
40 #include "gtkintl.h"
41 #include "gtklabel.h"
42 #include "gtkmarshalers.h"
43 #include "gtkmenuitem.h"
44 #include "gtkstock.h"
45 #include "gtktearoffmenuitem.h"
46 #include "gtktoolbutton.h"
47 #include "gtktoolbar.h"
48 #include "gtkprivate.h"
49 #include "gtkbuildable.h"
50 #include "gtkalias.h"
51
52
53 #define GTK_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ACTION, GtkActionPrivate))
54
55 struct _GtkActionPrivate 
56 {
57   const gchar *name; /* interned */
58   gchar *label;
59   gchar *short_label;
60   gchar *tooltip;
61   gchar *stock_id; /* stock icon */
62   gchar *icon_name; /* themed icon */
63
64   guint sensitive          : 1;
65   guint visible            : 1;
66   guint label_set          : 1; /* these two used so we can set label */
67   guint short_label_set    : 1; /* based on stock id */
68   guint visible_horizontal : 1;
69   guint visible_vertical   : 1;
70   guint is_important       : 1;
71   guint hide_if_empty      : 1;
72   guint visible_overflown  : 1;
73
74   /* accelerator */
75   guint          accel_count;
76   GtkAccelGroup *accel_group;
77   GClosure      *accel_closure;
78   GQuark         accel_quark;
79
80   GtkActionGroup *action_group;
81
82   /* list of proxy widgets */
83   GSList *proxies;
84 };
85
86 enum 
87 {
88   ACTIVATE,
89   LAST_SIGNAL
90 };
91
92 enum 
93 {
94   PROP_0,
95   PROP_NAME,
96   PROP_LABEL,
97   PROP_SHORT_LABEL,
98   PROP_TOOLTIP,
99   PROP_STOCK_ID,
100   PROP_ICON_NAME,
101   PROP_VISIBLE_HORIZONTAL,
102   PROP_VISIBLE_VERTICAL,
103   PROP_VISIBLE_OVERFLOWN,
104   PROP_IS_IMPORTANT,
105   PROP_HIDE_IF_EMPTY,
106   PROP_SENSITIVE,
107   PROP_VISIBLE,
108   PROP_ACTION_GROUP
109 };
110
111 /* GtkBuildable */
112 static void gtk_action_buildable_init             (GtkBuildableIface *iface);
113 static void gtk_action_buildable_set_name         (GtkBuildable *buildable,
114                                                    const gchar  *name);
115 static const gchar* gtk_action_buildable_get_name (GtkBuildable *buildable);
116
117 G_DEFINE_TYPE_WITH_CODE (GtkAction, gtk_action, G_TYPE_OBJECT,
118                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
119                                                 gtk_action_buildable_init))
120
121
122 static GQuark      quark_gtk_action_proxy  = 0;
123 static const gchar gtk_action_proxy_key[] = "gtk-action";
124
125 static void gtk_action_finalize     (GObject *object);
126 static void gtk_action_set_property (GObject         *object,
127                                      guint            prop_id,
128                                      const GValue    *value,
129                                      GParamSpec      *pspec);
130 static void gtk_action_get_property (GObject         *object,
131                                      guint            prop_id,
132                                      GValue          *value,
133                                      GParamSpec      *pspec);
134 static void gtk_action_set_action_group (GtkAction      *action,
135                                          GtkActionGroup *action_group);
136 static void gtk_action_set_is_important (GtkAction      *action,
137                                          gboolean        is_important);
138 static void gtk_action_set_label        (GtkAction      *action,
139                                          const gchar    *label);
140 static void gtk_action_set_short_label  (GtkAction      *action,
141                                          const gchar    *label);
142 static void gtk_action_set_visible_horizontal (GtkAction *action,
143                                                gboolean   visible_horizontal);
144 static void gtk_action_set_visible_vertical   (GtkAction *action,
145                                                gboolean   visible_vertical);
146 static void gtk_action_set_tooltip      (GtkAction      *action,
147                                          const gchar    *tooltip);
148 static void gtk_action_set_stock_id     (GtkAction      *action,
149                                          const gchar    *stock_id);
150 static void gtk_action_set_icon_name     (GtkAction     *action,
151                                          const gchar    *icon_name);
152 static void gtk_action_sync_tooltip     (GtkAction      *action,
153                                          GtkWidget      *proxy);
154
155 static GtkWidget *create_menu_item    (GtkAction *action);
156 static GtkWidget *create_tool_item    (GtkAction *action);
157 static void       connect_proxy       (GtkAction *action,
158                                        GtkWidget *proxy);
159 static void       disconnect_proxy    (GtkAction *action,
160                                        GtkWidget *proxy);
161
162 static void       closure_accel_activate (GClosure     *closure,
163                                           GValue       *return_value,
164                                           guint         n_param_values,
165                                           const GValue *param_values,
166                                           gpointer      invocation_hint,
167                                           gpointer      marshal_data);
168
169 static guint         action_signals[LAST_SIGNAL] = { 0 };
170
171
172 static void
173 gtk_action_class_init (GtkActionClass *klass)
174 {
175   GObjectClass *gobject_class;
176
177   quark_gtk_action_proxy = g_quark_from_static_string (gtk_action_proxy_key);
178
179   gobject_class = G_OBJECT_CLASS (klass);
180
181   gobject_class->finalize     = gtk_action_finalize;
182   gobject_class->set_property = gtk_action_set_property;
183   gobject_class->get_property = gtk_action_get_property;
184
185   klass->activate = NULL;
186
187   klass->create_menu_item = create_menu_item;
188   klass->create_tool_item = create_tool_item;
189   klass->create_menu = NULL;
190   klass->connect_proxy = connect_proxy;
191   klass->disconnect_proxy = disconnect_proxy;
192
193   klass->menu_item_type = GTK_TYPE_IMAGE_MENU_ITEM;
194   klass->toolbar_item_type = GTK_TYPE_TOOL_BUTTON;
195
196   g_object_class_install_property (gobject_class,
197                                    PROP_NAME,
198                                    g_param_spec_string ("name",
199                                                         P_("Name"),
200                                                         P_("A unique name for the action."),
201                                                         NULL,
202                                                         GTK_PARAM_READWRITE | 
203                                                         G_PARAM_CONSTRUCT_ONLY));
204
205   /**
206    * GtkAction:label:
207    *
208    * The label used for menu items and buttons that activate
209    * this action. If the label is %NULL, GTK+ uses the stock 
210    * label specified via the stock-id property.
211    */
212   g_object_class_install_property (gobject_class,
213                                    PROP_LABEL,
214                                    g_param_spec_string ("label",
215                                                         P_("Label"),
216                                                         P_("The label used for menu items and buttons "
217                                                            "that activate this action."),
218                                                         NULL,
219                                                         GTK_PARAM_READWRITE));
220   g_object_class_install_property (gobject_class,
221                                    PROP_SHORT_LABEL,
222                                    g_param_spec_string ("short-label",
223                                                         P_("Short label"),
224                                                         P_("A shorter label that may be used on toolbar buttons."),
225                                                         NULL,
226                                                         GTK_PARAM_READWRITE));
227   g_object_class_install_property (gobject_class,
228                                    PROP_TOOLTIP,
229                                    g_param_spec_string ("tooltip",
230                                                         P_("Tooltip"),
231                                                         P_("A tooltip for this action."),
232                                                         NULL,
233                                                         GTK_PARAM_READWRITE));
234   g_object_class_install_property (gobject_class,
235                                    PROP_STOCK_ID,
236                                    g_param_spec_string ("stock-id",
237                                                         P_("Stock Icon"),
238                                                         P_("The stock icon displayed in widgets representing "
239                                                            "this action."),
240                                                         NULL,
241                                                         GTK_PARAM_READWRITE));
242   /**
243    * GtkAction:icon-name:
244    *
245    * The name of the icon from the icon theme. 
246    * Note that the stock icon is preferred, if
247    * the ::stock-id property holds the id of an
248    * existing stock icon.
249    *
250    * Since: 2.10
251    */
252   g_object_class_install_property (gobject_class,
253                                    PROP_ICON_NAME,
254                                    g_param_spec_string ("icon-name",
255                                                         P_("Icon Name"),
256                                                         P_("The name of the icon from the icon theme"),
257                                                         NULL,
258                                                         GTK_PARAM_READWRITE));
259   g_object_class_install_property (gobject_class,
260                                    PROP_VISIBLE_HORIZONTAL,
261                                    g_param_spec_boolean ("visible-horizontal",
262                                                          P_("Visible when horizontal"),
263                                                          P_("Whether the toolbar item is visible when the toolbar "
264                                                             "is in a horizontal orientation."),
265                                                          TRUE,
266                                                          GTK_PARAM_READWRITE));
267   /**
268    * GtkAction:visible-overflown:
269    *
270    * When %TRUE, toolitem proxies for this action are represented in the 
271    * toolbar overflow menu.
272    *
273    * Since: 2.6
274    */
275   g_object_class_install_property (gobject_class,
276                                    PROP_VISIBLE_OVERFLOWN,
277                                    g_param_spec_boolean ("visible-overflown",
278                                                          P_("Visible when overflown"),
279                                                          P_("When TRUE, toolitem proxies for this action "
280                                                             "are represented in the toolbar overflow menu."),
281                                                          TRUE,
282                                                          GTK_PARAM_READWRITE));
283   g_object_class_install_property (gobject_class,
284                                    PROP_VISIBLE_VERTICAL,
285                                    g_param_spec_boolean ("visible-vertical",
286                                                          P_("Visible when vertical"),
287                                                          P_("Whether the toolbar item is visible when the toolbar "
288                                                             "is in a vertical orientation."),
289                                                          TRUE,
290                                                          GTK_PARAM_READWRITE));
291   g_object_class_install_property (gobject_class,
292                                    PROP_IS_IMPORTANT,
293                                    g_param_spec_boolean ("is-important",
294                                                          P_("Is important"),
295                                                          P_("Whether the action is considered important. "
296                                                             "When TRUE, toolitem proxies for this action "
297                                                             "show text in GTK_TOOLBAR_BOTH_HORIZ mode."),
298                                                          FALSE,
299                                                          GTK_PARAM_READWRITE));
300   g_object_class_install_property (gobject_class,
301                                    PROP_HIDE_IF_EMPTY,
302                                    g_param_spec_boolean ("hide-if-empty",
303                                                          P_("Hide if empty"),
304                                                          P_("When TRUE, empty menu proxies for this action are hidden."),
305                                                          TRUE,
306                                                          GTK_PARAM_READWRITE));
307   g_object_class_install_property (gobject_class,
308                                    PROP_SENSITIVE,
309                                    g_param_spec_boolean ("sensitive",
310                                                          P_("Sensitive"),
311                                                          P_("Whether the action is enabled."),
312                                                          TRUE,
313                                                          GTK_PARAM_READWRITE));
314   g_object_class_install_property (gobject_class,
315                                    PROP_VISIBLE,
316                                    g_param_spec_boolean ("visible",
317                                                          P_("Visible"),
318                                                          P_("Whether the action is visible."),
319                                                          TRUE,
320                                                          GTK_PARAM_READWRITE));
321   g_object_class_install_property (gobject_class,
322                                    PROP_ACTION_GROUP,
323                                    g_param_spec_object ("action-group",
324                                                          P_("Action Group"),
325                                                          P_("The GtkActionGroup this GtkAction is associated with, or NULL (for internal use)."),
326                                                          GTK_TYPE_ACTION_GROUP,
327                                                          GTK_PARAM_READWRITE));
328
329   /**
330    * GtkAction::activate:
331    * @action: the #GtkAction
332    *
333    * The "activate" signal is emitted when the action is activated.
334    *
335    * Since: 2.4
336    */
337   action_signals[ACTIVATE] =
338     g_signal_new (I_("activate"),
339                   G_OBJECT_CLASS_TYPE (klass),
340                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
341                   G_STRUCT_OFFSET (GtkActionClass, activate),  NULL, NULL,
342                   g_cclosure_marshal_VOID__VOID,
343                   G_TYPE_NONE, 0);
344
345   g_type_class_add_private (gobject_class, sizeof (GtkActionPrivate));
346 }
347
348
349 static void
350 gtk_action_init (GtkAction *action)
351 {
352   action->private_data = GTK_ACTION_GET_PRIVATE (action);
353
354   action->private_data->name = NULL;
355   action->private_data->label = NULL;
356   action->private_data->short_label = NULL;
357   action->private_data->tooltip = NULL;
358   action->private_data->stock_id = NULL;
359   action->private_data->icon_name = NULL;
360   action->private_data->visible_horizontal = TRUE;
361   action->private_data->visible_vertical   = TRUE;
362   action->private_data->visible_overflown  = TRUE;
363   action->private_data->is_important = FALSE;
364   action->private_data->hide_if_empty = TRUE;
365
366   action->private_data->sensitive = TRUE;
367   action->private_data->visible = TRUE;
368
369   action->private_data->label_set = FALSE;
370   action->private_data->short_label_set = FALSE;
371
372   action->private_data->accel_count = 0;
373   action->private_data->accel_group = NULL;
374   action->private_data->accel_quark = 0;
375   action->private_data->accel_closure = 
376     g_closure_new_object (sizeof (GClosure), G_OBJECT (action));
377   g_closure_set_marshal (action->private_data->accel_closure, 
378                          closure_accel_activate);
379   g_closure_ref (action->private_data->accel_closure);
380   g_closure_sink (action->private_data->accel_closure);
381
382   action->private_data->action_group = NULL;
383
384   action->private_data->proxies = NULL;
385 }
386
387 static void
388 gtk_action_buildable_init (GtkBuildableIface *iface)
389 {
390   iface->set_name = gtk_action_buildable_set_name;
391   iface->get_name = gtk_action_buildable_get_name;
392 }
393
394 static void
395 gtk_action_buildable_set_name (GtkBuildable *buildable,
396                                const gchar  *name)
397 {
398   GtkAction *action = GTK_ACTION (buildable);
399
400   action->private_data->name = g_intern_string (name);
401 }
402
403 static const gchar *
404 gtk_action_buildable_get_name (GtkBuildable *buildable)
405 {
406   GtkAction *action = GTK_ACTION (buildable);
407
408   return action->private_data->name;
409 }
410
411 /**
412  * gtk_action_new:
413  * @name: A unique name for the action
414  * @label: the label displayed in menu items and on buttons, or %NULL
415  * @tooltip: a tooltip for the action, or %NULL
416  * @stock_id: the stock icon to display in widgets representing the
417  *   action, or %NULL
418  *
419  * Creates a new #GtkAction object. To add the action to a
420  * #GtkActionGroup and set the accelerator for the action,
421  * call gtk_action_group_add_action_with_accel().
422  * See <xref linkend="XML-UI"/> for information on allowed action
423  * names.
424  *
425  * Return value: a new #GtkAction
426  *
427  * Since: 2.4
428  */
429 GtkAction *
430 gtk_action_new (const gchar *name,
431                 const gchar *label,
432                 const gchar *tooltip,
433                 const gchar *stock_id)
434 {
435   g_return_val_if_fail (name != NULL, NULL);
436
437   return g_object_new (GTK_TYPE_ACTION,
438                        "name", name,
439                        "label", label,
440                        "tooltip", tooltip,
441                        "stock-id", stock_id,
442                        NULL);
443 }
444
445 static void
446 gtk_action_finalize (GObject *object)
447 {
448   GtkAction *action;
449   action = GTK_ACTION (object);
450
451   g_free (action->private_data->label);
452   g_free (action->private_data->short_label);
453   g_free (action->private_data->tooltip);
454   g_free (action->private_data->stock_id);
455   g_free (action->private_data->icon_name);
456
457   g_closure_unref (action->private_data->accel_closure);
458   if (action->private_data->accel_group)
459     g_object_unref (action->private_data->accel_group);
460
461   G_OBJECT_CLASS (gtk_action_parent_class)->finalize (object);  
462 }
463
464 static void
465 gtk_action_set_property (GObject         *object,
466                          guint            prop_id,
467                          const GValue    *value,
468                          GParamSpec      *pspec)
469 {
470   GtkAction *action;
471   
472   action = GTK_ACTION (object);
473
474   switch (prop_id)
475     {
476     case PROP_NAME:
477       action->private_data->name = g_intern_string (g_value_get_string (value));
478       break;
479     case PROP_LABEL:
480       gtk_action_set_label (action, g_value_get_string (value));
481       break;
482     case PROP_SHORT_LABEL:
483       gtk_action_set_short_label (action, g_value_get_string (value));
484       break;
485     case PROP_TOOLTIP:
486       gtk_action_set_tooltip (action, g_value_get_string (value));
487       break;
488     case PROP_STOCK_ID:
489       gtk_action_set_stock_id (action, g_value_get_string (value));
490       break;
491     case PROP_ICON_NAME:
492       gtk_action_set_icon_name (action, g_value_get_string (value));
493       break;
494     case PROP_VISIBLE_HORIZONTAL:
495       gtk_action_set_visible_horizontal (action, g_value_get_boolean (value));
496       break;
497     case PROP_VISIBLE_VERTICAL:
498       gtk_action_set_visible_vertical (action, g_value_get_boolean (value));
499       break;
500     case PROP_VISIBLE_OVERFLOWN:
501       action->private_data->visible_overflown = g_value_get_boolean (value);
502       break;
503     case PROP_IS_IMPORTANT:
504       gtk_action_set_is_important (action, g_value_get_boolean (value));
505       break;
506     case PROP_HIDE_IF_EMPTY:
507       action->private_data->hide_if_empty = g_value_get_boolean (value);
508       break;
509     case PROP_SENSITIVE:
510       gtk_action_set_sensitive (action, g_value_get_boolean (value));
511       break;
512     case PROP_VISIBLE:
513       gtk_action_set_visible (action, g_value_get_boolean (value));
514       break;
515     case PROP_ACTION_GROUP:
516       gtk_action_set_action_group (action, g_value_get_object (value));
517       break;
518     default:
519       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
520       break;
521     }
522 }
523
524 static void
525 gtk_action_get_property (GObject    *object,
526                          guint       prop_id,
527                          GValue     *value,
528                          GParamSpec *pspec)
529 {
530   GtkAction *action;
531
532   action = GTK_ACTION (object);
533
534   switch (prop_id)
535     {
536     case PROP_NAME:
537       g_value_set_static_string (value, action->private_data->name);
538       break;
539     case PROP_LABEL:
540       g_value_set_string (value, action->private_data->label);
541       break;
542     case PROP_SHORT_LABEL:
543       g_value_set_string (value, action->private_data->short_label);
544       break;
545     case PROP_TOOLTIP:
546       g_value_set_string (value, action->private_data->tooltip);
547       break;
548     case PROP_STOCK_ID:
549       g_value_set_string (value, action->private_data->stock_id);
550       break;
551     case PROP_ICON_NAME:
552       g_value_set_string (value, action->private_data->icon_name);
553       break;
554     case PROP_VISIBLE_HORIZONTAL:
555       g_value_set_boolean (value, action->private_data->visible_horizontal);
556       break;
557     case PROP_VISIBLE_VERTICAL:
558       g_value_set_boolean (value, action->private_data->visible_vertical);
559       break;
560     case PROP_VISIBLE_OVERFLOWN:
561       g_value_set_boolean (value, action->private_data->visible_overflown);
562       break;
563     case PROP_IS_IMPORTANT:
564       g_value_set_boolean (value, action->private_data->is_important);
565       break;
566     case PROP_HIDE_IF_EMPTY:
567       g_value_set_boolean (value, action->private_data->hide_if_empty);
568       break;
569     case PROP_SENSITIVE:
570       g_value_set_boolean (value, action->private_data->sensitive);
571       break;
572     case PROP_VISIBLE:
573       g_value_set_boolean (value, action->private_data->visible);
574       break;
575     case PROP_ACTION_GROUP:
576       g_value_set_object (value, action->private_data->action_group);
577       break;
578     default:
579       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
580       break;
581     }
582 }
583
584 static GtkWidget *
585 create_menu_item (GtkAction *action)
586 {
587   GType menu_item_type;
588
589   menu_item_type = GTK_ACTION_GET_CLASS (action)->menu_item_type;
590
591   return g_object_new (menu_item_type, NULL);
592 }
593
594 static GtkWidget *
595 create_tool_item (GtkAction *action)
596 {
597   GType toolbar_item_type;
598
599   toolbar_item_type = GTK_ACTION_GET_CLASS (action)->toolbar_item_type;
600
601   return g_object_new (toolbar_item_type, NULL);
602 }
603
604 static void
605 remove_proxy (GtkAction *action,
606               GtkWidget *proxy)
607 {
608   if (GTK_IS_MENU_ITEM (proxy))
609     gtk_action_disconnect_accelerator (action);
610   
611   action->private_data->proxies = g_slist_remove (action->private_data->proxies, proxy);
612 }
613
614 /**
615  * _gtk_action_sync_menu_visible:
616  * @action: a #GtkAction, or %NULL to determine the action from @proxy
617  * @proxy: a proxy menu item
618  * @empty: whether the submenu attached to @proxy is empty
619  * 
620  * Updates the visibility of @proxy from the visibility of @action
621  * according to the following rules:
622  * <itemizedlist>
623  * <listitem><para>if @action is invisible, @proxy is too
624  * </para></listitem>
625  * <listitem><para>if @empty is %TRUE, hide @proxy unless the "hide-if-empty" 
626  *   property of @action indicates otherwise
627  * </para></listitem>
628  * </itemizedlist>
629  * 
630  * This function is used in the implementation of #GtkUIManager.
631  **/
632 void
633 _gtk_action_sync_menu_visible (GtkAction *action,
634                                GtkWidget *proxy,
635                                gboolean   empty)
636 {
637   gboolean visible = TRUE;
638   gboolean hide_if_empty = TRUE;
639
640   g_return_if_fail (GTK_IS_MENU_ITEM (proxy));
641   g_return_if_fail (action == NULL || GTK_IS_ACTION (action));
642
643   if (action == NULL)
644     action = g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy);
645
646   if (action)
647     {
648       /* a GtkMenu for a <popup/> doesn't have to have an action */
649       visible = gtk_action_is_visible (action);
650       hide_if_empty = action->private_data->hide_if_empty;
651     }
652
653   if (visible && !(empty && hide_if_empty))
654     gtk_widget_show (proxy);
655   else
656     gtk_widget_hide (proxy);
657 }
658
659 gboolean _gtk_menu_is_empty (GtkWidget *menu);
660
661 static gboolean
662 gtk_action_create_menu_proxy (GtkToolItem *tool_item, 
663                               GtkAction   *action)
664 {
665   GtkWidget *menu_item;
666   
667   if (action->private_data->visible_overflown)
668     {
669       menu_item = gtk_action_create_menu_item (action);
670
671       g_object_ref_sink (menu_item);
672       
673       gtk_tool_item_set_proxy_menu_item (tool_item, 
674                                          "gtk-action-menu-item", menu_item);
675       g_object_unref (menu_item);
676     }
677   else
678     gtk_tool_item_set_proxy_menu_item (tool_item, 
679                                        "gtk-action-menu-item", NULL);
680
681   return TRUE;
682 }
683
684 static void
685 connect_proxy (GtkAction     *action, 
686                GtkWidget     *proxy)
687 {
688   g_object_ref (action);
689   g_object_set_qdata_full (G_OBJECT (proxy), quark_gtk_action_proxy, action,
690                            g_object_unref);
691
692   /* add this widget to the list of proxies */
693   action->private_data->proxies = g_slist_prepend (action->private_data->proxies, proxy);
694   g_object_weak_ref (G_OBJECT (proxy), (GWeakNotify)remove_proxy, action);
695   
696   gtk_widget_set_sensitive (proxy, gtk_action_is_sensitive (action));
697   if (gtk_action_is_visible (action))
698     gtk_widget_show (proxy);
699   else
700     gtk_widget_hide (proxy);
701   gtk_widget_set_no_show_all (proxy, TRUE);
702
703   if (GTK_IS_MENU_ITEM (proxy))
704     {
705       GtkWidget *label;
706       /* menu item specific synchronisers ... */
707       
708       if (action->private_data->accel_quark)
709         {
710           gtk_action_connect_accelerator (action);
711           gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy),
712                                         g_quark_to_string (action->private_data->accel_quark));
713         }
714       
715       label = GTK_BIN (proxy)->child;
716
717       /* make sure label is a label */
718       if (label && !GTK_IS_LABEL (label))
719         {
720           gtk_container_remove (GTK_CONTAINER (proxy), label);
721           label = NULL;
722         }
723
724       if (!label)
725         label = g_object_new (GTK_TYPE_ACCEL_LABEL,
726                               "use-underline", TRUE,
727                               "xalign", 0.0,
728                               "visible", TRUE,
729                               "parent", proxy,
730                               NULL);
731       
732       if (GTK_IS_ACCEL_LABEL (label) && action->private_data->accel_quark)
733         g_object_set (label,
734                       "accel-closure", action->private_data->accel_closure,
735                       NULL);
736
737       gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
738
739       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
740         {
741           GtkWidget *image;
742
743           image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
744           if (image && !GTK_IS_IMAGE (image))
745             {
746               gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), NULL);
747               image = NULL;
748             }
749           if (!image)
750             {
751               image = gtk_image_new ();
752               gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy),
753                                              image);
754               gtk_widget_show (image);
755             }
756           
757           if (action->private_data->stock_id &&
758               gtk_icon_factory_lookup_default (action->private_data->stock_id))
759             gtk_image_set_from_stock (GTK_IMAGE (image),
760                                       action->private_data->stock_id, GTK_ICON_SIZE_MENU);
761           else if (action->private_data->icon_name)
762             gtk_image_set_from_icon_name (GTK_IMAGE (image),
763                                           action->private_data->icon_name, GTK_ICON_SIZE_MENU);
764         }
765       
766       if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)) == NULL)
767         g_signal_connect_object (proxy, "activate",
768                                  G_CALLBACK (gtk_action_activate), action,
769                                  G_CONNECT_SWAPPED);
770
771     }
772   else if (GTK_IS_TOOL_ITEM (proxy))
773     {
774       /* toolbar button specific synchronisers ... */
775       if (GTK_IS_TOOL_BUTTON (proxy))
776         {
777           g_object_set (proxy,
778                         "visible-horizontal", action->private_data->visible_horizontal,
779                         "visible-vertical", action->private_data->visible_vertical,
780                         "is-important", action->private_data->is_important,
781                         "label", action->private_data->short_label,
782                         "use-underline", TRUE,
783                         "stock-id", action->private_data->stock_id,
784                         "icon-name", action->private_data->icon_name,
785                         NULL);
786
787           g_signal_connect_object (proxy, "clicked",
788                                    G_CALLBACK (gtk_action_activate), action,
789                                    G_CONNECT_SWAPPED);
790         }
791       else 
792         {
793            g_object_set (proxy,
794                          "visible-horizontal", action->private_data->visible_horizontal,
795                          "visible-vertical", action->private_data->visible_vertical,
796                          "is-important", action->private_data->is_important,
797                          NULL);
798        }
799
800       gtk_action_sync_tooltip (action, proxy);
801
802       g_signal_connect_object (proxy, "create_menu_proxy",
803                                G_CALLBACK (gtk_action_create_menu_proxy),
804                                action, 0);
805
806       gtk_tool_item_rebuild_menu (GTK_TOOL_ITEM (proxy));
807     }
808   else if (GTK_IS_BUTTON (proxy))
809     {
810       /* button specific synchronisers ... */
811       if (gtk_button_get_use_stock (GTK_BUTTON (proxy)))
812         {
813           /* synchronise stock-id */
814           g_object_set (proxy,
815                         "label", action->private_data->stock_id,
816                         NULL);
817         }
818       else 
819         {
820           if (GTK_BIN (proxy)->child == NULL || 
821               GTK_IS_LABEL (GTK_BIN (proxy)->child))
822             {
823               /* synchronise the label */
824               g_object_set (proxy,
825                             "label", action->private_data->short_label,
826                             "use-underline", TRUE,
827                             NULL);
828             }
829         }
830       /* we leave the button alone if there is a custom child */
831       g_signal_connect_object (proxy, "clicked",
832                                G_CALLBACK (gtk_action_activate), action,
833                                G_CONNECT_SWAPPED);
834     }
835
836   if (action->private_data->action_group)
837     _gtk_action_group_emit_connect_proxy (action->private_data->action_group, action, proxy);
838 }
839
840 static void
841 disconnect_proxy (GtkAction *action, 
842                   GtkWidget *proxy)
843 {
844   g_object_set_qdata (G_OBJECT (proxy), quark_gtk_action_proxy, NULL);
845
846   g_object_weak_unref (G_OBJECT (proxy), (GWeakNotify)remove_proxy, action);
847   remove_proxy (action, proxy);
848
849   /* disconnect the activate handler */
850   g_signal_handlers_disconnect_by_func (proxy,
851                                         G_CALLBACK (gtk_action_activate),
852                                         action);
853
854   /* toolbar button specific synchronisers ... */
855   g_signal_handlers_disconnect_by_func (proxy,
856                                         G_CALLBACK (gtk_action_create_menu_proxy),
857                                         action);
858
859   if (action->private_data->action_group)
860     _gtk_action_group_emit_disconnect_proxy (action->private_data->action_group, action, proxy);
861 }
862
863 void
864 _gtk_action_emit_activate (GtkAction *action)
865 {
866   GtkActionGroup *group = action->private_data->action_group;
867
868   if (group != NULL) 
869     {
870       g_object_ref (group);
871       _gtk_action_group_emit_pre_activate (group, action);
872     }
873
874     g_signal_emit (action, action_signals[ACTIVATE], 0);
875
876   if (group != NULL) 
877     {
878       _gtk_action_group_emit_post_activate (group, action);
879       g_object_unref (group);
880     }
881 }
882
883 /**
884  * gtk_action_activate:
885  * @action: the action object
886  *
887  * Emits the "activate" signal on the specified action, if it isn't 
888  * insensitive. This gets called by the proxy widgets when they get 
889  * activated.
890  *
891  * It can also be used to manually activate an action.
892  *
893  * Since: 2.4
894  */
895 void
896 gtk_action_activate (GtkAction *action)
897 {
898   g_return_if_fail (GTK_IS_ACTION (action));
899   
900   if (gtk_action_is_sensitive (action))
901     _gtk_action_emit_activate (action);
902 }
903
904 /**
905  * gtk_action_create_icon:
906  * @action: the action object
907  * @icon_size: the size of the icon that should be created.
908  *
909  * This function is intended for use by action implementations to
910  * create icons displayed in the proxy widgets.
911  *
912  * Returns: a widget that displays the icon for this action.
913  *
914  * Since: 2.4
915  */
916 GtkWidget *
917 gtk_action_create_icon (GtkAction *action, GtkIconSize icon_size)
918 {
919   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
920
921   if (action->private_data->stock_id &&
922       gtk_icon_factory_lookup_default (action->private_data->stock_id))
923     return gtk_image_new_from_stock (action->private_data->stock_id, icon_size);
924   else if (action->private_data->icon_name)
925     return gtk_image_new_from_icon_name (action->private_data->icon_name, icon_size);
926   else
927     return NULL;
928 }
929
930 /**
931  * gtk_action_create_menu_item:
932  * @action: the action object
933  *
934  * Creates a menu item widget that proxies for the given action.
935  *
936  * Returns: a menu item connected to the action.
937  *
938  * Since: 2.4
939  */
940 GtkWidget *
941 gtk_action_create_menu_item (GtkAction *action)
942 {
943   GtkWidget *menu_item;
944
945   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
946
947   menu_item = (* GTK_ACTION_GET_CLASS (action)->create_menu_item) (action);
948
949   (* GTK_ACTION_GET_CLASS (action)->connect_proxy) (action, menu_item);
950
951   return menu_item;
952 }
953
954 /**
955  * gtk_action_create_tool_item:
956  * @action: the action object
957  *
958  * Creates a toolbar item widget that proxies for the given action.
959  *
960  * Returns: a toolbar item connected to the action.
961  *
962  * Since: 2.4
963  */
964 GtkWidget *
965 gtk_action_create_tool_item (GtkAction *action)
966 {
967   GtkWidget *button;
968
969   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
970
971   button = (* GTK_ACTION_GET_CLASS (action)->create_tool_item) (action);
972
973   (* GTK_ACTION_GET_CLASS (action)->connect_proxy) (action, button);
974
975   return button;
976 }
977
978 /**
979  * gtk_action_connect_proxy:
980  * @action: the action object
981  * @proxy: the proxy widget
982  *
983  * Connects a widget to an action object as a proxy.  Synchronises 
984  * various properties of the action with the widget (such as label 
985  * text, icon, tooltip, etc), and attaches a callback so that the 
986  * action gets activated when the proxy widget does.
987  *
988  * If the widget is already connected to an action, it is disconnected
989  * first.
990  *
991  * Since: 2.4
992  */
993 void
994 gtk_action_connect_proxy (GtkAction *action,
995                           GtkWidget *proxy)
996 {
997   GtkAction *prev_action;
998
999   g_return_if_fail (GTK_IS_ACTION (action));
1000   g_return_if_fail (GTK_IS_WIDGET (proxy));
1001
1002   prev_action = g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy);
1003
1004   if (prev_action)
1005     (* GTK_ACTION_GET_CLASS (action)->disconnect_proxy) (prev_action, proxy);  
1006
1007   (* GTK_ACTION_GET_CLASS (action)->connect_proxy) (action, proxy);
1008 }
1009
1010 /**
1011  * gtk_action_disconnect_proxy:
1012  * @action: the action object
1013  * @proxy: the proxy widget
1014  *
1015  * Disconnects a proxy widget from an action.  
1016  * Does <emphasis>not</emphasis> destroy the widget, however.
1017  *
1018  * Since: 2.4
1019  */
1020 void
1021 gtk_action_disconnect_proxy (GtkAction *action,
1022                              GtkWidget *proxy)
1023 {
1024   g_return_if_fail (GTK_IS_ACTION (action));
1025   g_return_if_fail (GTK_IS_WIDGET (proxy));
1026
1027   g_return_if_fail (g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy) == action);
1028
1029   (* GTK_ACTION_GET_CLASS (action)->disconnect_proxy) (action, proxy);  
1030 }
1031
1032 /**
1033  * gtk_action_get_proxies:
1034  * @action: the action object
1035  * 
1036  * Returns the proxy widgets for an action.
1037  * See also gtk_widget_get_action().
1038  * 
1039  * Return value: a #GSList of proxy widgets. The list is owned by GTK+
1040  * and must not be modified.
1041  *
1042  * Since: 2.4
1043  **/
1044 GSList*
1045 gtk_action_get_proxies (GtkAction *action)
1046 {
1047   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1048
1049   return action->private_data->proxies;
1050 }
1051
1052
1053 /**
1054  * gtk_widget_get_action:
1055  * @widget: a #GtkWidget
1056  *
1057  * Returns the #GtkAction that @widget is a proxy for. 
1058  * See also gtk_action_get_proxies().
1059  *
1060  * Returns: the action that a widget is a proxy for, or
1061  *  %NULL, if it is not attached to an action.
1062  *
1063  * Since: 2.10
1064  */
1065 GtkAction*
1066 gtk_widget_get_action (GtkWidget *widget)
1067 {
1068   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1069   
1070   return g_object_get_qdata (G_OBJECT (widget), quark_gtk_action_proxy);
1071 }
1072
1073
1074 /**
1075  * gtk_action_get_name:
1076  * @action: the action object
1077  * 
1078  * Returns the name of the action.
1079  * 
1080  * Return value: the name of the action. The string belongs to GTK+ and should not
1081  *   be freed.
1082  *
1083  * Since: 2.4
1084  **/
1085 G_CONST_RETURN gchar *
1086 gtk_action_get_name (GtkAction *action)
1087 {
1088   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1089
1090   return action->private_data->name;
1091 }
1092
1093 /**
1094  * gtk_action_is_sensitive:
1095  * @action: the action object
1096  * 
1097  * Returns whether the action is effectively sensitive.
1098  *
1099  * Return value: %TRUE if the action and its associated action group 
1100  * are both sensitive.
1101  *
1102  * Since: 2.4
1103  **/
1104 gboolean
1105 gtk_action_is_sensitive (GtkAction *action)
1106 {
1107   GtkActionPrivate *priv;
1108   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1109
1110   priv = action->private_data;
1111   return priv->sensitive &&
1112     (priv->action_group == NULL ||
1113      gtk_action_group_get_sensitive (priv->action_group));
1114 }
1115
1116 /**
1117  * gtk_action_get_sensitive:
1118  * @action: the action object
1119  * 
1120  * Returns whether the action itself is sensitive. Note that this doesn't 
1121  * necessarily mean effective sensitivity. See gtk_action_is_sensitive() 
1122  * for that.
1123  *
1124  * Return value: %TRUE if the action itself is sensitive.
1125  *
1126  * Since: 2.4
1127  **/
1128 gboolean
1129 gtk_action_get_sensitive (GtkAction *action)
1130 {
1131   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1132
1133   return action->private_data->sensitive;
1134 }
1135
1136 void
1137 _gtk_action_sync_sensitive (GtkAction *action)
1138 {
1139   GSList *p;
1140   GtkWidget *proxy;
1141   gboolean sensitive;
1142
1143   sensitive = gtk_action_is_sensitive (action);
1144
1145   for (p = action->private_data->proxies; p; p = p->next)
1146     {
1147       proxy = (GtkWidget *)p->data;
1148       gtk_widget_set_sensitive (proxy, sensitive);
1149     }      
1150 }
1151
1152 /**
1153  * gtk_action_set_sensitive:
1154  * @action: the action object
1155  * @sensitive: %TRUE to make the action sensitive
1156  * 
1157  * Sets the ::sensitive property of the action to @sensitive. Note that 
1158  * this doesn't necessarily mean effective sensitivity. See 
1159  * gtk_action_is_sensitive() 
1160  * for that.
1161  *
1162  * Since: 2.6
1163  **/
1164 void
1165 gtk_action_set_sensitive (GtkAction *action,
1166                           gboolean   sensitive)
1167 {
1168   g_return_if_fail (GTK_IS_ACTION (action));
1169
1170   sensitive = sensitive != FALSE;
1171   
1172   if (action->private_data->sensitive != sensitive)
1173     {
1174       action->private_data->sensitive = sensitive;
1175
1176       _gtk_action_sync_sensitive (action);
1177
1178       g_object_notify (G_OBJECT (action), "sensitive");
1179     }
1180 }
1181
1182 /**
1183  * gtk_action_is_visible:
1184  * @action: the action object
1185  * 
1186  * Returns whether the action is effectively visible.
1187  *
1188  * Return value: %TRUE if the action and its associated action group 
1189  * are both visible.
1190  *
1191  * Since: 2.4
1192  **/
1193 gboolean
1194 gtk_action_is_visible (GtkAction *action)
1195 {
1196   GtkActionPrivate *priv;
1197   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1198
1199   priv = action->private_data;
1200   return priv->visible &&
1201     (priv->action_group == NULL ||
1202      gtk_action_group_get_visible (priv->action_group));
1203 }
1204
1205 /**
1206  * gtk_action_get_visible:
1207  * @action: the action object
1208  * 
1209  * Returns whether the action itself is visible. Note that this doesn't 
1210  * necessarily mean effective visibility. See gtk_action_is_sensitive() 
1211  * for that.
1212  *
1213  * Return value: %TRUE if the action itself is visible.
1214  *
1215  * Since: 2.4
1216  **/
1217 gboolean
1218 gtk_action_get_visible (GtkAction *action)
1219 {
1220   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1221
1222   return action->private_data->visible;
1223 }
1224
1225 void
1226 _gtk_action_sync_visible (GtkAction *action)
1227 {
1228   GSList *p;
1229   GtkWidget *proxy;
1230   GtkWidget *menu;
1231   gboolean visible;
1232
1233   visible = gtk_action_is_visible (action);
1234     
1235   for (p = action->private_data->proxies; p; p = p->next)
1236     {
1237       proxy = (GtkWidget *)p->data;
1238
1239       if (GTK_IS_MENU_ITEM (proxy))
1240         {
1241           menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy));
1242           
1243           _gtk_action_sync_menu_visible (action, proxy, _gtk_menu_is_empty (menu));
1244         }
1245       else
1246         {
1247           if (visible)
1248             gtk_widget_show (proxy);
1249           else
1250             gtk_widget_hide (proxy);
1251         }
1252     } 
1253 }
1254
1255 /**
1256  * gtk_action_set_visible:
1257  * @action: the action object
1258  * @visible: %TRUE to make the action visible
1259  * 
1260  * Sets the ::visible property of the action to @visible. Note that 
1261  * this doesn't necessarily mean effective visibility. See 
1262  * gtk_action_is_visible() 
1263  * for that.
1264  *
1265  * Since: 2.6
1266  **/
1267 void
1268 gtk_action_set_visible (GtkAction *action,
1269                         gboolean   visible)
1270 {
1271   g_return_if_fail (GTK_IS_ACTION (action));
1272
1273   visible = visible != FALSE;
1274   
1275   if (action->private_data->visible != visible)
1276     {
1277       action->private_data->visible = visible;
1278
1279       _gtk_action_sync_visible (action);
1280
1281       g_object_notify (G_OBJECT (action), "visible");
1282     }
1283 }
1284
1285 static void 
1286 gtk_action_set_is_important (GtkAction *action,
1287                              gboolean   is_important)
1288 {
1289   GSList *p;
1290   GtkWidget *proxy;
1291
1292   is_important = is_important != FALSE;
1293   
1294   if (action->private_data->is_important != is_important)
1295     {
1296       action->private_data->is_important = is_important;
1297
1298       for (p = action->private_data->proxies; p; p = p->next)
1299         {
1300           proxy = (GtkWidget *)p->data;
1301
1302           if (GTK_IS_TOOL_ITEM (proxy))
1303             gtk_tool_item_set_is_important (GTK_TOOL_ITEM (proxy),
1304                                             is_important);
1305         }
1306       
1307       g_object_notify (G_OBJECT (action), "is-important");
1308     }  
1309 }
1310
1311 static void 
1312 gtk_action_set_label (GtkAction   *action,
1313                       const gchar *label)
1314 {
1315   GSList *p;
1316   GtkWidget *proxy, *child;
1317   gchar *tmp;
1318   
1319   tmp = action->private_data->label;
1320   action->private_data->label = g_strdup (label);
1321   g_free (tmp);
1322   action->private_data->label_set = (action->private_data->label != NULL);
1323   /* if label is unset, then use the label from the stock item */
1324   if (!action->private_data->label_set && action->private_data->stock_id)
1325     {
1326       GtkStockItem stock_item;
1327       
1328       if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
1329         action->private_data->label = g_strdup (stock_item.label);
1330     }
1331   
1332   for (p = action->private_data->proxies; p; p = p->next)
1333     {
1334       proxy = (GtkWidget *)p->data;
1335       
1336       if (GTK_IS_MENU_ITEM (proxy))
1337         {
1338           child = GTK_BIN (proxy)->child;
1339           
1340           if (GTK_IS_LABEL (child))
1341             gtk_label_set_label (GTK_LABEL (child), 
1342                                  action->private_data->label);
1343         }
1344     }
1345   
1346   g_object_notify (G_OBJECT (action), "label");
1347   
1348   /* if short_label is unset, set short_label=label */
1349   if (!action->private_data->short_label_set)
1350     {
1351       gtk_action_set_short_label (action, action->private_data->label);
1352       action->private_data->short_label_set = FALSE;
1353     }
1354 }
1355
1356 static void 
1357 gtk_action_set_short_label (GtkAction   *action,
1358                             const gchar *label)
1359 {
1360   GSList *p;
1361   GtkWidget *proxy, *child;
1362   gchar *tmp;
1363
1364   tmp = action->private_data->short_label;
1365   action->private_data->short_label = g_strdup (label);
1366   g_free (tmp);
1367   action->private_data->short_label_set = (action->private_data->short_label != NULL);
1368   /* if short_label is unset, then use the value of label */
1369   if (!action->private_data->short_label_set)
1370     action->private_data->short_label = g_strdup (action->private_data->label);
1371
1372   for (p = action->private_data->proxies; p; p = p->next)
1373     {
1374       proxy = (GtkWidget *)p->data;
1375
1376       if (GTK_IS_TOOL_BUTTON (proxy))
1377         gtk_tool_button_set_label (GTK_TOOL_BUTTON (proxy), 
1378                                    action->private_data->short_label);
1379       else if (GTK_IS_BUTTON (proxy) &&
1380                !gtk_button_get_use_stock (GTK_BUTTON (proxy)))
1381         {
1382           child = GTK_BIN (proxy)->child;
1383           
1384           if (child == NULL || GTK_IS_LABEL (child))
1385             gtk_button_set_label (GTK_BUTTON (proxy), 
1386                                   action->private_data->short_label);
1387         }
1388     }
1389
1390   g_object_notify (G_OBJECT (action), "short-label");
1391 }
1392
1393 static void 
1394 gtk_action_set_visible_horizontal (GtkAction *action,
1395                                    gboolean   visible_horizontal)
1396 {
1397   GSList *p;
1398   GtkWidget *proxy;
1399
1400   visible_horizontal = visible_horizontal != FALSE;
1401   
1402   if (action->private_data->visible_horizontal != visible_horizontal)
1403     {
1404       action->private_data->visible_horizontal = visible_horizontal;
1405
1406       for (p = action->private_data->proxies; p; p = p->next)
1407         {
1408           proxy = (GtkWidget *)p->data;
1409
1410           if (GTK_IS_TOOL_ITEM (proxy))
1411             gtk_tool_item_set_visible_horizontal (GTK_TOOL_ITEM (proxy),
1412                                                   visible_horizontal);
1413         }
1414       
1415       g_object_notify (G_OBJECT (action), "visible-horizontal");
1416     }  
1417 }
1418
1419 static void 
1420 gtk_action_set_visible_vertical (GtkAction *action,
1421                                  gboolean   visible_vertical)
1422 {
1423   GSList *p;
1424   GtkWidget *proxy;
1425
1426   visible_vertical = visible_vertical != FALSE;
1427   
1428   if (action->private_data->visible_vertical != visible_vertical)
1429     {
1430       action->private_data->visible_vertical = visible_vertical;
1431
1432       for (p = action->private_data->proxies; p; p = p->next)
1433         {
1434           proxy = (GtkWidget *)p->data;
1435
1436           if (GTK_IS_TOOL_ITEM (proxy))
1437             gtk_tool_item_set_visible_vertical (GTK_TOOL_ITEM (proxy),
1438                                                 visible_vertical);
1439         }
1440       
1441       g_object_notify (G_OBJECT (action), "visible-vertical");
1442     }  
1443 }
1444
1445 static void 
1446 gtk_action_sync_tooltip (GtkAction *action,
1447                          GtkWidget *proxy)
1448 {
1449   gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (proxy),
1450                                   action->private_data->tooltip);
1451 }
1452
1453 static void 
1454 gtk_action_set_tooltip (GtkAction   *action,
1455                         const gchar *tooltip)
1456 {
1457   GSList *p;
1458   GtkWidget *proxy;
1459   gchar *tmp;
1460
1461   tmp = action->private_data->tooltip;
1462   action->private_data->tooltip = g_strdup (tooltip);
1463   g_free (tmp);
1464
1465   for (p = action->private_data->proxies; p; p = p->next)
1466     {
1467       proxy = (GtkWidget *)p->data;
1468
1469       if (GTK_IS_TOOL_ITEM (proxy))
1470         gtk_action_sync_tooltip (action, proxy);
1471     }
1472
1473   g_object_notify (G_OBJECT (action), "tooltip");
1474 }
1475
1476 static void 
1477 gtk_action_set_stock_id (GtkAction   *action,
1478                          const gchar *stock_id)
1479 {
1480   GSList *p;
1481   GtkWidget *proxy, *image;
1482   gchar *tmp;
1483   
1484   tmp = action->private_data->stock_id;
1485   action->private_data->stock_id = g_strdup (stock_id);
1486   g_free (tmp);
1487
1488   for (p = action->private_data->proxies; p; p = p->next)
1489     {
1490       proxy = (GtkWidget *)p->data;
1491       
1492       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
1493         {
1494           image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
1495           
1496           if (GTK_IS_IMAGE (image))
1497             gtk_image_set_from_stock (GTK_IMAGE (image),
1498                                       action->private_data->stock_id, GTK_ICON_SIZE_MENU);
1499         } 
1500       else if (GTK_IS_TOOL_BUTTON (proxy))
1501         {
1502           gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (proxy),
1503                                         action->private_data->stock_id);
1504         }
1505       else if (GTK_IS_BUTTON (proxy) &&
1506                gtk_button_get_use_stock (GTK_BUTTON (proxy)))
1507         {
1508           gtk_button_set_label (GTK_BUTTON (proxy),
1509                                 action->private_data->stock_id);
1510         }
1511     }
1512
1513   g_object_notify (G_OBJECT (action), "stock-id");
1514   
1515   /* update label and short_label if appropriate */
1516   if (!action->private_data->label_set)
1517     {
1518       GtkStockItem stock_item;
1519       
1520       if (action->private_data->stock_id &&
1521           gtk_stock_lookup (action->private_data->stock_id, &stock_item))
1522         gtk_action_set_label (action, stock_item.label);
1523       else 
1524         gtk_action_set_label (action, NULL);
1525       
1526       action->private_data->label_set = FALSE;
1527     }
1528 }
1529
1530 static void 
1531 gtk_action_set_icon_name (GtkAction   *action,
1532                           const gchar *icon_name)
1533 {
1534   GSList *p;
1535   GtkWidget *proxy, *image;
1536   gchar *tmp;
1537   
1538   tmp = action->private_data->icon_name;
1539   action->private_data->icon_name = g_strdup (icon_name);
1540   g_free (tmp);
1541
1542   for (p = action->private_data->proxies; p; p = p->next)
1543     {
1544       proxy = (GtkWidget *)p->data;
1545       
1546       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
1547         {
1548           image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
1549           
1550           if (GTK_IS_IMAGE (image) &&
1551               (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
1552                gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
1553             gtk_image_set_from_icon_name (GTK_IMAGE (image),
1554                                           action->private_data->icon_name, GTK_ICON_SIZE_MENU);
1555         } 
1556       else if (GTK_IS_TOOL_BUTTON (proxy))
1557         {
1558           gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (proxy),
1559                                          action->private_data->icon_name);
1560         }
1561       else if (GTK_IS_BUTTON (proxy) &&
1562                !gtk_button_get_use_stock (GTK_BUTTON (proxy)))
1563         {
1564           image = gtk_button_get_image (GTK_BUTTON (proxy));
1565           
1566           if (GTK_IS_IMAGE (image) &&
1567               (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
1568                gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
1569             gtk_image_set_from_icon_name (GTK_IMAGE (image),
1570                                           action->private_data->icon_name, GTK_ICON_SIZE_MENU);
1571         }
1572     }
1573   
1574   g_object_notify (G_OBJECT (action), "icon-name");
1575 }
1576
1577
1578 /**
1579  * gtk_action_block_activate_from:
1580  * @action: the action object
1581  * @proxy: a proxy widget
1582  *
1583  * Disables calls to the gtk_action_activate()
1584  * function by signals on the given proxy widget.  This is used to
1585  * break notification loops for things like check or radio actions.
1586  *
1587  * This function is intended for use by action implementations.
1588  * 
1589  * Since: 2.4
1590  */
1591 void
1592 gtk_action_block_activate_from (GtkAction *action, 
1593                                 GtkWidget *proxy)
1594 {
1595   g_return_if_fail (GTK_IS_ACTION (action));
1596   
1597   g_signal_handlers_block_by_func (proxy, G_CALLBACK (gtk_action_activate),
1598                                    action);
1599 }
1600
1601 /**
1602  * gtk_action_unblock_activate_from:
1603  * @action: the action object
1604  * @proxy: a proxy widget
1605  *
1606  * Re-enables calls to the gtk_action_activate()
1607  * function by signals on the given proxy widget.  This undoes the
1608  * blocking done by gtk_action_block_activate_from().
1609  *
1610  * This function is intended for use by action implementations.
1611  * 
1612  * Since: 2.4
1613  */
1614 void
1615 gtk_action_unblock_activate_from (GtkAction *action, 
1616                                   GtkWidget *proxy)
1617 {
1618   g_return_if_fail (GTK_IS_ACTION (action));
1619
1620   g_signal_handlers_unblock_by_func (proxy, G_CALLBACK (gtk_action_activate),
1621                                      action);
1622 }
1623
1624 static void
1625 closure_accel_activate (GClosure     *closure,
1626                         GValue       *return_value,
1627                         guint         n_param_values,
1628                         const GValue *param_values,
1629                         gpointer      invocation_hint,
1630                         gpointer      marshal_data)
1631 {
1632   if (gtk_action_is_sensitive (GTK_ACTION (closure->data)))
1633     {
1634       _gtk_action_emit_activate (GTK_ACTION (closure->data));
1635       
1636       /* we handled the accelerator */
1637       g_value_set_boolean (return_value, TRUE);
1638     }
1639 }
1640
1641 static void
1642 gtk_action_set_action_group (GtkAction      *action,
1643                              GtkActionGroup *action_group)
1644 {
1645   if (action->private_data->action_group == NULL)
1646     g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1647   else
1648     g_return_if_fail (action_group == NULL);
1649
1650   action->private_data->action_group = action_group;
1651 }
1652
1653 /**
1654  * gtk_action_set_accel_path:
1655  * @action: the action object
1656  * @accel_path: the accelerator path
1657  *
1658  * Sets the accel path for this action.  All proxy widgets associated
1659  * with the action will have this accel path, so that their
1660  * accelerators are consistent.
1661  *
1662  * Note that @accel_path string will be stored in a #GQuark. Therefore, if you
1663  * pass a static string, you can save some memory by interning it first with 
1664  * g_intern_static_string().
1665  *
1666  * Since: 2.4
1667  */
1668 void
1669 gtk_action_set_accel_path (GtkAction   *action, 
1670                            const gchar *accel_path)
1671 {
1672   g_return_if_fail (GTK_IS_ACTION (action));
1673
1674   action->private_data->accel_quark = g_quark_from_string (accel_path);
1675 }
1676
1677 /**
1678  * gtk_action_get_accel_path:
1679  * @action: the action object
1680  *
1681  * Returns the accel path for this action.  
1682  *
1683  * Since: 2.6
1684  *
1685  * Returns: the accel path for this action, or %NULL
1686  *   if none is set. The returned string is owned by GTK+ 
1687  *   and must not be freed or modified.
1688  */
1689 G_CONST_RETURN gchar *
1690 gtk_action_get_accel_path (GtkAction *action)
1691 {
1692   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1693
1694   if (action->private_data->accel_quark)
1695     return g_quark_to_string (action->private_data->accel_quark);
1696   else
1697     return NULL;
1698 }
1699
1700 /**
1701  * gtk_action_get_accel_closure:
1702  * @action: the action object
1703  *
1704  * Returns the accel closure for this action.
1705  *
1706  * Since: 2.8
1707  *
1708  * Returns: the accel closure for this action. The returned closure is
1709  *          owned by GTK+ and must not be unreffed or modified.
1710  */
1711 GClosure *
1712 gtk_action_get_accel_closure (GtkAction *action)
1713 {
1714   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1715
1716   return action->private_data->accel_closure;
1717 }
1718
1719
1720 /**
1721  * gtk_action_set_accel_group:
1722  * @action: the action object
1723  * @accel_group: a #GtkAccelGroup or %NULL
1724  * 
1725  * Sets the #GtkAccelGroup in which the accelerator for this action
1726  * will be installed.
1727  *
1728  * Since: 2.4
1729  **/
1730 void
1731 gtk_action_set_accel_group (GtkAction     *action,
1732                             GtkAccelGroup *accel_group)
1733 {
1734   g_return_if_fail (GTK_IS_ACTION (action));
1735   g_return_if_fail (accel_group == NULL || GTK_IS_ACCEL_GROUP (accel_group));
1736   
1737   if (accel_group)
1738     g_object_ref (accel_group);
1739   if (action->private_data->accel_group)
1740     g_object_unref (action->private_data->accel_group);
1741
1742   action->private_data->accel_group = accel_group;
1743 }
1744
1745 /**
1746  * gtk_action_connect_accelerator:
1747  * @action: a #GtkAction
1748  * 
1749  * Installs the accelerator for @action if @action has an
1750  * accel path and group. See gtk_action_set_accel_path() and 
1751  * gtk_action_set_accel_group()
1752  *
1753  * Since multiple proxies may independently trigger the installation
1754  * of the accelerator, the @action counts the number of times this
1755  * function has been called and doesn't remove the accelerator until
1756  * gtk_action_disconnect_accelerator() has been called as many times.
1757  *
1758  * Since: 2.4
1759  **/
1760 void 
1761 gtk_action_connect_accelerator (GtkAction *action)
1762 {
1763   g_return_if_fail (GTK_IS_ACTION (action));
1764
1765   if (!action->private_data->accel_quark ||
1766       !action->private_data->accel_group)
1767     return;
1768
1769   if (action->private_data->accel_count == 0)
1770     {
1771       const gchar *accel_path = 
1772         g_quark_to_string (action->private_data->accel_quark);
1773       
1774       gtk_accel_group_connect_by_path (action->private_data->accel_group,
1775                                        accel_path,
1776                                        action->private_data->accel_closure);
1777     }
1778
1779   action->private_data->accel_count++;
1780 }
1781
1782 /**
1783  * gtk_action_disconnect_accelerator:
1784  * @action: a #GtkAction
1785  * 
1786  * Undoes the effect of one call to gtk_action_connect_accelerator().
1787  *
1788  * Since: 2.4
1789  **/
1790 void 
1791 gtk_action_disconnect_accelerator (GtkAction *action)
1792 {
1793   g_return_if_fail (GTK_IS_ACTION (action));
1794
1795   if (!action->private_data->accel_quark ||
1796       !action->private_data->accel_group)
1797     return;
1798
1799   action->private_data->accel_count--;
1800
1801   if (action->private_data->accel_count == 0)
1802     gtk_accel_group_disconnect (action->private_data->accel_group,
1803                                 action->private_data->accel_closure);
1804 }
1805
1806 /**
1807  * gtk_action_create_menu:
1808  * @action: a #GtkAction
1809  *
1810  * If @action provides a #GtkMenu widget as a submenu for the menu
1811  * item or the toolbar item it creates, this function returns an
1812  * instance of that menu.
1813  *
1814  * Return value: the menu item provided by the action, or %NULL.
1815  *
1816  * Since: 2.12
1817  */
1818 GtkWidget *
1819 gtk_action_create_menu (GtkAction *action)
1820 {
1821   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1822
1823   if (GTK_ACTION_GET_CLASS (action)->create_menu)
1824     return GTK_ACTION_GET_CLASS (action)->create_menu (action);
1825
1826   return NULL;
1827 }
1828
1829 #define __GTK_ACTION_C__
1830 #include "gtkaliasdef.c"