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