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