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