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