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