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