]> Pileus Git - ~andy/gtk/blob - gtk/gtkactiongroup.c
Fix up compiler warnings
[~andy/gtk] / gtk / gtkactiongroup.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 "gtkactiongroup.h"
34 #include "gtkiconfactory.h"
35 #include "gtkstock.h"
36 #include "gtktoggleaction.h"
37 #include "gtkradioaction.h"
38 #include "gtkaccelmap.h"
39 #include "gtkmarshalers.h"
40 #include "gtkprivate.h"
41 #include "gtkintl.h"
42 #include "gtkalias.h"
43
44 #define GTK_ACTION_GROUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ACTION_GROUP, GtkActionGroupPrivate))
45
46 struct _GtkActionGroupPrivate 
47 {
48   gchar           *name;
49   gboolean         sensitive;
50   gboolean         visible;
51   GHashTable      *actions;
52
53   GtkTranslateFunc translate_func;
54   gpointer         translate_data;
55   GtkDestroyNotify translate_notify;   
56 };
57
58 enum 
59 {
60   CONNECT_PROXY,
61   DISCONNECT_PROXY,
62   PRE_ACTIVATE,
63   POST_ACTIVATE,
64   LAST_SIGNAL
65 };
66
67 enum 
68 {
69   PROP_0,
70   PROP_NAME,
71   PROP_SENSITIVE,
72   PROP_VISIBLE
73 };
74
75 static void       gtk_action_group_init            (GtkActionGroup      *self);
76 static void       gtk_action_group_class_init      (GtkActionGroupClass *class);
77 static void       gtk_action_group_finalize        (GObject             *object);
78 static void       gtk_action_group_set_property    (GObject             *object,
79                                                     guint                prop_id,
80                                                     const GValue        *value,
81                                                     GParamSpec          *pspec);
82 static void       gtk_action_group_get_property    (GObject             *object,
83                                                     guint                prop_id,
84                                                     GValue              *value,
85                                                     GParamSpec          *pspec);
86 static GtkAction *gtk_action_group_real_get_action (GtkActionGroup      *self,
87                                                     const gchar         *name);
88
89
90 GType
91 gtk_action_group_get_type (void)
92 {
93   static GType type = 0;
94
95   if (!type)
96     {
97       static const GTypeInfo type_info =
98       {
99         sizeof (GtkActionGroupClass),
100         NULL,           /* base_init */
101         NULL,           /* base_finalize */
102         (GClassInitFunc) gtk_action_group_class_init,
103         NULL,           /* class_finalize */
104         NULL,           /* class_data */
105         sizeof (GtkActionGroup),
106         0, /* n_preallocs */
107         (GInstanceInitFunc) gtk_action_group_init,
108       };
109
110       type = g_type_register_static (G_TYPE_OBJECT, I_("GtkActionGroup"),
111                                      &type_info, 0);
112     }
113
114   return type;
115 }
116
117 static GObjectClass *parent_class = NULL;
118 static guint         action_group_signals[LAST_SIGNAL] = { 0 };
119
120 static void
121 gtk_action_group_class_init (GtkActionGroupClass *klass)
122 {
123   GObjectClass *gobject_class;
124
125   gobject_class = G_OBJECT_CLASS (klass);
126   parent_class = g_type_class_peek_parent (klass);
127
128   gobject_class->finalize = gtk_action_group_finalize;
129   gobject_class->set_property = gtk_action_group_set_property;
130   gobject_class->get_property = gtk_action_group_get_property;
131   klass->get_action = gtk_action_group_real_get_action;
132
133   g_object_class_install_property (gobject_class,
134                                    PROP_NAME,
135                                    g_param_spec_string ("name",
136                                                         P_("Name"),
137                                                         P_("A name for the action group."),
138                                                         NULL,
139                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
140   g_object_class_install_property (gobject_class,
141                                    PROP_SENSITIVE,
142                                    g_param_spec_boolean ("sensitive",
143                                                          P_("Sensitive"),
144                                                          P_("Whether the action group is enabled."),
145                                                          TRUE,
146                                                          GTK_PARAM_READWRITE));
147   g_object_class_install_property (gobject_class,
148                                    PROP_VISIBLE,
149                                    g_param_spec_boolean ("visible",
150                                                          P_("Visible"),
151                                                          P_("Whether the action group is visible."),
152                                                          TRUE,
153                                                          GTK_PARAM_READWRITE));
154
155   /**
156    * GtkActionGroup::connect-proxy:
157    * @action_group: the group
158    * @action: the action
159    * @proxy: the proxy
160    *
161    * The connect_proxy signal is emitted after connecting a proxy to 
162    * an action in the group. Note that the proxy may have been connected 
163    * to a different action before.
164    *
165    * This is intended for simple customizations for which a custom action
166    * class would be too clumsy, e.g. showing tooltips for menuitems in the
167    * statusbar.
168    *
169    * #GtkUIManager proxies the signal and provides global notification 
170    * just before any action is connected to a proxy, which is probably more
171    * convenient to use.
172    *
173    * Since: 2.4
174    */
175   action_group_signals[CONNECT_PROXY] =
176     g_signal_new (I_("connect_proxy"),
177                   G_OBJECT_CLASS_TYPE (klass),
178                   0, 0, NULL, NULL,
179                   _gtk_marshal_VOID__OBJECT_OBJECT,
180                   G_TYPE_NONE, 2,
181                   GTK_TYPE_ACTION, GTK_TYPE_WIDGET);
182
183   /**
184    * GtkActionGroup::disconnect-proxy:
185    * @action_group: the group
186    * @action: the action
187    * @proxy: the proxy
188    *
189    * The disconnect_proxy signal is emitted after disconnecting a proxy 
190    * from an action in the group. 
191    *
192    * #GtkUIManager proxies the signal and provides global notification 
193    * just before any action is connected to a proxy, which is probably more
194    * convenient to use.
195    *
196    * Since: 2.4
197    */
198   action_group_signals[DISCONNECT_PROXY] =
199     g_signal_new (I_("disconnect_proxy"),
200                   G_OBJECT_CLASS_TYPE (klass),
201                   0, 0, NULL, NULL,
202                   _gtk_marshal_VOID__OBJECT_OBJECT,
203                   G_TYPE_NONE, 2, 
204                   GTK_TYPE_ACTION, GTK_TYPE_WIDGET);
205
206   /**
207    * GtkActionGroup::pre-activate:
208    * @action_group: the group
209    * @action: the action
210    *
211    * The pre_activate signal is emitted just before the @action in the
212    * @action_group is activated
213    *
214    * This is intended for #GtkUIManager to proxy the signal and provide global
215    * notification just before any action is activated.
216    *
217    * Since: 2.4
218    */
219   action_group_signals[PRE_ACTIVATE] =
220     g_signal_new (I_("pre_activate"),
221                   G_OBJECT_CLASS_TYPE (klass),
222                   0, 0, NULL, NULL,
223                   _gtk_marshal_VOID__OBJECT,
224                   G_TYPE_NONE, 1, 
225                   GTK_TYPE_ACTION);
226
227   /**
228    * GtkActionGroup::post-activate:
229    * @action_group: the group
230    * @action: the action
231    *
232    * The post_activate signal is emitted just after the @action in the
233    * @action_group is activated
234    *
235    * This is intended for #GtkUIManager to proxy the signal and provide global
236    * notification just after any action is activated.
237    *
238    * Since: 2.4
239    */
240   action_group_signals[POST_ACTIVATE] =
241     g_signal_new (I_("post_activate"),
242                   G_OBJECT_CLASS_TYPE (klass),
243                   0, 0, NULL, NULL,
244                   _gtk_marshal_VOID__OBJECT,
245                   G_TYPE_NONE, 1, 
246                   GTK_TYPE_ACTION);
247
248   g_type_class_add_private (gobject_class, sizeof (GtkActionGroupPrivate));
249 }
250
251
252 static void 
253 remove_action (GtkAction *action) 
254 {
255   g_object_set (action, I_("action-group"), NULL, NULL);
256   g_object_unref (action);
257 }
258
259 static void
260 gtk_action_group_init (GtkActionGroup *self)
261 {
262   self->private_data = GTK_ACTION_GROUP_GET_PRIVATE (self);
263   self->private_data->name = NULL;
264   self->private_data->sensitive = TRUE;
265   self->private_data->visible = TRUE;
266   self->private_data->actions = g_hash_table_new_full (g_str_hash, g_str_equal,
267                                                        (GDestroyNotify) g_free,
268                                                        (GDestroyNotify) remove_action);
269   self->private_data->translate_func = NULL;
270   self->private_data->translate_data = NULL;
271   self->private_data->translate_notify = NULL;
272 }
273
274 /**
275  * gtk_action_group_new:
276  * @name: the name of the action group.
277  *
278  * Creates a new #GtkActionGroup object. The name of the action group
279  * is used when associating <link linkend="Action-Accel">keybindings</link> 
280  * with the actions.
281  *
282  * Returns: the new #GtkActionGroup
283  *
284  * Since: 2.4
285  */
286 GtkActionGroup *
287 gtk_action_group_new (const gchar *name)
288 {
289   GtkActionGroup *self;
290
291   self = g_object_new (GTK_TYPE_ACTION_GROUP, NULL);
292   self->private_data->name = g_strdup (name);
293
294   return self;
295 }
296
297 static void
298 gtk_action_group_finalize (GObject *object)
299 {
300   GtkActionGroup *self;
301
302   self = GTK_ACTION_GROUP (object);
303
304   g_free (self->private_data->name);
305   self->private_data->name = NULL;
306
307   g_hash_table_destroy (self->private_data->actions);
308   self->private_data->actions = NULL;
309
310   if (self->private_data->translate_notify)
311     self->private_data->translate_notify (self->private_data->translate_data);
312
313   if (parent_class->finalize)
314     (* parent_class->finalize) (object);
315 }
316
317 static void
318 gtk_action_group_set_property (GObject         *object,
319                                guint            prop_id,
320                                const GValue    *value,
321                                GParamSpec      *pspec)
322 {
323   GtkActionGroup *self;
324   gchar *tmp;
325   
326   self = GTK_ACTION_GROUP (object);
327
328   switch (prop_id)
329     {
330     case PROP_NAME:
331       tmp = self->private_data->name;
332       self->private_data->name = g_value_dup_string (value);
333       g_free (tmp);
334       break;
335     case PROP_SENSITIVE:
336       gtk_action_group_set_sensitive (self, g_value_get_boolean (value));
337       break;
338     case PROP_VISIBLE:
339       gtk_action_group_set_visible (self, g_value_get_boolean (value));
340       break;
341     default:
342       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343       break;
344     }
345 }
346
347 static void
348 gtk_action_group_get_property (GObject    *object,
349                                guint       prop_id,
350                                GValue     *value,
351                                GParamSpec *pspec)
352 {
353   GtkActionGroup *self;
354   
355   self = GTK_ACTION_GROUP (object);
356
357   switch (prop_id)
358     {
359     case PROP_NAME:
360       g_value_set_string (value, self->private_data->name);
361       break;
362     case PROP_SENSITIVE:
363       g_value_set_boolean (value, self->private_data->sensitive);
364       break;
365     case PROP_VISIBLE:
366       g_value_set_boolean (value, self->private_data->visible);
367       break;
368     default:
369       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370       break;
371     }
372 }
373
374 static GtkAction *
375 gtk_action_group_real_get_action (GtkActionGroup *self,
376                                   const gchar    *action_name)
377 {
378   return g_hash_table_lookup (self->private_data->actions, action_name);
379 }
380
381 /**
382  * gtk_action_group_get_name:
383  * @action_group: the action group
384  *
385  * Gets the name of the action group.
386  *
387  * Returns: the name of the action group.
388  * 
389  * Since: 2.4
390  */
391 G_CONST_RETURN gchar *
392 gtk_action_group_get_name (GtkActionGroup *action_group)
393 {
394   g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
395
396   return action_group->private_data->name;
397 }
398
399 /**
400  * gtk_action_group_get_sensitive:
401  * @action_group: the action group
402  *
403  * Returns %TRUE if the group is sensitive.  The constituent actions
404  * can only be logically sensitive (see gtk_action_is_sensitive()) if
405  * they are sensitive (see gtk_action_get_sensitive()) and their group
406  * is sensitive.
407  * 
408  * Return value: %TRUE if the group is sensitive.
409  *
410  * Since: 2.4
411  */
412 gboolean
413 gtk_action_group_get_sensitive (GtkActionGroup *action_group)
414 {
415   g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), FALSE);
416
417   return action_group->private_data->sensitive;
418 }
419
420 static void
421 cb_set_action_sensitivity (const gchar *name, 
422                            GtkAction   *action)
423 {
424   /* Minor optimization, the action_groups state only affects actions 
425    * that are themselves sensitive */
426   if (gtk_action_get_sensitive (action))
427     _gtk_action_sync_sensitive (action);
428 }
429
430 /**
431  * gtk_action_group_set_sensitive:
432  * @action_group: the action group
433  * @sensitive: new sensitivity
434  *
435  * Changes the sensitivity of @action_group
436  * 
437  * Since: 2.4
438  */
439 void
440 gtk_action_group_set_sensitive (GtkActionGroup *action_group, 
441                                 gboolean        sensitive)
442 {
443   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
444
445   sensitive = sensitive != FALSE;
446
447   if (action_group->private_data->sensitive != sensitive)
448     {
449       action_group->private_data->sensitive = sensitive;
450       g_hash_table_foreach (action_group->private_data->actions, 
451                             (GHFunc) cb_set_action_sensitivity, NULL);
452
453       g_object_notify (G_OBJECT (action_group), "sensitive");
454     }
455 }
456
457 /**
458  * gtk_action_group_get_visible:
459  * @action_group: the action group
460  *
461  * Returns %TRUE if the group is visible.  The constituent actions
462  * can only be logically visible (see gtk_action_is_visible()) if
463  * they are visible (see gtk_action_get_visible()) and their group
464  * is visible.
465  * 
466  * Return value: %TRUE if the group is visible.
467  * 
468  * Since: 2.4
469  */
470 gboolean
471 gtk_action_group_get_visible (GtkActionGroup *action_group)
472 {
473   g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), FALSE);
474
475   return action_group->private_data->visible;
476 }
477
478 static void
479 cb_set_action_visiblity (const gchar *name, 
480                          GtkAction   *action)
481 {
482   /* Minor optimization, the action_groups state only affects actions 
483    * that are themselves visible */
484   if (gtk_action_get_visible (action))
485     _gtk_action_sync_visible (action);
486 }
487
488 /**
489  * gtk_action_group_set_visible:
490  * @action_group: the action group
491  * @visible: new visiblity
492  *
493  * Changes the visible of @action_group.
494  * 
495  * Since: 2.4
496  */
497 void
498 gtk_action_group_set_visible (GtkActionGroup *action_group, 
499                               gboolean        visible)
500 {
501   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
502
503   visible = visible != FALSE;
504
505   if (action_group->private_data->visible != visible)
506     {
507       action_group->private_data->visible = visible;
508       g_hash_table_foreach (action_group->private_data->actions, 
509                             (GHFunc) cb_set_action_visiblity, NULL);
510
511       g_object_notify (G_OBJECT (action_group), "visible");
512     }
513 }
514
515 /**
516  * gtk_action_group_get_action:
517  * @action_group: the action group
518  * @action_name: the name of the action
519  *
520  * Looks up an action in the action group by name.
521  *
522  * Returns: the action, or %NULL if no action by that name exists
523  *
524  * Since: 2.4
525  */
526 GtkAction *
527 gtk_action_group_get_action (GtkActionGroup *action_group,
528                              const gchar    *action_name)
529 {
530   g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
531   g_return_val_if_fail (GTK_ACTION_GROUP_GET_CLASS (action_group)->get_action != NULL, NULL);
532
533   return (* GTK_ACTION_GROUP_GET_CLASS (action_group)->get_action)
534     (action_group, action_name);
535 }
536
537 /**
538  * gtk_action_group_add_action:
539  * @action_group: the action group
540  * @action: an action
541  *
542  * Adds an action object to the action group. Note that this function
543  * does not set up the accel path of the action, which can lead to problems
544  * if a user tries to modify the accelerator of a menuitem associated with
545  * the action. Therefore you must either set the accel path yourself with
546  * gtk_action_set_accel_path(), or use 
547  * <literal>gtk_action_group_add_action_with_accel (..., NULL)</literal>.
548  *
549  * Since: 2.4
550  */
551 void
552 gtk_action_group_add_action (GtkActionGroup *action_group,
553                              GtkAction      *action)
554 {
555   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
556   g_return_if_fail (GTK_IS_ACTION (action));
557   g_return_if_fail (gtk_action_get_name (action) != NULL);
558
559   g_hash_table_insert (action_group->private_data->actions, 
560                        g_strdup (gtk_action_get_name (action)),
561                        g_object_ref (action));
562   g_object_set (action, I_("action-group"), action_group, NULL);
563 }
564
565 /**
566  * gtk_action_group_add_action_with_accel:
567  * @action_group: the action group 
568  * @action: the action to add 
569  * @accelerator: the accelerator for the action, in
570  *   the format understood by gtk_accelerator_parse(), or "" for no accelerator, or 
571  *   %NULL to use the stock accelerator 
572  *
573  * Adds an action object to the action group and sets up the accelerator.
574  *
575  * If @accelerator is %NULL, attempts to use the accelerator associated 
576  * with the stock_id of the action. 
577  *
578  * Accel paths are set to
579  * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.
580  *
581  * Since: 2.4
582  */
583 void
584 gtk_action_group_add_action_with_accel (GtkActionGroup *action_group,
585                                         GtkAction      *action,
586                                         const gchar    *accelerator)
587 {
588   gchar *accel_path;
589   guint  accel_key = 0;
590   GdkModifierType accel_mods;
591   GtkStockItem stock_item;
592   gchar *name;
593   gchar *stock_id;
594   
595   g_object_get (action, "name", &name, "stock-id", &stock_id, NULL);
596
597   accel_path = g_strconcat ("<Actions>/",
598                             action_group->private_data->name, "/", name, NULL);
599
600   if (accelerator)
601     {
602       if (accelerator[0] == 0) 
603         accel_key = 0;
604       else
605         {
606           gtk_accelerator_parse (accelerator, &accel_key, &accel_mods);
607           if (accel_key == 0)
608             g_warning ("Unable to parse accelerator '%s' for action '%s'",
609                        accelerator, name);
610         }
611     }
612   else if (stock_id && gtk_stock_lookup (stock_id, &stock_item))
613     {
614       accel_key = stock_item.keyval;
615       accel_mods = stock_item.modifier;
616     }
617
618   if (accel_key)
619     gtk_accel_map_add_entry (accel_path, accel_key, accel_mods);
620
621   gtk_action_set_accel_path (action, accel_path);
622   gtk_action_group_add_action (action_group, action);
623
624   g_free (accel_path);
625   g_free (stock_id);
626   g_free (name);
627 }
628
629 /**
630  * gtk_action_group_remove_action:
631  * @action_group: the action group
632  * @action: an action
633  *
634  * Removes an action object from the action group.
635  *
636  * Since: 2.4
637  */
638 void
639 gtk_action_group_remove_action (GtkActionGroup *action_group,
640                                 GtkAction      *action)
641 {
642   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
643   g_return_if_fail (GTK_IS_ACTION (action));
644   g_return_if_fail (gtk_action_get_name (action) != NULL);
645
646   /* extra protection to make sure action->name is valid */
647   g_object_ref (action);
648   g_hash_table_remove (action_group->private_data->actions, gtk_action_get_name (action));
649   g_object_unref (action);
650 }
651
652 static void
653 add_single_action (gpointer key, 
654                    gpointer value, 
655                    gpointer user_data)
656 {
657   GList **list = user_data;
658
659   *list = g_list_prepend (*list, value);
660 }
661
662 /**
663  * gtk_action_group_list_actions:
664  * @action_group: the action group
665  *
666  * Lists the actions in the action group.
667  *
668  * Returns: an allocated list of the action objects in the action group
669  * 
670  * Since: 2.4
671  */
672 GList *
673 gtk_action_group_list_actions (GtkActionGroup *action_group)
674 {
675   GList *actions = NULL;
676   g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL);
677   
678   g_hash_table_foreach (action_group->private_data->actions, add_single_action, &actions);
679
680   return g_list_reverse (actions);
681 }
682
683
684 /**
685  * gtk_action_group_add_actions:
686  * @action_group: the action group
687  * @entries: an array of action descriptions
688  * @n_entries: the number of entries
689  * @user_data: data to pass to the action callbacks
690  *
691  * This is a convenience function to create a number of actions and add them 
692  * to the action group.
693  *
694  * The "activate" signals of the actions are connected to the callbacks and 
695  * their accel paths are set to 
696  * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
697  * 
698  * Since: 2.4
699  */
700 void
701 gtk_action_group_add_actions (GtkActionGroup       *action_group,
702                               const GtkActionEntry *entries,
703                               guint                 n_entries,
704                               gpointer              user_data)
705 {
706   gtk_action_group_add_actions_full (action_group, 
707                                      entries, n_entries, 
708                                      user_data, NULL);
709 }
710
711 typedef struct _SharedData  SharedData;
712
713 struct _SharedData {
714   guint          ref_count;
715   gpointer       data;
716   GDestroyNotify destroy;
717 };
718
719 static void
720 shared_data_unref (gpointer data)
721 {
722   SharedData *shared_data = (SharedData *)data;
723
724   shared_data->ref_count--;
725   if (shared_data->ref_count == 0)
726     {
727       if (shared_data->destroy) 
728         (*shared_data->destroy) (shared_data->data);
729       
730       g_slice_free (SharedData, shared_data);
731     }
732 }
733
734
735 /**
736  * gtk_action_group_add_actions_full:
737  * @action_group: the action group
738  * @entries: an array of action descriptions
739  * @n_entries: the number of entries
740  * @user_data: data to pass to the action callbacks
741  * @destroy: destroy notification callback for @user_data
742  *
743  * This variant of gtk_action_group_add_actions() adds a #GDestroyNotify
744  * callback for @user_data. 
745  * 
746  * Since: 2.4
747  */
748 void
749 gtk_action_group_add_actions_full (GtkActionGroup       *action_group,
750                                    const GtkActionEntry *entries,
751                                    guint                 n_entries,
752                                    gpointer              user_data,
753                                    GDestroyNotify        destroy)
754 {
755
756   /* Keep this in sync with the other 
757    * gtk_action_group_add_..._actions_full() functions.
758    */
759   guint i;
760   SharedData *shared_data;
761
762   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
763
764   shared_data = g_slice_new0 (SharedData);
765   shared_data->ref_count = 1;
766   shared_data->data = user_data;
767   shared_data->destroy = destroy;
768
769   for (i = 0; i < n_entries; i++)
770     {
771       GtkAction *action;
772       const gchar *label;
773       const gchar *tooltip;
774
775       label = gtk_action_group_translate_string (action_group, entries[i].label);
776       tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
777
778       action = gtk_action_new (entries[i].name,
779                                label,
780                                tooltip,
781                                NULL);
782
783       if (entries[i].stock_id) 
784         {
785           if (gtk_icon_factory_lookup_default (entries[i].stock_id))
786             g_object_set (action, "stock-id", entries[i].stock_id, NULL);
787           else
788             g_object_set (action, "icon-name", entries[i].stock_id, NULL);
789         }
790           
791       if (entries[i].callback)
792         {
793           GClosure *closure;
794
795           closure = g_cclosure_new (entries[i].callback, user_data, NULL);
796           g_closure_add_finalize_notifier (closure, shared_data, 
797                                            (GClosureNotify)shared_data_unref);
798           shared_data->ref_count++;
799
800           g_signal_connect_closure (action, "activate", closure, FALSE);
801         }
802           
803       gtk_action_group_add_action_with_accel (action_group, 
804                                               action,
805                                               entries[i].accelerator);
806       g_object_unref (action);
807     }
808
809   shared_data_unref (shared_data);
810 }
811
812 /**
813  * gtk_action_group_add_toggle_actions:
814  * @action_group: the action group
815  * @entries: an array of toggle action descriptions
816  * @n_entries: the number of entries
817  * @user_data: data to pass to the action callbacks
818  *
819  * This is a convenience function to create a number of toggle actions and add them 
820  * to the action group.
821  *
822  * The "activate" signals of the actions are connected to the callbacks and 
823  * their accel paths are set to 
824  * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
825  * 
826  * Since: 2.4
827  */
828 void
829 gtk_action_group_add_toggle_actions (GtkActionGroup             *action_group,
830                                      const GtkToggleActionEntry *entries,
831                                      guint                       n_entries,
832                                      gpointer                    user_data)
833 {
834   gtk_action_group_add_toggle_actions_full (action_group, 
835                                             entries, n_entries, 
836                                             user_data, NULL);
837 }
838
839
840 /**
841  * gtk_action_group_add_toggle_actions_full:
842  * @action_group: the action group
843  * @entries: an array of toggle action descriptions
844  * @n_entries: the number of entries
845  * @user_data: data to pass to the action callbacks
846  * @destroy: destroy notification callback for @user_data
847  *
848  * This variant of gtk_action_group_add_toggle_actions() adds a 
849  * #GDestroyNotify callback for @user_data. 
850  * 
851  * Since: 2.4
852  */
853 void
854 gtk_action_group_add_toggle_actions_full (GtkActionGroup             *action_group,
855                                           const GtkToggleActionEntry *entries,
856                                           guint                       n_entries,
857                                           gpointer                    user_data,
858                                           GDestroyNotify              destroy)
859 {
860   /* Keep this in sync with the other 
861    * gtk_action_group_add_..._actions_full() functions.
862    */
863   guint i;
864   SharedData *shared_data;
865
866   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
867
868   shared_data = g_slice_new0 (SharedData);
869   shared_data->ref_count = 1;
870   shared_data->data = user_data;
871   shared_data->destroy = destroy;
872
873   for (i = 0; i < n_entries; i++)
874     {
875       GtkToggleAction *action;
876       const gchar *label;
877       const gchar *tooltip;
878
879       label = gtk_action_group_translate_string (action_group, entries[i].label);
880       tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
881
882       action = gtk_toggle_action_new (entries[i].name,
883                                       label,
884                                       tooltip,
885                                       NULL);
886
887       if (entries[i].stock_id) 
888         {
889           if (gtk_icon_factory_lookup_default (entries[i].stock_id))
890             g_object_set (action, "stock-id", entries[i].stock_id, NULL);
891           else
892             g_object_set (action, "icon-name", entries[i].stock_id, NULL);
893         }
894
895       gtk_toggle_action_set_active (action, entries[i].is_active);
896
897       if (entries[i].callback)
898         {
899           GClosure *closure;
900
901           closure = g_cclosure_new (entries[i].callback, user_data, NULL);
902           g_closure_add_finalize_notifier (closure, shared_data, 
903                                            (GClosureNotify)shared_data_unref);
904           shared_data->ref_count++;
905
906           g_signal_connect_closure (action, "activate", closure, FALSE);
907         }
908           
909       gtk_action_group_add_action_with_accel (action_group, 
910                                               GTK_ACTION (action),
911                                               entries[i].accelerator);
912       g_object_unref (action);
913     }
914
915     shared_data_unref (shared_data);
916 }
917
918 /**
919  * gtk_action_group_add_radio_actions:
920  * @action_group: the action group
921  * @entries: an array of radio action descriptions
922  * @n_entries: the number of entries
923  * @value: the value of the action to activate initially, or -1 if
924  *   no action should be activated
925  * @on_change: the callback to connect to the changed signal
926  * @user_data: data to pass to the action callbacks
927  * 
928  * This is a convenience routine to create a group of radio actions and
929  * add them to the action group. 
930  *
931  * The "changed" signal of the first radio action is connected to the 
932  * @on_change callback and the accel paths of the actions are set to 
933  * <literal>&lt;Actions&gt;/<replaceable>group-name</replaceable>/<replaceable>action-name</replaceable></literal>.  
934  * 
935  * Since: 2.4
936  **/
937 void            
938 gtk_action_group_add_radio_actions (GtkActionGroup            *action_group,
939                                     const GtkRadioActionEntry *entries,
940                                     guint                      n_entries,
941                                     gint                       value,
942                                     GCallback                  on_change,
943                                     gpointer                   user_data)
944 {
945   gtk_action_group_add_radio_actions_full (action_group, 
946                                            entries, n_entries, 
947                                            value,
948                                            on_change, user_data, NULL);
949 }
950
951 /**
952  * gtk_action_group_add_radio_actions_full:
953  * @action_group: the action group
954  * @entries: an array of radio action descriptions
955  * @n_entries: the number of entries
956  * @value: the value of the action to activate initially, or -1 if
957  *   no action should be activated
958  * @on_change: the callback to connect to the changed signal
959  * @user_data: data to pass to the action callbacks
960  * @destroy: destroy notification callback for @user_data
961  *
962  * This variant of gtk_action_group_add_radio_actions() adds a 
963  * #GDestroyNotify callback for @user_data. 
964  * 
965  * Since: 2.4
966  **/
967 void            
968 gtk_action_group_add_radio_actions_full (GtkActionGroup            *action_group,
969                                          const GtkRadioActionEntry *entries,
970                                          guint                      n_entries,
971                                          gint                       value,
972                                          GCallback                  on_change,
973                                          gpointer                   user_data,
974                                          GDestroyNotify             destroy)
975 {
976   /* Keep this in sync with the other 
977    * gtk_action_group_add_..._actions_full() functions.
978    */
979   guint i;
980   GSList *group = NULL;
981   GtkRadioAction *first_action = NULL;
982
983   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
984
985   for (i = 0; i < n_entries; i++)
986     {
987       GtkRadioAction *action;
988       const gchar *label;
989       const gchar *tooltip; 
990
991       label = gtk_action_group_translate_string (action_group, entries[i].label);
992       tooltip = gtk_action_group_translate_string (action_group, entries[i].tooltip);
993
994       action = gtk_radio_action_new (entries[i].name,
995                                      label,
996                                      tooltip,
997                                      NULL,
998                                      entries[i].value);
999
1000       if (entries[i].stock_id) 
1001         {
1002           if (gtk_icon_factory_lookup_default (entries[i].stock_id))
1003             g_object_set (action, "stock-id", entries[i].stock_id, NULL);
1004           else
1005             g_object_set (action, "icon-name", entries[i].stock_id, NULL);
1006         }
1007
1008       if (i == 0) 
1009         first_action = action;
1010
1011       gtk_radio_action_set_group (action, group);
1012       group = gtk_radio_action_get_group (action);
1013
1014       if (value == entries[i].value)
1015         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1016
1017       gtk_action_group_add_action_with_accel (action_group, 
1018                                               GTK_ACTION (action),
1019                                               entries[i].accelerator);
1020       g_object_unref (action);
1021     }
1022
1023   if (on_change && first_action)
1024     g_signal_connect_data (first_action, "changed",
1025                            on_change, user_data, 
1026                            (GClosureNotify)destroy, 0);
1027 }
1028
1029 /**
1030  * gtk_action_group_set_translate_func:
1031  * @action_group: a #GtkActionGroup
1032  * @func: a #GtkTranslateFunc
1033  * @data: data to be passed to @func and @notify
1034  * @notify: a #GtkDestroyNotify function to be called when @action_group is 
1035  *   destroyed and when the translation function is changed again
1036  * 
1037  * Sets a function to be used for translating the @label and @tooltip of 
1038  * #GtkActionGroupEntry<!-- -->s added by gtk_action_group_add_actions().
1039  *
1040  * If you're using gettext(), it is enough to set the translation domain
1041  * with gtk_action_group_set_translation_domain().
1042  *
1043  * Since: 2.4 
1044  **/
1045 void
1046 gtk_action_group_set_translate_func (GtkActionGroup   *action_group,
1047                                      GtkTranslateFunc  func,
1048                                      gpointer          data,
1049                                      GtkDestroyNotify  notify)
1050 {
1051   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1052   
1053   if (action_group->private_data->translate_notify)
1054     action_group->private_data->translate_notify (action_group->private_data->translate_data);
1055       
1056   action_group->private_data->translate_func = func;
1057   action_group->private_data->translate_data = data;
1058   action_group->private_data->translate_notify = notify;
1059 }
1060
1061 static gchar *
1062 dgettext_swapped (const gchar *msgid, 
1063                   const gchar *domainname)
1064 {
1065   /* Pass through dgettext if and only if msgid is nonempty. */
1066   if (msgid && *msgid) 
1067     return dgettext (domainname, msgid); 
1068   else
1069     return (gchar*) msgid;
1070 }
1071
1072 /**
1073  * gtk_action_group_set_translation_domain:
1074  * @action_group: a #GtkActionGroup
1075  * @domain: the translation domain to use for dgettext() calls
1076  * 
1077  * Sets the translation domain and uses dgettext() for translating the 
1078  * @label and @tooltip of #GtkActionEntry<!-- -->s added by 
1079  * gtk_action_group_add_actions().
1080  *
1081  * If you're not using gettext() for localization, see 
1082  * gtk_action_group_set_translate_func().
1083  *
1084  * Since: 2.4
1085  **/
1086 void 
1087 gtk_action_group_set_translation_domain (GtkActionGroup *action_group,
1088                                          const gchar    *domain)
1089 {
1090   g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
1091
1092   gtk_action_group_set_translate_func (action_group, 
1093                                        (GtkTranslateFunc)dgettext_swapped,
1094                                        g_strdup (domain),
1095                                        g_free);
1096
1097
1098
1099 /**
1100  * gtk_action_group_translate_string:
1101  * @action_group: a #GtkActionGroup
1102  * @string: a string
1103  *
1104  * Translates a string using the specified translate_func(). This
1105  * is mainly intended for language bindings.
1106  *
1107  * Returns: the translation of @string
1108  *
1109  * Since: 2.6
1110  **/
1111 G_CONST_RETURN gchar *
1112 gtk_action_group_translate_string (GtkActionGroup *action_group,
1113                                    const gchar    *string)
1114 {
1115   GtkTranslateFunc translate_func;
1116   gpointer translate_data;
1117   
1118   g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), string);
1119   
1120   if (string == NULL)
1121     return NULL;
1122
1123   translate_func = action_group->private_data->translate_func;
1124   translate_data = action_group->private_data->translate_data;
1125   
1126   if (translate_func)
1127     return translate_func (string, translate_data);
1128   else
1129     return string;
1130 }
1131
1132 /* Protected for use by GtkAction */
1133 void
1134 _gtk_action_group_emit_connect_proxy  (GtkActionGroup *action_group,
1135                                        GtkAction      *action,
1136                                        GtkWidget      *proxy)
1137 {
1138   g_signal_emit (action_group, action_group_signals[CONNECT_PROXY], 0, 
1139                  action, proxy);
1140 }
1141
1142 void
1143 _gtk_action_group_emit_disconnect_proxy  (GtkActionGroup *action_group,
1144                                           GtkAction      *action,
1145                                           GtkWidget      *proxy)
1146 {
1147   g_signal_emit (action_group, action_group_signals[DISCONNECT_PROXY], 0, 
1148                  action, proxy);
1149 }
1150
1151 void
1152 _gtk_action_group_emit_pre_activate  (GtkActionGroup *action_group,
1153                                       GtkAction      *action)
1154 {
1155   g_signal_emit (action_group, action_group_signals[PRE_ACTIVATE], 0, action);
1156 }
1157
1158 void
1159 _gtk_action_group_emit_post_activate (GtkActionGroup *action_group,
1160                                       GtkAction      *action)
1161 {
1162   g_signal_emit (action_group, action_group_signals[POST_ACTIVATE], 0, action);
1163 }
1164
1165 #define __GTK_ACTION_GROUP_C__
1166 #include "gtkaliasdef.c"