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