]> Pileus Git - ~andy/gtk/blob - gtk/gtkaction.c
089b2a27ed29d388d3b0345dee2edfdebbf33df3
[~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 "gtkimage.h"
38 #include "gtkimagemenuitem.h"
39 #include "gtkintl.h"
40 #include "gtklabel.h"
41 #include "gtkmarshalers.h"
42 #include "gtkmenuitem.h"
43 #include "gtkstock.h"
44 #include "gtktearoffmenuitem.h"
45 #include "gtktoolbutton.h"
46 #include "gtktoolbar.h"
47
48
49 #define GTK_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ACTION, GtkActionPrivate))
50
51 struct _GtkActionPrivate 
52 {
53   gchar *name;
54   gchar *label;
55   gchar *short_label;
56   gchar *tooltip;
57   gchar *stock_id; /* icon */
58
59   guint sensitive       : 1;
60   guint visible         : 1;
61   guint label_set       : 1; /* these two used so we can set label */
62   guint short_label_set : 1; /* based on stock id */
63   guint visible_horizontal : 1;
64   guint visible_vertical   : 1;
65   guint is_important    : 1;
66   guint hide_if_empty   : 1;
67
68   /* accelerator */
69   guint          accel_count;
70   GtkAccelGroup *accel_group;
71   GClosure      *accel_closure;
72   GQuark         accel_quark;
73
74   GtkActionGroup *action_group;
75
76   /* list of proxy widgets */
77   GSList *proxies;
78 };
79
80 enum 
81 {
82   ACTIVATE,
83   LAST_SIGNAL
84 };
85
86 enum 
87 {
88   PROP_0,
89   PROP_NAME,
90   PROP_LABEL,
91   PROP_SHORT_LABEL,
92   PROP_TOOLTIP,
93   PROP_STOCK_ID,
94   PROP_VISIBLE_HORIZONTAL,
95   PROP_VISIBLE_VERTICAL,
96   PROP_IS_IMPORTANT,
97   PROP_HIDE_IF_EMPTY,
98   PROP_SENSITIVE,
99   PROP_VISIBLE,
100   PROP_ACTION_GROUP
101 };
102
103 static void gtk_action_init       (GtkAction *action);
104 static void gtk_action_class_init (GtkActionClass *class);
105
106 static GQuark       accel_path_id  = 0;
107 static const gchar *accel_path_key = "GtkAction::accel_path";
108
109 GType
110 gtk_action_get_type (void)
111 {
112   static GtkType type = 0;
113
114   if (!type)
115     {
116       static const GTypeInfo type_info =
117       {
118         sizeof (GtkActionClass),
119         (GBaseInitFunc) NULL,
120         (GBaseFinalizeFunc) NULL,
121         (GClassInitFunc) gtk_action_class_init,
122         (GClassFinalizeFunc) NULL,
123         NULL,
124         
125         sizeof (GtkAction),
126         0, /* n_preallocs */
127         (GInstanceInitFunc) gtk_action_init,
128       };
129
130       type = g_type_register_static (G_TYPE_OBJECT,
131                                      "GtkAction",
132                                      &type_info, 0);
133     }
134   return type;
135 }
136
137 static void gtk_action_finalize     (GObject *object);
138 static void gtk_action_set_property (GObject         *object,
139                                      guint            prop_id,
140                                      const GValue    *value,
141                                      GParamSpec      *pspec);
142 static void gtk_action_get_property (GObject         *object,
143                                      guint            prop_id,
144                                      GValue          *value,
145                                      GParamSpec      *pspec);
146 static void gtk_action_set_action_group (GtkAction          *action,
147                                          GtkActionGroup *action_group);
148
149 static GtkWidget *create_menu_item    (GtkAction *action);
150 static GtkWidget *create_tool_item    (GtkAction *action);
151 static void       connect_proxy       (GtkAction     *action,
152                                        GtkWidget     *proxy);
153 static void       disconnect_proxy    (GtkAction *action,
154                                        GtkWidget *proxy);
155 static void       closure_accel_activate (GClosure     *closure,
156                                           GValue       *return_value,
157                                           guint         n_param_values,
158                                           const GValue *param_values,
159                                           gpointer      invocation_hint,
160                                           gpointer      marshal_data);
161
162 static GObjectClass *parent_class = NULL;
163 static guint         action_signals[LAST_SIGNAL] = { 0 };
164
165
166 static void
167 gtk_action_class_init (GtkActionClass *klass)
168 {
169   GObjectClass *gobject_class;
170
171   accel_path_id = g_quark_from_static_string (accel_path_key);
172
173   parent_class = g_type_class_peek_parent (klass);
174   gobject_class = G_OBJECT_CLASS (klass);
175
176   gobject_class->finalize     = gtk_action_finalize;
177   gobject_class->set_property = gtk_action_set_property;
178   gobject_class->get_property = gtk_action_get_property;
179
180   klass->activate = NULL;
181
182   klass->create_menu_item = create_menu_item;
183   klass->create_tool_item = create_tool_item;
184   klass->connect_proxy = connect_proxy;
185   klass->disconnect_proxy = disconnect_proxy;
186
187   klass->menu_item_type = GTK_TYPE_IMAGE_MENU_ITEM;
188   klass->toolbar_item_type = GTK_TYPE_TOOL_BUTTON;
189
190   g_object_class_install_property (gobject_class,
191                                    PROP_NAME,
192                                    g_param_spec_string ("name",
193                                                         P_("Name"),
194                                                         P_("A unique name for the action."),
195                                                         NULL,
196                                                         G_PARAM_READWRITE |
197                                                         G_PARAM_CONSTRUCT_ONLY));
198   g_object_class_install_property (gobject_class,
199                                    PROP_LABEL,
200                                    g_param_spec_string ("label",
201                                                         P_("Label"),
202                                                         P_("The label used for menu items and buttons that activate this action."),
203                                                         NULL,
204                                                         G_PARAM_READWRITE));
205   g_object_class_install_property (gobject_class,
206                                    PROP_SHORT_LABEL,
207                                    g_param_spec_string ("short_label",
208                                                         P_("Short label"),
209                                                         P_("A shorter label that may be used on toolbar buttons."),
210                                                         NULL,
211                                                         G_PARAM_READWRITE));
212   g_object_class_install_property (gobject_class,
213                                    PROP_TOOLTIP,
214                                    g_param_spec_string ("tooltip",
215                                                         P_("Tooltip"),
216                                                         P_("A tooltip for this action."),
217                                                         NULL,
218                                                         G_PARAM_READWRITE));
219   g_object_class_install_property (gobject_class,
220                                    PROP_STOCK_ID,
221                                    g_param_spec_string ("stock_id",
222                                                         P_("Stock Icon"),
223                                                         P_("The stock icon displayed in widgets representing this action."),
224                                                         NULL,
225                                                         G_PARAM_READWRITE));
226   g_object_class_install_property (gobject_class,
227                                    PROP_VISIBLE_HORIZONTAL,
228                                    g_param_spec_boolean ("visible_horizontal",
229                                                          P_("Visible when horizontal"),
230                                                          P_("Whether the toolbar item is visible when the toolbar is in a horizontal orientation."),
231                                                          TRUE,
232                                                          G_PARAM_READWRITE));
233   g_object_class_install_property (gobject_class,
234                                    PROP_VISIBLE_VERTICAL,
235                                    g_param_spec_boolean ("visible_vertical",
236                                                          P_("Visible when vertical"),
237                                                          P_("Whether the toolbar item is visible when the toolbar is in a vertical orientation."),
238                                                          TRUE,
239                                                          G_PARAM_READWRITE));
240   g_object_class_install_property (gobject_class,
241                                    PROP_IS_IMPORTANT,
242                                    g_param_spec_boolean ("is_important",
243                                                          P_("Is important"),
244                                                          P_("Whether the action is considered important. When TRUE, toolitem proxies for this action show text in GTK_TOOLBAR_BOTH_HORIZ mode."),
245                                                          FALSE,
246                                                          G_PARAM_READWRITE));
247   g_object_class_install_property (gobject_class,
248                                    PROP_HIDE_IF_EMPTY,
249                                    g_param_spec_boolean ("hide_if_empty",
250                                                          P_("Hide if empty"),
251                                                          P_("When TRUE, empty menu proxies for this action are hidden."),
252                                                          TRUE,
253                                                          G_PARAM_READWRITE));
254   g_object_class_install_property (gobject_class,
255                                    PROP_SENSITIVE,
256                                    g_param_spec_boolean ("sensitive",
257                                                          P_("Sensitive"),
258                                                          P_("Whether the action is enabled."),
259                                                          TRUE,
260                                                          G_PARAM_READWRITE));
261   g_object_class_install_property (gobject_class,
262                                    PROP_VISIBLE,
263                                    g_param_spec_boolean ("visible",
264                                                          P_("Visible"),
265                                                          P_("Whether the action is visible."),
266                                                          TRUE,
267                                                          G_PARAM_READWRITE));
268   g_object_class_install_property (gobject_class,
269                                    PROP_ACTION_GROUP,
270                                    g_param_spec_object ("action_group",
271                                                          P_("Action Group"),
272                                                          P_("The GtkActionGroup this GtkAction is associated with, or NULL (for internal use)."),
273                                                          GTK_TYPE_ACTION_GROUP,
274                                                          G_PARAM_READWRITE));
275
276   /**
277    * GtkAction::activate:
278    * @action: the #GtkAction
279    *
280    * The "activate" signal is emitted when the action is activated.
281    *
282    * Since: 2.4
283    */
284   action_signals[ACTIVATE] =
285     g_signal_new ("activate",
286                   G_OBJECT_CLASS_TYPE (klass),
287                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
288                   G_STRUCT_OFFSET (GtkActionClass, activate),  NULL, NULL,
289                   g_cclosure_marshal_VOID__VOID,
290                   G_TYPE_NONE, 0);
291
292   g_type_class_add_private (gobject_class, sizeof (GtkActionPrivate));
293 }
294
295
296 static void
297 gtk_action_init (GtkAction *action)
298 {
299   action->private_data = GTK_ACTION_GET_PRIVATE (action);
300
301   action->private_data->name = NULL;
302   action->private_data->label = NULL;
303   action->private_data->short_label = NULL;
304   action->private_data->tooltip = NULL;
305   action->private_data->stock_id = NULL;
306   action->private_data->visible_horizontal = TRUE;
307   action->private_data->visible_vertical   = TRUE;
308   action->private_data->is_important = FALSE;
309   action->private_data->hide_if_empty = TRUE;
310
311   action->private_data->sensitive = TRUE;
312   action->private_data->visible = TRUE;
313
314   action->private_data->label_set = FALSE;
315   action->private_data->short_label_set = FALSE;
316
317   action->private_data->accel_count = 0;
318   action->private_data->accel_closure = 
319     g_closure_new_object (sizeof (GClosure), G_OBJECT (action));
320   g_closure_set_marshal (action->private_data->accel_closure, 
321                          closure_accel_activate);
322   g_closure_ref (action->private_data->accel_closure);
323   g_closure_sink (action->private_data->accel_closure);
324
325   action->private_data->accel_quark = 0;
326   action->private_data->accel_count = 0;
327   action->private_data->accel_group = NULL;
328
329   action->private_data->action_group = NULL;
330
331   action->private_data->proxies = NULL;
332 }
333
334 /**
335  * gtk_action_new:
336  * @name: A unique name for the action
337  * @label: the label displayed in menu items and on buttons
338  * @tooltip: a tooltip for the action
339  * @stock_id: the stock icon to display in widgets representing the action
340  *
341  * Creates a new #GtkAction object. To add the action to a
342  * #GtkActionGroup and set the accelerator for the action,
343  * call gtk_action_group_add_action_with_accel().
344  *
345  * Return value: a new #GtkAction
346  *
347  * Since: 2.4
348  */
349 GtkAction *
350 gtk_action_new (const gchar *name,
351                 const gchar *label,
352                 const gchar *tooltip,
353                 const gchar *stock_id)
354 {
355   GtkAction *action;
356
357   action = g_object_new (GTK_TYPE_ACTION,
358                          "name", name,
359                          "label", label,
360                          "tooltip", tooltip,
361                          "stock_id", stock_id,
362                          NULL);
363
364   return action;
365 }
366
367 static void
368 gtk_action_finalize (GObject *object)
369 {
370   GtkAction *action;
371   action = GTK_ACTION (object);
372
373   g_free (action->private_data->name);
374   g_free (action->private_data->label);
375   g_free (action->private_data->short_label);
376   g_free (action->private_data->tooltip);
377   g_free (action->private_data->stock_id);
378
379   g_closure_unref (action->private_data->accel_closure);
380   if (action->private_data->accel_group)
381     g_object_unref (action->private_data->accel_group);
382
383   G_OBJECT_CLASS (parent_class)->finalize (object);  
384 }
385
386 static void
387 gtk_action_set_property (GObject         *object,
388                          guint            prop_id,
389                          const GValue    *value,
390                          GParamSpec      *pspec)
391 {
392   GtkAction *action;
393   gchar *tmp;
394   
395   action = GTK_ACTION (object);
396
397   switch (prop_id)
398     {
399     case PROP_NAME:
400       tmp = action->private_data->name;
401       action->private_data->name = g_value_dup_string (value);
402       g_free (tmp);
403       break;
404     case PROP_LABEL:
405       tmp = action->private_data->label;
406       action->private_data->label = g_value_dup_string (value);
407       g_free (tmp);
408       action->private_data->label_set = (action->private_data->label != NULL);
409       /* if label is unset, then use the label from the stock item */
410       if (!action->private_data->label_set && action->private_data->stock_id)
411         {
412           GtkStockItem stock_item;
413
414           if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
415             action->private_data->label = g_strdup (stock_item.label);
416         }
417       /* if short_label is unset, set short_label=label */
418       if (!action->private_data->short_label_set)
419         {
420           tmp = action->private_data->short_label;
421           action->private_data->short_label = g_strdup (action->private_data->label);
422           g_free (tmp);
423           g_object_notify (object, "short_label");
424         }
425       break;
426     case PROP_SHORT_LABEL:
427       tmp = action->private_data->short_label;
428       action->private_data->short_label = g_value_dup_string (value);
429       g_free (tmp);
430       action->private_data->short_label_set = (action->private_data->short_label != NULL);
431       /* if short_label is unset, then use the value of label */
432       if (!action->private_data->short_label_set)
433         {
434           action->private_data->short_label = g_strdup (action->private_data->label);
435         }
436       break;
437     case PROP_TOOLTIP:
438       tmp = action->private_data->tooltip;
439       action->private_data->tooltip = g_value_dup_string (value);
440       g_free (tmp);
441       break;
442     case PROP_STOCK_ID:
443       tmp = action->private_data->stock_id;
444       action->private_data->stock_id = g_value_dup_string (value);
445       g_free (tmp);
446       /* update label and short_label if appropriate */
447       if (!action->private_data->label_set)
448         {
449           GtkStockItem stock_item;
450
451           g_free (action->private_data->label);
452           if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
453             action->private_data->label = g_strdup (stock_item.label);
454           else
455             action->private_data->label = NULL;
456           g_object_notify (object, "label");
457         }
458       if (!action->private_data->short_label_set)
459         {
460           tmp = action->private_data->short_label;
461           action->private_data->short_label = g_strdup (action->private_data->label);
462           g_free (tmp);
463           g_object_notify (object, "short_label");
464         }
465       break;
466     case PROP_VISIBLE_HORIZONTAL:
467       action->private_data->visible_horizontal = g_value_get_boolean (value);
468       break;
469     case PROP_VISIBLE_VERTICAL:
470       action->private_data->visible_vertical = g_value_get_boolean (value);
471       break;
472     case PROP_IS_IMPORTANT:
473       action->private_data->is_important = g_value_get_boolean (value);
474       break;
475     case PROP_HIDE_IF_EMPTY:
476       action->private_data->hide_if_empty = g_value_get_boolean (value);
477       break;
478     case PROP_SENSITIVE:
479       action->private_data->sensitive = g_value_get_boolean (value);
480       break;
481     case PROP_VISIBLE:
482       action->private_data->visible = g_value_get_boolean (value);
483       break;
484     case PROP_ACTION_GROUP:
485       gtk_action_set_action_group (action, g_value_get_object (value));
486       break;
487     default:
488       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
489       break;
490     }
491 }
492
493 static void
494 gtk_action_get_property (GObject    *object,
495                          guint       prop_id,
496                          GValue     *value,
497                          GParamSpec *pspec)
498 {
499   GtkAction *action;
500
501   action = GTK_ACTION (object);
502
503   switch (prop_id)
504     {
505     case PROP_NAME:
506       g_value_set_string (value, action->private_data->name);
507       break;
508     case PROP_LABEL:
509       g_value_set_string (value, action->private_data->label);
510       break;
511     case PROP_SHORT_LABEL:
512       g_value_set_string (value, action->private_data->short_label);
513       break;
514     case PROP_TOOLTIP:
515       g_value_set_string (value, action->private_data->tooltip);
516       break;
517     case PROP_STOCK_ID:
518       g_value_set_string (value, action->private_data->stock_id);
519       break;
520     case PROP_VISIBLE_HORIZONTAL:
521       g_value_set_boolean (value, action->private_data->visible_horizontal);
522       break;
523     case PROP_VISIBLE_VERTICAL:
524       g_value_set_boolean (value, action->private_data->visible_vertical);
525       break;
526     case PROP_IS_IMPORTANT:
527       g_value_set_boolean (value, action->private_data->is_important);
528       break;
529     case PROP_HIDE_IF_EMPTY:
530       g_value_set_boolean (value, action->private_data->hide_if_empty);
531       break;
532     case PROP_SENSITIVE:
533       g_value_set_boolean (value, action->private_data->sensitive);
534       break;
535     case PROP_VISIBLE:
536       g_value_set_boolean (value, action->private_data->visible);
537       break;
538     case PROP_ACTION_GROUP:
539       g_value_set_object (value, action->private_data->action_group);
540       break;
541     default:
542       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
543       break;
544     }
545 }
546
547 static GtkWidget *
548 create_menu_item (GtkAction *action)
549 {
550   GType menu_item_type;
551
552   menu_item_type = GTK_ACTION_GET_CLASS (action)->menu_item_type;
553
554   return g_object_new (menu_item_type, NULL);
555 }
556
557 static GtkWidget *
558 create_tool_item (GtkAction *action)
559 {
560   GType toolbar_item_type;
561
562   toolbar_item_type = GTK_ACTION_GET_CLASS (action)->toolbar_item_type;
563
564   return g_object_new (toolbar_item_type, NULL);
565 }
566
567 static void
568 remove_proxy (GtkWidget *proxy, 
569               GtkAction *action)
570 {
571   if (GTK_IS_MENU_ITEM (proxy))
572     gtk_action_disconnect_accelerator (action);
573
574   action->private_data->proxies = g_slist_remove (action->private_data->proxies, proxy);
575 }
576
577 static void
578 gtk_action_sync_sensitivity (GtkAction  *action, 
579                              GParamSpec *pspec,
580                              GtkWidget  *proxy)
581 {
582   gtk_widget_set_sensitive (proxy, gtk_action_is_sensitive (action));
583 }
584
585 static void
586 gtk_action_sync_property (GtkAction  *action, 
587                           GParamSpec *pspec,
588                           GtkWidget  *proxy)
589 {
590   const gchar *property;
591   GValue value = { 0, };
592
593   property = g_param_spec_get_name (pspec);
594
595   g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
596   g_object_get_property (G_OBJECT (action), property, &value);
597
598   g_object_set_property (G_OBJECT (proxy), property, &value);
599   g_value_unset (&value);
600 }
601
602 /**
603  * _gtk_action_sync_menu_visible:
604  * @action: a #GtkAction, or %NULL to determine the action from @proxy
605  * @proxy: a proxy menu item
606  * @empty: whether the submenu attached to @proxy is empty
607  * 
608  * Updates the visibility of @proxy from the visibility of @action
609  * according to the following rules:
610  * <itemizedlist>
611  * <listitem><para>if @action is invisible, @proxy is too
612  * </para></listitem>
613  * <listitem><para>if @empty is %TRUE, hide @proxy unless the "hide-if-empty" 
614  *   property of @action indicates otherwise
615  * </para></listitem>
616  * </itemizedlist>
617  * 
618  * This function is used in the implementation of #GtkUIManager.
619  **/
620 void
621 _gtk_action_sync_menu_visible (GtkAction *action,
622                                GtkWidget *proxy,
623                                gboolean   empty)
624 {
625   gboolean visible, hide_if_empty;
626
627   g_return_if_fail (GTK_IS_MENU_ITEM (proxy));
628   g_return_if_fail (action == NULL || GTK_IS_ACTION (action));
629   
630   if (action == NULL)
631     action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
632
633   visible = gtk_action_is_visible (action);
634   hide_if_empty = action->private_data->hide_if_empty;
635
636   g_object_set (G_OBJECT (proxy),
637                 "visible", visible && !(empty && hide_if_empty),
638                 NULL);
639 }
640
641 gboolean _gtk_menu_is_empty (GtkWidget *menu);
642
643 static void
644 gtk_action_sync_visible (GtkAction  *action, 
645                          GParamSpec *pspec,
646                          GtkWidget  *proxy)
647 {
648   if (GTK_IS_MENU_ITEM (proxy))
649     {
650       GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy));
651
652       _gtk_action_sync_menu_visible (action, proxy, _gtk_menu_is_empty (menu));
653     }
654   else
655     {
656       if (gtk_action_is_visible (action))
657         gtk_widget_show (proxy);
658       else
659         gtk_widget_hide (proxy);
660     }
661 }
662
663 static void
664 gtk_action_sync_label (GtkAction  *action, 
665                        GParamSpec *pspec, 
666                        GtkWidget  *proxy)
667 {
668   GtkWidget *label = NULL;
669
670   g_return_if_fail (GTK_IS_MENU_ITEM (proxy));
671   label = GTK_BIN (proxy)->child;
672
673   if (GTK_IS_LABEL (label))
674     gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
675 }
676
677 static void
678 gtk_action_sync_short_label (GtkAction  *action, 
679                              GParamSpec *pspec,
680                              GtkWidget  *proxy)
681 {
682   GValue value = { 0, };
683
684   g_value_init (&value, G_TYPE_STRING);
685   g_object_get_property (G_OBJECT (action), "short_label", &value);
686
687   g_object_set_property (G_OBJECT (proxy), "label", &value);
688   g_value_unset (&value);
689 }
690
691 static void
692 gtk_action_sync_stock_id (GtkAction  *action, 
693                           GParamSpec *pspec,
694                           GtkWidget  *proxy)
695 {
696   GtkWidget *image = NULL;
697
698   if (GTK_IS_IMAGE_MENU_ITEM (proxy))
699     {
700       image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
701
702       if (GTK_IS_IMAGE (image))
703         gtk_image_set_from_stock (GTK_IMAGE (image),
704                                   action->private_data->stock_id, GTK_ICON_SIZE_MENU);
705     }
706 }
707
708 static void
709 gtk_action_sync_tooltip (GtkAction  *action, 
710                          GParamSpec *pspec, 
711                          GtkWidget  *proxy)
712 {
713   g_return_if_fail (GTK_IS_TOOL_ITEM (proxy));
714
715   if (GTK_IS_TOOLBAR (gtk_widget_get_parent (proxy)))
716     {
717       GtkToolbar *toolbar = GTK_TOOLBAR (gtk_widget_get_parent (proxy));
718       
719       gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (proxy), 
720                                  toolbar->tooltips,
721                                  action->private_data->tooltip,
722                                  NULL);
723     }
724 }
725
726
727 static gboolean
728 gtk_action_create_menu_proxy (GtkToolItem *tool_item, 
729                               GtkAction   *action)
730 {
731   GtkWidget *menu_item = gtk_action_create_menu_item (action);
732
733   g_object_ref (menu_item);
734   gtk_object_sink (GTK_OBJECT (menu_item));
735   
736   gtk_tool_item_set_proxy_menu_item (tool_item, "gtk-action-menu-item", menu_item);
737   g_object_unref (menu_item);
738
739   return TRUE;
740 }
741
742 static void
743 connect_proxy (GtkAction     *action, 
744                GtkWidget     *proxy)
745 {
746   GtkActionGroup *group = action->private_data->action_group;
747
748   g_object_ref (action);
749   g_object_set_data_full (G_OBJECT (proxy), "gtk-action", action,
750                           g_object_unref);
751
752   /* add this widget to the list of proxies */
753   action->private_data->proxies = g_slist_prepend (action->private_data->proxies, proxy);
754   g_signal_connect (proxy, "destroy",
755                     G_CALLBACK (remove_proxy), action);
756
757   g_signal_connect_object (action, "notify::sensitive",
758                            G_CALLBACK (gtk_action_sync_sensitivity), proxy, 0);
759   gtk_widget_set_sensitive (proxy, gtk_action_is_sensitive (action));
760
761   g_signal_connect_object (action, "notify::visible",
762                            G_CALLBACK (gtk_action_sync_visible), proxy, 0);
763   if (gtk_action_is_visible (action))
764     gtk_widget_show (proxy);
765   else
766     gtk_widget_hide (proxy);
767   gtk_widget_set_no_show_all (proxy, TRUE);
768
769   if (GTK_IS_MENU_ITEM (proxy))
770     {
771       GtkWidget *label;
772       /* menu item specific synchronisers ... */
773       
774       if (action->private_data->accel_quark)
775         {
776           gtk_action_connect_accelerator (action);
777           gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy),
778                                         g_quark_to_string (action->private_data->accel_quark));
779         }
780       
781       label = GTK_BIN (proxy)->child;
782
783       /* make sure label is a label */
784       if (label && !GTK_IS_LABEL (label))
785         {
786           gtk_container_remove (GTK_CONTAINER (proxy), label);
787           label = NULL;
788         }
789
790       if (!label)
791         label = g_object_new (GTK_TYPE_ACCEL_LABEL,
792                               "use_underline", TRUE,
793                               "xalign", 0.0,
794                               "visible", TRUE,
795                               "parent", proxy,
796                               NULL);
797       
798       if (GTK_IS_ACCEL_LABEL (label) && action->private_data->accel_quark)
799         g_object_set (G_OBJECT (label),
800                       "accel_closure", action->private_data->accel_closure,
801                       NULL);
802
803       gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
804       g_signal_connect_object (action, "notify::label",
805                                G_CALLBACK (gtk_action_sync_label), proxy, 0);
806
807       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
808         {
809           GtkWidget *image;
810
811           image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
812           if (image && !GTK_IS_IMAGE (image))
813             {
814               gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), NULL);
815               image = NULL;
816             }
817           if (!image)
818             {
819               image = gtk_image_new_from_stock (NULL,
820                                                 GTK_ICON_SIZE_MENU);
821               gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy),
822                                              image);
823               gtk_widget_show (image);
824             }
825           gtk_image_set_from_stock (GTK_IMAGE (image),
826                                     action->private_data->stock_id, GTK_ICON_SIZE_MENU);
827           g_signal_connect_object (action, "notify::stock_id",
828                                    G_CALLBACK (gtk_action_sync_stock_id),
829                                    proxy, 0);
830         }
831
832       if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)) == NULL)
833       g_signal_connect_object (proxy, "activate",
834                                G_CALLBACK (gtk_action_activate), action,
835                                G_CONNECT_SWAPPED);
836
837     }
838   else if (GTK_IS_TOOL_ITEM (proxy))
839     {
840       /* toolbar item specific synchronisers ... */
841
842       g_object_set (G_OBJECT (proxy),
843                     "visible_horizontal", action->private_data->visible_horizontal,
844                     "visible_vertical",   action->private_data->visible_vertical,
845                     "is_important", action->private_data->is_important,
846                     NULL);
847       /* FIXME: we should set the tooltip here, but the current api
848        * doesn't allow it before the item is added to a toolbar. 
849        */
850       g_signal_connect_object (action, "notify::visible_horizontal",
851                                G_CALLBACK (gtk_action_sync_property), 
852                                proxy, 0);
853       g_signal_connect_object (action, "notify::visible_vertical",
854                                G_CALLBACK (gtk_action_sync_property), 
855                                proxy, 0);
856       g_signal_connect_object (action, "notify::is_important",
857                                G_CALLBACK (gtk_action_sync_property), 
858                                proxy, 0);
859       g_signal_connect_object (action, "notify::tooltip",
860                                G_CALLBACK (gtk_action_sync_tooltip), 
861                                proxy, 0);
862
863       g_signal_connect_object (proxy, "create_menu_proxy",
864                                G_CALLBACK (gtk_action_create_menu_proxy),
865                                action, 0);
866
867       /* toolbar button specific synchronisers ... */
868       if (GTK_IS_TOOL_BUTTON (proxy))
869         {
870           g_object_set (G_OBJECT (proxy),
871                         "label", action->private_data->short_label,
872                         "use_underline", TRUE,
873                         "stock_id", action->private_data->stock_id,
874                         NULL);
875           /* FIXME: we should set the tooltip here, but the current api
876            * doesn't allow it before the item is added to a toolbar. 
877            */
878           g_signal_connect_object (action, "notify::short_label",
879                                    G_CALLBACK (gtk_action_sync_short_label),
880                                    proxy, 0);      
881           g_signal_connect_object (action, "notify::stock_id",
882                                    G_CALLBACK (gtk_action_sync_property), 
883                                    proxy, 0);
884       g_signal_connect_object (proxy, "clicked",
885                                G_CALLBACK (gtk_action_activate), action,
886                                G_CONNECT_SWAPPED);
887     }
888     }
889   else if (GTK_IS_BUTTON (proxy))
890     {
891       /* button specific synchronisers ... */
892
893       /* synchronise the label */
894       g_object_set (G_OBJECT (proxy),
895                     "label", action->private_data->short_label,
896                     "use_underline", TRUE,
897                     NULL);
898       g_signal_connect_object (action, "notify::short_label",
899                                G_CALLBACK (gtk_action_sync_short_label),
900                                proxy, 0);
901       
902       g_signal_connect_object (proxy, "clicked",
903                                G_CALLBACK (gtk_action_activate), action,
904                                G_CONNECT_SWAPPED);
905     }
906
907   _gtk_action_group_emit_connect_proxy (group, action, proxy);
908 }
909
910 static void
911 disconnect_proxy (GtkAction *action, 
912                   GtkWidget *proxy)
913 {
914   GtkActionGroup *group = action->private_data->action_group;
915
916   g_object_set_data (G_OBJECT (proxy), "gtk-action", NULL);
917
918   /* remove proxy from list of proxies */
919   g_signal_handlers_disconnect_by_func (proxy,
920                                         G_CALLBACK (remove_proxy),
921                                         action);
922   remove_proxy (proxy, action);
923
924   /* disconnect the activate handler */
925   g_signal_handlers_disconnect_by_func (proxy,
926                                         G_CALLBACK (gtk_action_activate),
927                                         action);
928
929   /* disconnect handlers for notify::* signals */
930   g_signal_handlers_disconnect_by_func (proxy,
931                                         G_CALLBACK (gtk_action_sync_sensitivity),
932                                         action);
933   g_signal_handlers_disconnect_by_func (proxy,
934                                         G_CALLBACK (gtk_action_sync_property),
935                                         action);
936
937   g_signal_handlers_disconnect_by_func (action,
938                                 G_CALLBACK (gtk_action_sync_stock_id), proxy);
939
940   /* menu item specific synchronisers ... */
941   g_signal_handlers_disconnect_by_func (action,
942                                         G_CALLBACK (gtk_action_sync_label),
943                                         proxy);
944   
945   /* toolbar button specific synchronisers ... */
946   g_signal_handlers_disconnect_by_func (action,
947                                         G_CALLBACK (gtk_action_sync_short_label),
948                                         proxy);
949
950   g_signal_handlers_disconnect_by_func (proxy,
951                                         G_CALLBACK (gtk_action_create_menu_proxy),
952                                         action);
953
954   _gtk_action_group_emit_disconnect_proxy (group, action, proxy);
955 }
956
957 void
958 _gtk_action_emit_activate (GtkAction *action)
959 {
960   GtkActionGroup *group = action->private_data->action_group;
961
962   if (group != NULL) 
963     {
964       g_object_ref (group);
965       _gtk_action_group_emit_pre_activate (group, action);
966     }
967
968     g_signal_emit (action, action_signals[ACTIVATE], 0);
969
970   if (group != NULL) 
971     {
972       _gtk_action_group_emit_post_activate (group, action);
973       g_object_unref (group);
974     }
975 }
976
977 /**
978  * gtk_action_activate:
979  * @action: the action object
980  *
981  * Emits the "activate" signal on the specified action, if it isn't 
982  * insensitive. This gets called by the proxy widgets when they get 
983  * activated.
984  *
985  * It can also be used to manually activate an action.
986  *
987  * Since: 2.4
988  */
989 void
990 gtk_action_activate (GtkAction *action)
991 {
992   g_return_if_fail (GTK_IS_ACTION (action));
993   
994   if (gtk_action_is_sensitive (action))
995     _gtk_action_emit_activate (action);
996 }
997
998 /**
999  * gtk_action_create_icon:
1000  * @action: the action object
1001  * @icon_size: the size of the icon that should be created.
1002  *
1003  * This function is intended for use by action implementations to
1004  * create icons displayed in the proxy widgets.
1005  *
1006  * Returns: a widget that displays the icon for this action.
1007  *
1008  * Since: 2.4
1009  */
1010 GtkWidget *
1011 gtk_action_create_icon (GtkAction *action, GtkIconSize icon_size)
1012 {
1013   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1014
1015   if (action->private_data->stock_id)
1016     return gtk_image_new_from_stock (action->private_data->stock_id, icon_size);
1017   else
1018     return NULL;
1019 }
1020
1021 /**
1022  * gtk_action_create_menu_item:
1023  * @action: the action object
1024  *
1025  * Creates a menu item widget that proxies for the given action.
1026  *
1027  * Returns: a menu item connected to the action.
1028  *
1029  * Since: 2.4
1030  */
1031 GtkWidget *
1032 gtk_action_create_menu_item (GtkAction *action)
1033 {
1034   GtkWidget *menu_item;
1035
1036   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1037
1038   menu_item = (* GTK_ACTION_GET_CLASS (action)->create_menu_item) (action);
1039
1040   (* GTK_ACTION_GET_CLASS (action)->connect_proxy) (action, menu_item);
1041
1042   return menu_item;
1043 }
1044
1045 /**
1046  * gtk_action_create_tool_item:
1047  * @action: the action object
1048  *
1049  * Creates a toolbar item widget that proxies for the given action.
1050  *
1051  * Returns: a toolbar item connected to the action.
1052  *
1053  * Since: 2.4
1054  */
1055 GtkWidget *
1056 gtk_action_create_tool_item (GtkAction *action)
1057 {
1058   GtkWidget *button;
1059
1060   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1061
1062   button = (* GTK_ACTION_GET_CLASS (action)->create_tool_item) (action);
1063
1064   (* GTK_ACTION_GET_CLASS (action)->connect_proxy) (action, button);
1065
1066   return button;
1067 }
1068
1069 /**
1070  * gtk_action_connect_proxy:
1071  * @action: the action object
1072  * @proxy: the proxy widget
1073  *
1074  * Connects a widget to an action object as a proxy.  Synchronises 
1075  * various properties of the action with the widget (such as label 
1076  * text, icon, tooltip, etc), and attaches a callback so that the 
1077  * action gets activated when the proxy widget does.
1078  *
1079  * If the widget is already connected to an action, it is disconnected
1080  * first.
1081  *
1082  * Since: 2.4
1083  */
1084 void
1085 gtk_action_connect_proxy (GtkAction *action,
1086                           GtkWidget *proxy)
1087 {
1088   GtkAction *prev_action;
1089
1090   g_return_if_fail (GTK_IS_ACTION (action));
1091   g_return_if_fail (GTK_IS_WIDGET (proxy));
1092
1093   prev_action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
1094
1095   if (prev_action)
1096     (* GTK_ACTION_GET_CLASS (action)->disconnect_proxy) (prev_action, proxy);  
1097
1098   (* GTK_ACTION_GET_CLASS (action)->connect_proxy) (action, proxy);
1099 }
1100
1101 /**
1102  * gtk_action_disconnect_proxy:
1103  * @action: the action object
1104  * @proxy: the proxy widget
1105  *
1106  * Disconnects a proxy widget from an action.  
1107  * Does <emphasis>not</emphasis> destroy the widget, however.
1108  *
1109  * Since: 2.4
1110  */
1111 void
1112 gtk_action_disconnect_proxy (GtkAction *action,
1113                              GtkWidget *proxy)
1114 {
1115   g_return_if_fail (GTK_IS_ACTION (action));
1116   g_return_if_fail (GTK_IS_WIDGET (proxy));
1117
1118   g_return_if_fail (g_object_get_data (G_OBJECT (proxy), "gtk-action") == action);
1119
1120   (* GTK_ACTION_GET_CLASS (action)->disconnect_proxy) (action, proxy);  
1121 }
1122
1123 /**
1124  * gtk_action_get_proxies:
1125  * @action: the action object
1126  * 
1127  * Returns the proxy widgets for an action.
1128  * 
1129  * Return value: a #GSList of proxy widgets. The list is owned by the action and
1130  * must not be modified.
1131  *
1132  * Since: 2.4
1133  **/
1134 GSList*
1135 gtk_action_get_proxies (GtkAction *action)
1136 {
1137   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1138
1139   return action->private_data->proxies;
1140 }
1141
1142
1143 /**
1144  * gtk_action_get_name:
1145  * @action: the action object
1146  * 
1147  * Returns the name of the action.
1148  * 
1149  * Return value: the name of the action. The string belongs to GTK+ and should not
1150  *   be freed.
1151  *
1152  * Since: 2.4
1153  **/
1154 const gchar *
1155 gtk_action_get_name (GtkAction *action)
1156 {
1157   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
1158
1159   return action->private_data->name;
1160 }
1161
1162 /**
1163  * gtk_action_is_sensitive:
1164  * @action: the action object
1165  * 
1166  * Returns whether the action is effectively sensitive.
1167  *
1168  * Return value: %TRUE if the action and its associated action group 
1169  * are both sensitive.
1170  *
1171  * Since: 2.4
1172  **/
1173 gboolean
1174 gtk_action_is_sensitive (GtkAction *action)
1175 {
1176   GtkActionPrivate *priv;
1177   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1178
1179   priv = action->private_data;
1180   return priv->sensitive &&
1181     (priv->action_group == NULL ||
1182      gtk_action_group_get_sensitive (priv->action_group));
1183 }
1184
1185 /**
1186  * gtk_action_get_sensitive:
1187  * @action: the action object
1188  * 
1189  * Returns whether the action itself is sensitive. Note that this doesn't 
1190  * necessarily mean effective sensitivity. See gtk_action_is_sensitive() 
1191  * for that.
1192  *
1193  * Return value: %TRUE if the action itself is sensitive.
1194  *
1195  * Since: 2.4
1196  **/
1197 gboolean
1198 gtk_action_get_sensitive (GtkAction *action)
1199 {
1200   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1201
1202   return action->private_data->sensitive;
1203 }
1204
1205 /**
1206  * gtk_action_is_visible:
1207  * @action: the action object
1208  * 
1209  * Returns whether the action is effectively visible.
1210  *
1211  * Return value: %TRUE if the action and its associated action group 
1212  * are both visible.
1213  *
1214  * Since: 2.4
1215  **/
1216 gboolean
1217 gtk_action_is_visible (GtkAction *action)
1218 {
1219   GtkActionPrivate *priv;
1220   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1221
1222   priv = action->private_data;
1223   return priv->visible &&
1224     (priv->action_group == NULL ||
1225      gtk_action_group_get_visible (priv->action_group));
1226 }
1227
1228 /**
1229  * gtk_action_get_visible:
1230  * @action: the action object
1231  * 
1232  * Returns whether the action itself is visible. Note that this doesn't 
1233  * necessarily mean effective visibility. See gtk_action_is_sensitive() 
1234  * for that.
1235  *
1236  * Return value: %TRUE if the action itself is visible.
1237  *
1238  * Since: 2.4
1239  **/
1240 gboolean
1241 gtk_action_get_visible (GtkAction *action)
1242 {
1243   g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
1244
1245   return action->private_data->visible;
1246 }
1247
1248 /**
1249  * gtk_action_block_activate_from:
1250  * @action: the action object
1251  * @proxy: a proxy widget
1252  *
1253  * Disables calls to the gtk_action_activate()
1254  * function by signals on the given proxy widget.  This is used to
1255  * break notification loops for things like check or radio actions.
1256  *
1257  * This function is intended for use by action implementations.
1258  * 
1259  * Since: 2.4
1260  */
1261 void
1262 gtk_action_block_activate_from (GtkAction *action, 
1263                                 GtkWidget *proxy)
1264 {
1265   g_return_if_fail (GTK_IS_ACTION (action));
1266   
1267   g_signal_handlers_block_by_func (proxy, G_CALLBACK (gtk_action_activate),
1268                                    action);
1269 }
1270
1271 /**
1272  * gtk_action_unblock_activate_from:
1273  * @action: the action object
1274  * @proxy: a proxy widget
1275  *
1276  * Re-enables calls to the gtk_action_activate()
1277  * function by signals on the given proxy widget.  This undoes the
1278  * blocking done by gtk_action_block_activate_from().
1279  *
1280  * This function is intended for use by action implementations.
1281  * 
1282  * Since: 2.4
1283  */
1284 void
1285 gtk_action_unblock_activate_from (GtkAction *action, 
1286                                   GtkWidget *proxy)
1287 {
1288   g_return_if_fail (GTK_IS_ACTION (action));
1289
1290   g_signal_handlers_unblock_by_func (proxy, G_CALLBACK (gtk_action_activate),
1291                                      action);
1292 }
1293
1294 static void
1295 closure_accel_activate (GClosure     *closure,
1296                         GValue       *return_value,
1297                         guint         n_param_values,
1298                         const GValue *param_values,
1299                         gpointer      invocation_hint,
1300                         gpointer      marshal_data)
1301 {
1302   if (gtk_action_is_sensitive (GTK_ACTION (closure->data)))
1303     g_signal_emit (closure->data, action_signals[ACTIVATE], 0);
1304
1305   /* we handled the accelerator */
1306   g_value_set_boolean (return_value, TRUE);
1307 }
1308
1309 static void
1310 gtk_action_set_action_group (GtkAction      *action,
1311                              GtkActionGroup *action_group)
1312 {
1313   g_return_if_fail (GTK_IS_ACTION (action));
1314
1315   if (action->private_data->action_group == NULL)
1316     g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1317   else
1318     g_return_if_fail (action_group == NULL);
1319
1320   action->private_data->action_group = action_group;
1321 }
1322
1323 /**
1324  * gtk_action_set_accel_path:
1325  * @action: the action object
1326  * @accel_path: the accelerator path
1327  *
1328  * Sets the accel path for this action.  All proxy widgets associated
1329  * with the action will have this accel path, so that their
1330  * accelerators are consistent.
1331  *
1332  * Since: 2.4
1333  */
1334 void
1335 gtk_action_set_accel_path (GtkAction   *action, 
1336                            const gchar *accel_path)
1337 {
1338   g_return_if_fail (GTK_IS_ACTION (action));
1339
1340   action->private_data->accel_quark = g_quark_from_string (accel_path);
1341 }
1342
1343 /**
1344  * gtk_action_set_accel_group:
1345  * @action: the action object
1346  * @accel_group: a #GtkAccelGroup or %NULL
1347  * 
1348  * Sets the #GtkAccelGroup in which the accelerator for this action
1349  * will be installed.
1350  *
1351  * Since: 2.4
1352  **/
1353 void
1354 gtk_action_set_accel_group (GtkAction     *action,
1355                             GtkAccelGroup *accel_group)
1356 {
1357   g_return_if_fail (GTK_IS_ACTION (action));
1358   g_return_if_fail (accel_group == NULL || GTK_IS_ACCEL_GROUP (accel_group));
1359   
1360   if (accel_group)
1361     g_object_ref (accel_group);
1362   if (action->private_data->accel_group)
1363     g_object_unref (action->private_data->accel_group);
1364
1365   action->private_data->accel_group = accel_group;
1366 }
1367
1368 /**
1369  * gtk_action_connect_accelerator:
1370  * @action: a #GtkAction
1371  * 
1372  * Installs the accelerator for @action if @action has an
1373  * accel path and group. See gtk_action_set_accel_path() and 
1374  * gtk_action_set_accel_group()
1375  *
1376  * Since multiple proxies may independently trigger the installation
1377  * of the accelerator, the @action counts the number of times this
1378  * function has been called and doesn't remove the accelerator until
1379  * gtk_action_disconnect_accelerator() has been called as many times.
1380  *
1381  * Since: 2.4
1382  **/
1383 void 
1384 gtk_action_connect_accelerator (GtkAction *action)
1385 {
1386   g_return_if_fail (GTK_IS_ACTION (action));
1387
1388   if (!action->private_data->accel_quark ||
1389       !action->private_data->accel_group)
1390     return;
1391
1392   if (action->private_data->accel_count == 0)
1393     {
1394       const gchar *accel_path = 
1395         g_quark_to_string (action->private_data->accel_quark);
1396       
1397       gtk_accel_group_connect_by_path (action->private_data->accel_group,
1398                                        accel_path,
1399                                        action->private_data->accel_closure);
1400     }
1401
1402   action->private_data->accel_count++;
1403 }
1404
1405 /**
1406  * gtk_action_disconnect_accelerator:
1407  * @action: a #GtkAction
1408  * 
1409  * Undoes the effect of one call to gtk_action_connect_accelerator().
1410  *
1411  * Since: 2.4
1412  **/
1413 void 
1414 gtk_action_disconnect_accelerator (GtkAction *action)
1415 {
1416   g_return_if_fail (GTK_IS_ACTION (action));
1417
1418   if (!action->private_data->accel_quark ||
1419       !action->private_data->accel_group)
1420     return;
1421
1422   action->private_data->accel_count--;
1423
1424   if (action->private_data->accel_count == 0)
1425     gtk_accel_group_disconnect (action->private_data->accel_group,
1426                                 action->private_data->accel_closure);
1427 }