]> Pileus Git - ~andy/gtk/blob - gtk/gtkaction.c
consistently chain up using GTK_FOO_CLASS(parent_class)->bar(instance)
[~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           GtkWidget *image;
821
822           image = gtk_button_get_image (GTK_BUTTON (proxy));
823
824           if (GTK_IS_IMAGE (image) ||
825               GTK_BIN (proxy)->child == NULL || 
826               GTK_IS_LABEL (GTK_BIN (proxy)->child))
827             {
828               /* synchronise the label */
829               g_object_set (proxy,
830                             "label", action->private_data->short_label,
831                             "use-underline", TRUE,
832                             NULL);
833             }
834
835           if (GTK_IS_IMAGE (image) &&
836               (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
837                gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
838             gtk_image_set_from_icon_name (GTK_IMAGE (image),
839                                           action->private_data->icon_name, GTK_ICON_SIZE_MENU);
840         }
841       /* we leave the button alone if there is a custom child */
842       g_signal_connect_object (proxy, "clicked",
843                                G_CALLBACK (gtk_action_activate), action,
844                                G_CONNECT_SWAPPED);
845     }
846
847   if (action->private_data->action_group)
848     _gtk_action_group_emit_connect_proxy (action->private_data->action_group, action, proxy);
849 }
850
851 static void
852 disconnect_proxy (GtkAction *action, 
853                   GtkWidget *proxy)
854 {
855   g_object_set_qdata (G_OBJECT (proxy), quark_gtk_action_proxy, NULL);
856
857   g_object_weak_unref (G_OBJECT (proxy), (GWeakNotify)remove_proxy, action);
858   remove_proxy (action, proxy);
859
860   /* disconnect the activate handler */
861   g_signal_handlers_disconnect_by_func (proxy,
862                                         G_CALLBACK (gtk_action_activate),
863                                         action);
864
865   /* toolbar button specific synchronisers ... */
866   g_signal_handlers_disconnect_by_func (proxy,
867                                         G_CALLBACK (gtk_action_create_menu_proxy),
868                                         action);
869
870   if (action->private_data->action_group)
871     _gtk_action_group_emit_disconnect_proxy (action->private_data->action_group, action, proxy);
872 }
873
874 void
875 _gtk_action_emit_activate (GtkAction *action)
876 {
877   GtkActionGroup *group = action->private_data->action_group;
878
879   if (group != NULL) 
880     {
881       g_object_ref (group);
882       _gtk_action_group_emit_pre_activate (group, action);
883     }
884
885     g_signal_emit (action, action_signals[ACTIVATE], 0);
886
887   if (group != NULL) 
888     {
889       _gtk_action_group_emit_post_activate (group, action);
890       g_object_unref (group);
891     }
892 }
893
894 /**
895  * gtk_action_activate:
896  * @action: the action object
897  *
898  * Emits the "activate" signal on the specified action, if it isn't 
899  * insensitive. This gets called by the proxy widgets when they get 
900  * activated.
901  *
902  * It can also be used to manually activate an action.
903  *
904  * Since: 2.4
905  */
906 void
907 gtk_action_activate (GtkAction *action)
908 {
909   g_return_if_fail (GTK_IS_ACTION (action));
910   
911   if (gtk_action_is_sensitive (action))
912     _gtk_action_emit_activate (action);
913 }
914
915 /**
916  * gtk_action_create_icon:
917  * @action: the action object
918  * @icon_size: the size of the icon that should be created.
919  *
920  * This function is intended for use by action implementations to
921  * create icons displayed in the proxy widgets.
922  *
923  * Returns: a widget that displays the icon for this action.
924  *
925  * Since: 2.4
926  */
927 GtkWidget *
928 gtk_action_create_icon (GtkAction *action, GtkIconSize icon_size)
929 {
930   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
931
932   if (action->private_data->stock_id &&
933       gtk_icon_factory_lookup_default (action->private_data->stock_id))
934     return gtk_image_new_from_stock (action->private_data->stock_id, icon_size);
935   else if (action->private_data->icon_name)
936     return gtk_image_new_from_icon_name (action->private_data->icon_name, icon_size);
937   else
938     return NULL;
939 }
940
941 /**
942  * gtk_action_create_menu_item:
943  * @action: the action object
944  *
945  * Creates a menu item widget that proxies for the given action.
946  *
947  * Returns: a menu item connected to the action.
948  *
949  * Since: 2.4
950  */
951 GtkWidget *
952 gtk_action_create_menu_item (GtkAction *action)
953 {
954   GtkWidget *menu_item;
955
956   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
957
958   menu_item = GTK_ACTION_GET_CLASS (action)->create_menu_item (action);
959
960   GTK_ACTION_GET_CLASS (action)->connect_proxy (action, menu_item);
961
962   return menu_item;
963 }
964
965 /**
966  * gtk_action_create_tool_item:
967  * @action: the action object
968  *
969  * Creates a toolbar item widget that proxies for the given action.
970  *
971  * Returns: a toolbar item connected to the action.
972  *
973  * Since: 2.4
974  */
975 GtkWidget *
976 gtk_action_create_tool_item (GtkAction *action)
977 {
978   GtkWidget *button;
979
980   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
981
982   button = GTK_ACTION_GET_CLASS (action)->create_tool_item (action);
983
984   GTK_ACTION_GET_CLASS (action)->connect_proxy (action, button);
985
986   return button;
987 }
988
989 /**
990  * gtk_action_connect_proxy:
991  * @action: the action object
992  * @proxy: the proxy widget
993  *
994  * Connects a widget to an action object as a proxy.  Synchronises 
995  * various properties of the action with the widget (such as label 
996  * text, icon, tooltip, etc), and attaches a callback so that the 
997  * action gets activated when the proxy widget does.
998  *
999  * If the widget is already connected to an action, it is disconnected
1000  * first.
1001  *
1002  * Since: 2.4
1003  */
1004 void
1005 gtk_action_connect_proxy (GtkAction *action,
1006                           GtkWidget *proxy)
1007 {
1008   GtkAction *prev_action;
1009
1010   g_return_if_fail (GTK_IS_ACTION (action));
1011   g_return_if_fail (GTK_IS_WIDGET (proxy));
1012
1013   prev_action = g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy);
1014
1015   if (prev_action)
1016     GTK_ACTION_GET_CLASS (action)->disconnect_proxy (prev_action, proxy);
1017
1018   GTK_ACTION_GET_CLASS (action)->connect_proxy (action, proxy);
1019 }
1020
1021 /**
1022  * gtk_action_disconnect_proxy:
1023  * @action: the action object
1024  * @proxy: the proxy widget
1025  *
1026  * Disconnects a proxy widget from an action.  
1027  * Does <emphasis>not</emphasis> destroy the widget, however.
1028  *
1029  * Since: 2.4
1030  */
1031 void
1032 gtk_action_disconnect_proxy (GtkAction *action,
1033                              GtkWidget *proxy)
1034 {
1035   g_return_if_fail (GTK_IS_ACTION (action));
1036   g_return_if_fail (GTK_IS_WIDGET (proxy));
1037
1038   g_return_if_fail (g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy) == action);
1039
1040   GTK_ACTION_GET_CLASS (action)->disconnect_proxy (action, proxy);
1041 }
1042
1043 /**
1044  * gtk_action_get_proxies:
1045  * @action: the action object
1046  * 
1047  * Returns the proxy widgets for an action.
1048  * See also gtk_widget_get_action().
1049  * 
1050  * Return value: a #GSList of proxy widgets. The list is owned by GTK+
1051  * and must not be modified.
1052  *
1053  * Since: 2.4
1054  **/
1055 GSList*
1056 gtk_action_get_proxies (GtkAction *action)
1057 {
1058   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1059
1060   return action->private_data->proxies;
1061 }
1062
1063
1064 /**
1065  * gtk_widget_get_action:
1066  * @widget: a #GtkWidget
1067  *
1068  * Returns the #GtkAction that @widget is a proxy for. 
1069  * See also gtk_action_get_proxies().
1070  *
1071  * Returns: the action that a widget is a proxy for, or
1072  *  %NULL, if it is not attached to an action.
1073  *
1074  * Since: 2.10
1075  */
1076 GtkAction*
1077 gtk_widget_get_action (GtkWidget *widget)
1078 {
1079   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1080   
1081   return g_object_get_qdata (G_OBJECT (widget), quark_gtk_action_proxy);
1082 }
1083
1084
1085 /**
1086  * gtk_action_get_name:
1087  * @action: the action object
1088  * 
1089  * Returns the name of the action.
1090  * 
1091  * Return value: the name of the action. The string belongs to GTK+ and should not
1092  *   be freed.
1093  *
1094  * Since: 2.4
1095  **/
1096 G_CONST_RETURN gchar *
1097 gtk_action_get_name (GtkAction *action)
1098 {
1099   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1100
1101   return action->private_data->name;
1102 }
1103
1104 /**
1105  * gtk_action_is_sensitive:
1106  * @action: the action object
1107  * 
1108  * Returns whether the action is effectively sensitive.
1109  *
1110  * Return value: %TRUE if the action and its associated action group 
1111  * are both sensitive.
1112  *
1113  * Since: 2.4
1114  **/
1115 gboolean
1116 gtk_action_is_sensitive (GtkAction *action)
1117 {
1118   GtkActionPrivate *priv;
1119   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1120
1121   priv = action->private_data;
1122   return priv->sensitive &&
1123     (priv->action_group == NULL ||
1124      gtk_action_group_get_sensitive (priv->action_group));
1125 }
1126
1127 /**
1128  * gtk_action_get_sensitive:
1129  * @action: the action object
1130  * 
1131  * Returns whether the action itself is sensitive. Note that this doesn't 
1132  * necessarily mean effective sensitivity. See gtk_action_is_sensitive() 
1133  * for that.
1134  *
1135  * Return value: %TRUE if the action itself is sensitive.
1136  *
1137  * Since: 2.4
1138  **/
1139 gboolean
1140 gtk_action_get_sensitive (GtkAction *action)
1141 {
1142   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1143
1144   return action->private_data->sensitive;
1145 }
1146
1147 void
1148 _gtk_action_sync_sensitive (GtkAction *action)
1149 {
1150   GSList *p;
1151   GtkWidget *proxy;
1152   gboolean sensitive;
1153
1154   sensitive = gtk_action_is_sensitive (action);
1155
1156   for (p = action->private_data->proxies; p; p = p->next)
1157     {
1158       proxy = (GtkWidget *)p->data;
1159       gtk_widget_set_sensitive (proxy, sensitive);
1160     }      
1161 }
1162
1163 /**
1164  * gtk_action_set_sensitive:
1165  * @action: the action object
1166  * @sensitive: %TRUE to make the action sensitive
1167  * 
1168  * Sets the ::sensitive property of the action to @sensitive. Note that 
1169  * this doesn't necessarily mean effective sensitivity. See 
1170  * gtk_action_is_sensitive() 
1171  * for that.
1172  *
1173  * Since: 2.6
1174  **/
1175 void
1176 gtk_action_set_sensitive (GtkAction *action,
1177                           gboolean   sensitive)
1178 {
1179   g_return_if_fail (GTK_IS_ACTION (action));
1180
1181   sensitive = sensitive != FALSE;
1182   
1183   if (action->private_data->sensitive != sensitive)
1184     {
1185       action->private_data->sensitive = sensitive;
1186
1187       _gtk_action_sync_sensitive (action);
1188
1189       g_object_notify (G_OBJECT (action), "sensitive");
1190     }
1191 }
1192
1193 /**
1194  * gtk_action_is_visible:
1195  * @action: the action object
1196  * 
1197  * Returns whether the action is effectively visible.
1198  *
1199  * Return value: %TRUE if the action and its associated action group 
1200  * are both visible.
1201  *
1202  * Since: 2.4
1203  **/
1204 gboolean
1205 gtk_action_is_visible (GtkAction *action)
1206 {
1207   GtkActionPrivate *priv;
1208   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1209
1210   priv = action->private_data;
1211   return priv->visible &&
1212     (priv->action_group == NULL ||
1213      gtk_action_group_get_visible (priv->action_group));
1214 }
1215
1216 /**
1217  * gtk_action_get_visible:
1218  * @action: the action object
1219  * 
1220  * Returns whether the action itself is visible. Note that this doesn't 
1221  * necessarily mean effective visibility. See gtk_action_is_sensitive() 
1222  * for that.
1223  *
1224  * Return value: %TRUE if the action itself is visible.
1225  *
1226  * Since: 2.4
1227  **/
1228 gboolean
1229 gtk_action_get_visible (GtkAction *action)
1230 {
1231   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1232
1233   return action->private_data->visible;
1234 }
1235
1236 void
1237 _gtk_action_sync_visible (GtkAction *action)
1238 {
1239   GSList *p;
1240   GtkWidget *proxy;
1241   GtkWidget *menu;
1242   gboolean visible;
1243
1244   visible = gtk_action_is_visible (action);
1245     
1246   for (p = action->private_data->proxies; p; p = p->next)
1247     {
1248       proxy = (GtkWidget *)p->data;
1249
1250       if (GTK_IS_MENU_ITEM (proxy))
1251         {
1252           menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy));
1253           
1254           _gtk_action_sync_menu_visible (action, proxy, _gtk_menu_is_empty (menu));
1255         }
1256       else
1257         {
1258           if (visible)
1259             gtk_widget_show (proxy);
1260           else
1261             gtk_widget_hide (proxy);
1262         }
1263     } 
1264 }
1265
1266 /**
1267  * gtk_action_set_visible:
1268  * @action: the action object
1269  * @visible: %TRUE to make the action visible
1270  * 
1271  * Sets the ::visible property of the action to @visible. Note that 
1272  * this doesn't necessarily mean effective visibility. See 
1273  * gtk_action_is_visible() 
1274  * for that.
1275  *
1276  * Since: 2.6
1277  **/
1278 void
1279 gtk_action_set_visible (GtkAction *action,
1280                         gboolean   visible)
1281 {
1282   g_return_if_fail (GTK_IS_ACTION (action));
1283
1284   visible = visible != FALSE;
1285   
1286   if (action->private_data->visible != visible)
1287     {
1288       action->private_data->visible = visible;
1289
1290       _gtk_action_sync_visible (action);
1291
1292       g_object_notify (G_OBJECT (action), "visible");
1293     }
1294 }
1295
1296 static void 
1297 gtk_action_set_is_important (GtkAction *action,
1298                              gboolean   is_important)
1299 {
1300   GSList *p;
1301   GtkWidget *proxy;
1302
1303   is_important = is_important != FALSE;
1304   
1305   if (action->private_data->is_important != is_important)
1306     {
1307       action->private_data->is_important = is_important;
1308
1309       for (p = action->private_data->proxies; p; p = p->next)
1310         {
1311           proxy = (GtkWidget *)p->data;
1312
1313           if (GTK_IS_TOOL_ITEM (proxy))
1314             gtk_tool_item_set_is_important (GTK_TOOL_ITEM (proxy),
1315                                             is_important);
1316         }
1317       
1318       g_object_notify (G_OBJECT (action), "is-important");
1319     }  
1320 }
1321
1322 static void 
1323 gtk_action_set_label (GtkAction   *action,
1324                       const gchar *label)
1325 {
1326   GSList *p;
1327   GtkWidget *proxy, *child;
1328   gchar *tmp;
1329   
1330   tmp = action->private_data->label;
1331   action->private_data->label = g_strdup (label);
1332   g_free (tmp);
1333   action->private_data->label_set = (action->private_data->label != NULL);
1334   /* if label is unset, then use the label from the stock item */
1335   if (!action->private_data->label_set && action->private_data->stock_id)
1336     {
1337       GtkStockItem stock_item;
1338       
1339       if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
1340         action->private_data->label = g_strdup (stock_item.label);
1341     }
1342   
1343   for (p = action->private_data->proxies; p; p = p->next)
1344     {
1345       proxy = (GtkWidget *)p->data;
1346       
1347       if (GTK_IS_MENU_ITEM (proxy))
1348         {
1349           child = GTK_BIN (proxy)->child;
1350           
1351           if (GTK_IS_LABEL (child))
1352             gtk_label_set_label (GTK_LABEL (child), 
1353                                  action->private_data->label);
1354         }
1355     }
1356   
1357   g_object_notify (G_OBJECT (action), "label");
1358   
1359   /* if short_label is unset, set short_label=label */
1360   if (!action->private_data->short_label_set)
1361     {
1362       gtk_action_set_short_label (action, action->private_data->label);
1363       action->private_data->short_label_set = FALSE;
1364     }
1365 }
1366
1367 static void 
1368 gtk_action_set_short_label (GtkAction   *action,
1369                             const gchar *label)
1370 {
1371   GSList *p;
1372   GtkWidget *proxy, *child;
1373   gchar *tmp;
1374
1375   tmp = action->private_data->short_label;
1376   action->private_data->short_label = g_strdup (label);
1377   g_free (tmp);
1378   action->private_data->short_label_set = (action->private_data->short_label != NULL);
1379   /* if short_label is unset, then use the value of label */
1380   if (!action->private_data->short_label_set)
1381     action->private_data->short_label = g_strdup (action->private_data->label);
1382
1383   for (p = action->private_data->proxies; p; p = p->next)
1384     {
1385       proxy = (GtkWidget *)p->data;
1386
1387       if (GTK_IS_TOOL_BUTTON (proxy))
1388         gtk_tool_button_set_label (GTK_TOOL_BUTTON (proxy),
1389                                    action->private_data->short_label);
1390       else if (GTK_IS_BUTTON (proxy) &&
1391                !gtk_button_get_use_stock (GTK_BUTTON (proxy)))
1392         {
1393           GtkWidget *image;
1394
1395           child = GTK_BIN (proxy)->child;
1396
1397           image = gtk_button_get_image (GTK_BUTTON (proxy));
1398
1399           if (GTK_IS_IMAGE (image) ||
1400               child == NULL || GTK_IS_LABEL (child))
1401             gtk_button_set_label (GTK_BUTTON (proxy),
1402                                   action->private_data->short_label);
1403         }
1404     }
1405
1406   g_object_notify (G_OBJECT (action), "short-label");
1407 }
1408
1409 static void 
1410 gtk_action_set_visible_horizontal (GtkAction *action,
1411                                    gboolean   visible_horizontal)
1412 {
1413   GSList *p;
1414   GtkWidget *proxy;
1415
1416   visible_horizontal = visible_horizontal != FALSE;
1417   
1418   if (action->private_data->visible_horizontal != visible_horizontal)
1419     {
1420       action->private_data->visible_horizontal = visible_horizontal;
1421
1422       for (p = action->private_data->proxies; p; p = p->next)
1423         {
1424           proxy = (GtkWidget *)p->data;
1425
1426           if (GTK_IS_TOOL_ITEM (proxy))
1427             gtk_tool_item_set_visible_horizontal (GTK_TOOL_ITEM (proxy),
1428                                                   visible_horizontal);
1429         }
1430       
1431       g_object_notify (G_OBJECT (action), "visible-horizontal");
1432     }  
1433 }
1434
1435 static void 
1436 gtk_action_set_visible_vertical (GtkAction *action,
1437                                  gboolean   visible_vertical)
1438 {
1439   GSList *p;
1440   GtkWidget *proxy;
1441
1442   visible_vertical = visible_vertical != FALSE;
1443   
1444   if (action->private_data->visible_vertical != visible_vertical)
1445     {
1446       action->private_data->visible_vertical = visible_vertical;
1447
1448       for (p = action->private_data->proxies; p; p = p->next)
1449         {
1450           proxy = (GtkWidget *)p->data;
1451
1452           if (GTK_IS_TOOL_ITEM (proxy))
1453             gtk_tool_item_set_visible_vertical (GTK_TOOL_ITEM (proxy),
1454                                                 visible_vertical);
1455         }
1456       
1457       g_object_notify (G_OBJECT (action), "visible-vertical");
1458     }  
1459 }
1460
1461 static void 
1462 gtk_action_sync_tooltip (GtkAction *action,
1463                          GtkWidget *proxy)
1464 {
1465   gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (proxy),
1466                                   action->private_data->tooltip);
1467 }
1468
1469 static void 
1470 gtk_action_set_tooltip (GtkAction   *action,
1471                         const gchar *tooltip)
1472 {
1473   GSList *p;
1474   GtkWidget *proxy;
1475   gchar *tmp;
1476
1477   tmp = action->private_data->tooltip;
1478   action->private_data->tooltip = g_strdup (tooltip);
1479   g_free (tmp);
1480
1481   for (p = action->private_data->proxies; p; p = p->next)
1482     {
1483       proxy = (GtkWidget *)p->data;
1484
1485       if (GTK_IS_TOOL_ITEM (proxy))
1486         gtk_action_sync_tooltip (action, proxy);
1487     }
1488
1489   g_object_notify (G_OBJECT (action), "tooltip");
1490 }
1491
1492 static void 
1493 gtk_action_set_stock_id (GtkAction   *action,
1494                          const gchar *stock_id)
1495 {
1496   GSList *p;
1497   GtkWidget *proxy, *image;
1498   gchar *tmp;
1499   
1500   tmp = action->private_data->stock_id;
1501   action->private_data->stock_id = g_strdup (stock_id);
1502   g_free (tmp);
1503
1504   for (p = action->private_data->proxies; p; p = p->next)
1505     {
1506       proxy = (GtkWidget *)p->data;
1507       
1508       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
1509         {
1510           image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
1511           
1512           if (GTK_IS_IMAGE (image))
1513             gtk_image_set_from_stock (GTK_IMAGE (image),
1514                                       action->private_data->stock_id, GTK_ICON_SIZE_MENU);
1515         } 
1516       else if (GTK_IS_TOOL_BUTTON (proxy))
1517         {
1518           gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (proxy),
1519                                         action->private_data->stock_id);
1520         }
1521       else if (GTK_IS_BUTTON (proxy) &&
1522                gtk_button_get_use_stock (GTK_BUTTON (proxy)))
1523         {
1524           gtk_button_set_label (GTK_BUTTON (proxy),
1525                                 action->private_data->stock_id);
1526         }
1527     }
1528
1529   g_object_notify (G_OBJECT (action), "stock-id");
1530   
1531   /* update label and short_label if appropriate */
1532   if (!action->private_data->label_set)
1533     {
1534       GtkStockItem stock_item;
1535       
1536       if (action->private_data->stock_id &&
1537           gtk_stock_lookup (action->private_data->stock_id, &stock_item))
1538         gtk_action_set_label (action, stock_item.label);
1539       else 
1540         gtk_action_set_label (action, NULL);
1541       
1542       action->private_data->label_set = FALSE;
1543     }
1544 }
1545
1546 static void 
1547 gtk_action_set_icon_name (GtkAction   *action,
1548                           const gchar *icon_name)
1549 {
1550   GSList *p;
1551   GtkWidget *proxy, *image;
1552   gchar *tmp;
1553   
1554   tmp = action->private_data->icon_name;
1555   action->private_data->icon_name = g_strdup (icon_name);
1556   g_free (tmp);
1557
1558   for (p = action->private_data->proxies; p; p = p->next)
1559     {
1560       proxy = (GtkWidget *)p->data;
1561       
1562       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
1563         {
1564           image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (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       else if (GTK_IS_TOOL_BUTTON (proxy))
1573         {
1574           gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (proxy),
1575                                          action->private_data->icon_name);
1576         }
1577       else if (GTK_IS_BUTTON (proxy) &&
1578                !gtk_button_get_use_stock (GTK_BUTTON (proxy)))
1579         {
1580           image = gtk_button_get_image (GTK_BUTTON (proxy));
1581           
1582           if (GTK_IS_IMAGE (image) &&
1583               (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
1584                gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
1585             gtk_image_set_from_icon_name (GTK_IMAGE (image),
1586                                           action->private_data->icon_name, GTK_ICON_SIZE_MENU);
1587         }
1588     }
1589   
1590   g_object_notify (G_OBJECT (action), "icon-name");
1591 }
1592
1593
1594 /**
1595  * gtk_action_block_activate_from:
1596  * @action: the action object
1597  * @proxy: a proxy widget
1598  *
1599  * Disables calls to the gtk_action_activate()
1600  * function by signals on the given proxy widget.  This is used to
1601  * break notification loops for things like check or radio actions.
1602  *
1603  * This function is intended for use by action implementations.
1604  * 
1605  * Since: 2.4
1606  */
1607 void
1608 gtk_action_block_activate_from (GtkAction *action, 
1609                                 GtkWidget *proxy)
1610 {
1611   g_return_if_fail (GTK_IS_ACTION (action));
1612   
1613   g_signal_handlers_block_by_func (proxy, G_CALLBACK (gtk_action_activate),
1614                                    action);
1615 }
1616
1617 /**
1618  * gtk_action_unblock_activate_from:
1619  * @action: the action object
1620  * @proxy: a proxy widget
1621  *
1622  * Re-enables calls to the gtk_action_activate()
1623  * function by signals on the given proxy widget.  This undoes the
1624  * blocking done by gtk_action_block_activate_from().
1625  *
1626  * This function is intended for use by action implementations.
1627  * 
1628  * Since: 2.4
1629  */
1630 void
1631 gtk_action_unblock_activate_from (GtkAction *action, 
1632                                   GtkWidget *proxy)
1633 {
1634   g_return_if_fail (GTK_IS_ACTION (action));
1635
1636   g_signal_handlers_unblock_by_func (proxy, G_CALLBACK (gtk_action_activate),
1637                                      action);
1638 }
1639
1640 static void
1641 closure_accel_activate (GClosure     *closure,
1642                         GValue       *return_value,
1643                         guint         n_param_values,
1644                         const GValue *param_values,
1645                         gpointer      invocation_hint,
1646                         gpointer      marshal_data)
1647 {
1648   if (gtk_action_is_sensitive (GTK_ACTION (closure->data)))
1649     {
1650       _gtk_action_emit_activate (GTK_ACTION (closure->data));
1651       
1652       /* we handled the accelerator */
1653       g_value_set_boolean (return_value, TRUE);
1654     }
1655 }
1656
1657 static void
1658 gtk_action_set_action_group (GtkAction      *action,
1659                              GtkActionGroup *action_group)
1660 {
1661   if (action->private_data->action_group == NULL)
1662     g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1663   else
1664     g_return_if_fail (action_group == NULL);
1665
1666   action->private_data->action_group = action_group;
1667 }
1668
1669 /**
1670  * gtk_action_set_accel_path:
1671  * @action: the action object
1672  * @accel_path: the accelerator path
1673  *
1674  * Sets the accel path for this action.  All proxy widgets associated
1675  * with the action will have this accel path, so that their
1676  * accelerators are consistent.
1677  *
1678  * Note that @accel_path string will be stored in a #GQuark. Therefore, if you
1679  * pass a static string, you can save some memory by interning it first with 
1680  * g_intern_static_string().
1681  *
1682  * Since: 2.4
1683  */
1684 void
1685 gtk_action_set_accel_path (GtkAction   *action, 
1686                            const gchar *accel_path)
1687 {
1688   g_return_if_fail (GTK_IS_ACTION (action));
1689
1690   action->private_data->accel_quark = g_quark_from_string (accel_path);
1691 }
1692
1693 /**
1694  * gtk_action_get_accel_path:
1695  * @action: the action object
1696  *
1697  * Returns the accel path for this action.  
1698  *
1699  * Since: 2.6
1700  *
1701  * Returns: the accel path for this action, or %NULL
1702  *   if none is set. The returned string is owned by GTK+ 
1703  *   and must not be freed or modified.
1704  */
1705 G_CONST_RETURN gchar *
1706 gtk_action_get_accel_path (GtkAction *action)
1707 {
1708   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1709
1710   if (action->private_data->accel_quark)
1711     return g_quark_to_string (action->private_data->accel_quark);
1712   else
1713     return NULL;
1714 }
1715
1716 /**
1717  * gtk_action_get_accel_closure:
1718  * @action: the action object
1719  *
1720  * Returns the accel closure for this action.
1721  *
1722  * Since: 2.8
1723  *
1724  * Returns: the accel closure for this action. The returned closure is
1725  *          owned by GTK+ and must not be unreffed or modified.
1726  */
1727 GClosure *
1728 gtk_action_get_accel_closure (GtkAction *action)
1729 {
1730   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1731
1732   return action->private_data->accel_closure;
1733 }
1734
1735
1736 /**
1737  * gtk_action_set_accel_group:
1738  * @action: the action object
1739  * @accel_group: a #GtkAccelGroup or %NULL
1740  * 
1741  * Sets the #GtkAccelGroup in which the accelerator for this action
1742  * will be installed.
1743  *
1744  * Since: 2.4
1745  **/
1746 void
1747 gtk_action_set_accel_group (GtkAction     *action,
1748                             GtkAccelGroup *accel_group)
1749 {
1750   g_return_if_fail (GTK_IS_ACTION (action));
1751   g_return_if_fail (accel_group == NULL || GTK_IS_ACCEL_GROUP (accel_group));
1752   
1753   if (accel_group)
1754     g_object_ref (accel_group);
1755   if (action->private_data->accel_group)
1756     g_object_unref (action->private_data->accel_group);
1757
1758   action->private_data->accel_group = accel_group;
1759 }
1760
1761 /**
1762  * gtk_action_connect_accelerator:
1763  * @action: a #GtkAction
1764  * 
1765  * Installs the accelerator for @action if @action has an
1766  * accel path and group. See gtk_action_set_accel_path() and 
1767  * gtk_action_set_accel_group()
1768  *
1769  * Since multiple proxies may independently trigger the installation
1770  * of the accelerator, the @action counts the number of times this
1771  * function has been called and doesn't remove the accelerator until
1772  * gtk_action_disconnect_accelerator() has been called as many times.
1773  *
1774  * Since: 2.4
1775  **/
1776 void 
1777 gtk_action_connect_accelerator (GtkAction *action)
1778 {
1779   g_return_if_fail (GTK_IS_ACTION (action));
1780
1781   if (!action->private_data->accel_quark ||
1782       !action->private_data->accel_group)
1783     return;
1784
1785   if (action->private_data->accel_count == 0)
1786     {
1787       const gchar *accel_path = 
1788         g_quark_to_string (action->private_data->accel_quark);
1789       
1790       gtk_accel_group_connect_by_path (action->private_data->accel_group,
1791                                        accel_path,
1792                                        action->private_data->accel_closure);
1793     }
1794
1795   action->private_data->accel_count++;
1796 }
1797
1798 /**
1799  * gtk_action_disconnect_accelerator:
1800  * @action: a #GtkAction
1801  * 
1802  * Undoes the effect of one call to gtk_action_connect_accelerator().
1803  *
1804  * Since: 2.4
1805  **/
1806 void 
1807 gtk_action_disconnect_accelerator (GtkAction *action)
1808 {
1809   g_return_if_fail (GTK_IS_ACTION (action));
1810
1811   if (!action->private_data->accel_quark ||
1812       !action->private_data->accel_group)
1813     return;
1814
1815   action->private_data->accel_count--;
1816
1817   if (action->private_data->accel_count == 0)
1818     gtk_accel_group_disconnect (action->private_data->accel_group,
1819                                 action->private_data->accel_closure);
1820 }
1821
1822 /**
1823  * gtk_action_create_menu:
1824  * @action: a #GtkAction
1825  *
1826  * If @action provides a #GtkMenu widget as a submenu for the menu
1827  * item or the toolbar item it creates, this function returns an
1828  * instance of that menu.
1829  *
1830  * Return value: the menu item provided by the action, or %NULL.
1831  *
1832  * Since: 2.12
1833  */
1834 GtkWidget *
1835 gtk_action_create_menu (GtkAction *action)
1836 {
1837   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1838
1839   if (GTK_ACTION_GET_CLASS (action)->create_menu)
1840     return GTK_ACTION_GET_CLASS (action)->create_menu (action);
1841
1842   return NULL;
1843 }
1844
1845 #define __GTK_ACTION_C__
1846 #include "gtkaliasdef.c"