]> Pileus Git - ~andy/gtk/blob - gtk/gtkradioaction.c
Make PLT-reduction work with gcc4, and don't include everything in
[~andy/gtk] / gtk / gtkradioaction.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 "gtkradioaction.h"
34 #include "gtkradiomenuitem.h"
35 #include "gtktoggleactionprivate.h"
36 #include "gtktoggletoolbutton.h"
37 #include "gtkintl.h"
38 #include "gtkalias.h"
39
40 #define GTK_RADIO_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RADIO_ACTION, GtkRadioActionPrivate))
41
42 struct _GtkRadioActionPrivate 
43 {
44   GSList *group;
45   gint    value;
46 };
47
48 enum 
49 {
50   CHANGED,
51   LAST_SIGNAL
52 };
53
54 enum 
55 {
56   PROP_0,
57   PROP_VALUE,
58   PROP_GROUP
59 };
60
61 static void gtk_radio_action_init         (GtkRadioAction *action);
62 static void gtk_radio_action_class_init   (GtkRadioActionClass *class);
63 static void gtk_radio_action_finalize     (GObject *object);
64 static void gtk_radio_action_set_property (GObject         *object,
65                                            guint            prop_id,
66                                            const GValue    *value,
67                                            GParamSpec      *pspec);
68 static void gtk_radio_action_get_property (GObject         *object,
69                                            guint            prop_id,
70                                            GValue          *value,
71                                            GParamSpec      *pspec);
72 static void gtk_radio_action_activate     (GtkAction *action);
73 static GtkWidget *create_menu_item        (GtkAction *action);
74
75
76 GType
77 gtk_radio_action_get_type (void)
78 {
79   static GtkType type = 0;
80
81   if (!type)
82     {
83       static const GTypeInfo type_info =
84       {
85         sizeof (GtkRadioActionClass),
86         (GBaseInitFunc) NULL,
87         (GBaseFinalizeFunc) NULL,
88         (GClassInitFunc) gtk_radio_action_class_init,
89         (GClassFinalizeFunc) NULL,
90         NULL,
91         
92         sizeof (GtkRadioAction),
93         0, /* n_preallocs */
94         (GInstanceInitFunc) gtk_radio_action_init,
95       };
96
97       type = g_type_register_static (GTK_TYPE_TOGGLE_ACTION,
98                                      "GtkRadioAction",
99                                      &type_info, 0);
100     }
101   return type;
102 }
103
104 static GObjectClass *parent_class = NULL;
105 static guint         radio_action_signals[LAST_SIGNAL] = { 0 };
106
107 static void
108 gtk_radio_action_class_init (GtkRadioActionClass *klass)
109 {
110   GObjectClass *gobject_class;
111   GtkActionClass *action_class;
112
113   parent_class = g_type_class_peek_parent (klass);
114   gobject_class = G_OBJECT_CLASS (klass);
115   action_class = GTK_ACTION_CLASS (klass);
116
117   gobject_class->finalize = gtk_radio_action_finalize;
118   gobject_class->set_property = gtk_radio_action_set_property;
119   gobject_class->get_property = gtk_radio_action_get_property;
120
121   action_class->activate = gtk_radio_action_activate;
122
123   action_class->create_menu_item = create_menu_item;
124
125   /**
126    * GtkRadioAction:value:
127    *
128    * The value is an arbitrary integer which can be used as a
129    * convenient way to determine which action in the group is 
130    * currently active in an ::activate or ::changed signal handler.
131    * See gtk_radio_action_get_current_value() and #GtkRadioActionEntry
132    * for convenient ways to get and set this property.
133    *
134    * Since: 2.4
135    */
136   g_object_class_install_property (gobject_class,
137                                    PROP_VALUE,
138                                    g_param_spec_int ("value",
139                                                      P_("The value"),
140                                                      P_("The value returned by gtk_radio_action_get_current_value() when this action is the current action of its group."),
141                                                      G_MININT,
142                                                      G_MAXINT,
143                                                      0,
144                                                      G_PARAM_READWRITE));
145
146   /**
147    * GtkRadioAction:group:
148    *
149    * Sets a new group for a radio action.
150    *
151    * Since: 2.4
152    */
153   g_object_class_install_property (gobject_class,
154                                    PROP_GROUP,
155                                    g_param_spec_object ("group",
156                                                         P_("Group"),
157                                                         P_("The radio action whose group this action belongs to."),
158                                                         GTK_TYPE_RADIO_ACTION,
159                                                         G_PARAM_WRITABLE));
160
161   /**
162    * GtkRadioAction::changed:
163    * @action: the action on which the signal is emitted
164    * @current: the member of @action<!-- -->s group which has just been activated
165    *
166    * The ::changed signal is emitted on every member of a radio group when the
167    * active member is changed. The signal gets emitted after the ::activate signals
168    * for the previous and current active members.
169    *
170    * Since: 2.4
171    */
172   radio_action_signals[CHANGED] =
173     g_signal_new ("changed",
174                   G_OBJECT_CLASS_TYPE (klass),
175                   G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
176                   G_STRUCT_OFFSET (GtkRadioActionClass, changed),  NULL, NULL,
177                   g_cclosure_marshal_VOID__OBJECT,
178                   G_TYPE_NONE, 1, GTK_TYPE_RADIO_ACTION);
179
180   g_type_class_add_private (gobject_class, sizeof (GtkRadioActionPrivate));
181 }
182
183 static void
184 gtk_radio_action_init (GtkRadioAction *action)
185 {
186   action->private_data = GTK_RADIO_ACTION_GET_PRIVATE (action);
187   action->private_data->group = g_slist_prepend (NULL, action);
188   action->private_data->value = 0;
189 }
190
191 /**
192  * gtk_radio_action_new:
193  * @name: A unique name for the action
194  * @label: The label displayed in menu items and on buttons
195  * @tooltip: A tooltip for this action
196  * @stock_id: The stock icon to display in widgets representing this action
197  * @value: The value which gtk_radio_action_get_current_value() should return
198  *    if this action is selected.
199  *
200  * Creates a new #GtkRadioAction object. To add the action to
201  * a #GtkActionGroup and set the accelerator for the action,
202  * call gtk_action_group_add_action_with_accel().
203  *
204  * Return value: a new #GtkRadioAction
205  *
206  * Since: 2.4
207  */
208 GtkRadioAction *
209 gtk_radio_action_new (const gchar *name,
210                       const gchar *label,
211                       const gchar *tooltip,
212                       const gchar *stock_id,
213                       gint value)
214 {
215   GtkRadioAction *action;
216
217   action = g_object_new (GTK_TYPE_RADIO_ACTION,
218                          "name", name,
219                          "label", label,
220                          "tooltip", tooltip,
221                          "stock_id", stock_id,
222                          "value", value,
223                          NULL);
224
225   return action;
226 }
227
228 static void
229 gtk_radio_action_finalize (GObject *object)
230 {
231   GtkRadioAction *action;
232   GSList *tmp_list;
233
234   action = GTK_RADIO_ACTION (object);
235
236   g_print ("finalize %p\n", action);
237
238   action->private_data->group = g_slist_remove (action->private_data->group, action);
239
240   tmp_list = action->private_data->group;
241
242   while (tmp_list)
243     {
244       GtkRadioAction *tmp_action = tmp_list->data;
245
246       tmp_list = tmp_list->next;
247       tmp_action->private_data->group = action->private_data->group;
248     }
249
250   (* parent_class->finalize) (object);
251 }
252
253 static void
254 gtk_radio_action_set_property (GObject         *object,
255                                guint            prop_id,
256                                const GValue    *value,
257                                GParamSpec      *pspec)
258 {
259   GtkRadioAction *radio_action;
260   
261   radio_action = GTK_RADIO_ACTION (object);
262
263   switch (prop_id)
264     {
265     case PROP_VALUE:
266       radio_action->private_data->value = g_value_get_int (value);
267       break;
268     case PROP_GROUP: 
269       {
270         GtkRadioAction *arg;
271         GSList *slist = NULL;
272         
273         if (G_VALUE_HOLDS_OBJECT (value)) 
274           {
275             arg = GTK_RADIO_ACTION (g_value_get_object (value));
276             if (arg)
277               slist = gtk_radio_action_get_group (arg);
278             gtk_radio_action_set_group (radio_action, slist);
279           }
280       }
281       break;
282     default:
283       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284       break;
285     }
286 }
287
288 static void
289 gtk_radio_action_get_property (GObject    *object,
290                                guint       prop_id,
291                                GValue     *value,
292                                GParamSpec *pspec)
293 {
294   GtkRadioAction *radio_action;
295
296   radio_action = GTK_RADIO_ACTION (object);
297
298   switch (prop_id)
299     {
300     case PROP_VALUE:
301       g_value_set_int (value, radio_action->private_data->value);
302       break;
303     default:
304       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
305       break;
306     }
307 }
308
309 static void
310 gtk_radio_action_activate (GtkAction *action)
311 {
312   GtkRadioAction *radio_action;
313   GtkToggleAction *toggle_action;
314   GtkToggleAction *tmp_action;
315   GSList *tmp_list;
316
317   radio_action = GTK_RADIO_ACTION (action);
318   toggle_action = GTK_TOGGLE_ACTION (action);
319
320   if (toggle_action->private_data->active)
321     {
322       tmp_list = radio_action->private_data->group;
323
324       while (tmp_list)
325         {
326           tmp_action = tmp_list->data;
327           tmp_list = tmp_list->next;
328
329           if (tmp_action->private_data->active && (tmp_action != toggle_action)) 
330             {
331               toggle_action->private_data->active = !toggle_action->private_data->active;
332               break;
333             }
334         }
335     }
336   else
337     {
338       toggle_action->private_data->active = !toggle_action->private_data->active;
339
340       tmp_list = radio_action->private_data->group;
341       while (tmp_list)
342         {
343           tmp_action = tmp_list->data;
344           tmp_list = tmp_list->next;
345
346           if (tmp_action->private_data->active && (tmp_action != toggle_action))
347             {
348               _gtk_action_emit_activate (GTK_ACTION (tmp_action));
349               break;
350             }
351         }
352
353       tmp_list = radio_action->private_data->group;
354       while (tmp_list)
355         {
356           tmp_action = tmp_list->data;
357           tmp_list = tmp_list->next;
358           
359           g_signal_emit (tmp_action, radio_action_signals[CHANGED], 0, radio_action);
360         }
361     }
362
363   gtk_toggle_action_toggled (toggle_action);
364 }
365
366 static GtkWidget *
367 create_menu_item (GtkAction *action)
368 {
369   return g_object_new (GTK_TYPE_CHECK_MENU_ITEM, 
370                        "draw_as_radio", TRUE,
371                        NULL);
372 }
373
374 /**
375  * gtk_radio_action_get_group:
376  * @action: the action object
377  *
378  * Returns the list representing the radio group for this object.
379  * Note that the returned list is only valid until the next change
380  * to the group. 
381  *
382  * A common way to set up a group of radio group is the following:
383  * <informalexample><programlisting>
384  *   GSList *group = NULL;
385  *   GtkRadioAction *action;
386  *  
387  *   while (/<!-- -->* more actions to add *<!-- -->/)
388  *     {
389  *        action = gtk_radio_action_new (...);
390  *
391  *        gtk_radio_action_set_group (action, group);
392  *        group = gtk_radio_action_get_group (action);
393  *     }
394  * </programlisting></informalexample>
395  *
396  * Returns: the list representing the radio group for this object
397  *
398  * Since: 2.4
399  */
400 GSList *
401 gtk_radio_action_get_group (GtkRadioAction *action)
402 {
403   g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), NULL);
404
405   return action->private_data->group;
406 }
407
408 /**
409  * gtk_radio_action_set_group:
410  * @action: the action object
411  * @group: a list representing a radio group
412  *
413  * Sets the radio group for the radio action object.
414  *
415  * Since: 2.4
416  */
417 void
418 gtk_radio_action_set_group (GtkRadioAction *action, 
419                             GSList         *group)
420 {
421   g_return_if_fail (GTK_IS_RADIO_ACTION (action));
422   g_return_if_fail (!g_slist_find (group, action));
423
424   if (action->private_data->group)
425     {
426       GSList *slist;
427
428       action->private_data->group = g_slist_remove (action->private_data->group, action);
429
430       for (slist = action->private_data->group; slist; slist = slist->next)
431         {
432           GtkRadioAction *tmp_action = slist->data;
433
434           tmp_action->private_data->group = action->private_data->group;
435         }
436     }
437
438   action->private_data->group = g_slist_prepend (group, action);
439
440   if (group)
441     {
442       GSList *slist;
443
444       for (slist = action->private_data->group; slist; slist = slist->next)
445         {
446           GtkRadioAction *tmp_action = slist->data;
447
448           tmp_action->private_data->group = action->private_data->group;
449         }
450     }
451   else
452     {
453       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
454     }
455 }
456
457 /**
458  * gtk_radio_action_get_current_value:
459  * @action: a #GtkRadioAction
460  * 
461  * Obtains the value property of the currently active member of 
462  * the group to which @action belongs.
463  * 
464  * Return value: The value of the currently active group member
465  *
466  * Since: 2.4
467  **/
468 gint
469 gtk_radio_action_get_current_value (GtkRadioAction *action)
470 {
471   GSList *slist;
472
473   g_return_val_if_fail (GTK_IS_RADIO_ACTION (action), 0);
474
475   if (action->private_data->group)
476     {
477       for (slist = action->private_data->group; slist; slist = slist->next)
478         {
479           GtkToggleAction *toggle_action = slist->data;
480
481           if (toggle_action->private_data->active)
482             return GTK_RADIO_ACTION (toggle_action)->private_data->value;
483         }
484     }
485
486   return action->private_data->value;
487 }
488
489 #define __GTK_RADIO_ACTION_C__
490 #include "gtkaliasdef.c"