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