]> Pileus Git - ~andy/gtk/blob - gtk/gtkradiomenuitem.c
Revert name change
[~andy/gtk] / gtk / gtkradiomenuitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include "gtkaccellabel.h"
29 #include "gtkmarshalers.h"
30 #include "gtkradiomenuitem.h"
31 #include "gtkprivate.h"
32 #include "gtkintl.h"
33 #include "gtkalias.h"
34
35
36 enum {
37   PROP_0,
38   PROP_GROUP
39 };
40
41
42 static void gtk_radio_menu_item_destroy        (GtkObject             *object);
43 static void gtk_radio_menu_item_activate       (GtkMenuItem           *menu_item);
44 static void gtk_radio_menu_item_set_property   (GObject               *object,
45                                                 guint                  prop_id,
46                                                 const GValue          *value,
47                                                 GParamSpec            *pspec);
48 static void gtk_radio_menu_item_get_property   (GObject               *object,
49                                                 guint                  prop_id,
50                                                 GValue                *value,
51                                                 GParamSpec            *pspec);
52
53 static guint group_changed_signal = 0;
54
55 G_DEFINE_TYPE (GtkRadioMenuItem, gtk_radio_menu_item, GTK_TYPE_CHECK_MENU_ITEM)
56
57 GtkWidget*
58 gtk_radio_menu_item_new (GSList *group)
59 {
60   GtkRadioMenuItem *radio_menu_item;
61
62   radio_menu_item = g_object_new (GTK_TYPE_RADIO_MENU_ITEM, NULL);
63
64   gtk_radio_menu_item_set_group (radio_menu_item, group);
65
66   return GTK_WIDGET (radio_menu_item);
67 }
68
69 static void
70 gtk_radio_menu_item_set_property (GObject      *object,
71                                   guint         prop_id,
72                                   const GValue *value,
73                                   GParamSpec   *pspec)
74 {
75   GtkRadioMenuItem *radio_menu_item;
76
77   radio_menu_item = GTK_RADIO_MENU_ITEM (object);
78
79   switch (prop_id)
80     {
81       GSList *slist;
82
83     case PROP_GROUP:
84       if (G_VALUE_HOLDS_OBJECT (value))
85         slist = gtk_radio_menu_item_get_group ((GtkRadioMenuItem*) g_value_get_object (value));
86       else
87         slist = NULL;
88       gtk_radio_menu_item_set_group (radio_menu_item, slist);
89       break;
90     default:
91       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92       break;
93     }
94 }
95
96 static void
97 gtk_radio_menu_item_get_property (GObject    *object,
98                                   guint       prop_id,
99                                   GValue     *value,
100                                   GParamSpec *pspec)
101 {
102   switch (prop_id)
103     {
104     default:
105       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
106       break;
107     }
108 }
109
110 void
111 gtk_radio_menu_item_set_group (GtkRadioMenuItem *radio_menu_item,
112                                GSList           *group)
113 {
114   GtkWidget *old_group_singleton = NULL;
115   GtkWidget *new_group_singleton = NULL;
116   
117   g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (radio_menu_item));
118   g_return_if_fail (!g_slist_find (group, radio_menu_item));
119
120   if (radio_menu_item->group)
121     {
122       GSList *slist;
123
124       radio_menu_item->group = g_slist_remove (radio_menu_item->group, radio_menu_item);
125       
126       if (radio_menu_item->group && !radio_menu_item->group->next)
127         old_group_singleton = g_object_ref (radio_menu_item->group->data);
128           
129       for (slist = radio_menu_item->group; slist; slist = slist->next)
130         {
131           GtkRadioMenuItem *tmp_item;
132           
133           tmp_item = slist->data;
134           
135           tmp_item->group = radio_menu_item->group;
136         }
137     }
138   
139   if (group && !group->next)
140     new_group_singleton = g_object_ref (group->data);
141   
142   radio_menu_item->group = g_slist_prepend (group, radio_menu_item);
143   
144   if (group)
145     {
146       GSList *slist;
147       
148       for (slist = group; slist; slist = slist->next)
149         {
150           GtkRadioMenuItem *tmp_item;
151           
152           tmp_item = slist->data;
153           
154           tmp_item->group = radio_menu_item->group;
155         }
156     }
157   else
158     {
159       GTK_CHECK_MENU_ITEM (radio_menu_item)->active = TRUE;
160       /* gtk_widget_set_state (GTK_WIDGET (radio_menu_item), GTK_STATE_ACTIVE);
161        */
162     }
163
164   g_object_ref (radio_menu_item);
165
166   g_object_notify (G_OBJECT (radio_menu_item), "group");
167   g_signal_emit (radio_menu_item, group_changed_signal, 0);
168   if (old_group_singleton)
169     {
170       g_signal_emit (old_group_singleton, group_changed_signal, 0);
171       g_object_unref (old_group_singleton);
172     }
173   if (new_group_singleton)
174     {
175       g_signal_emit (new_group_singleton, group_changed_signal, 0);
176       g_object_unref (new_group_singleton);
177     }
178
179   g_object_unref (radio_menu_item);
180 }
181
182 GtkWidget*
183 gtk_radio_menu_item_new_with_label (GSList *group,
184                                     const gchar *label)
185 {
186   GtkWidget *radio_menu_item;
187   GtkWidget *accel_label;
188
189   radio_menu_item = gtk_radio_menu_item_new (group);
190   accel_label = gtk_accel_label_new (label);
191   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
192   gtk_container_add (GTK_CONTAINER (radio_menu_item), accel_label);
193   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), radio_menu_item);
194   gtk_widget_show (accel_label);
195
196   return radio_menu_item;
197 }
198
199
200 /**
201  * gtk_radio_menu_item_new_with_mnemonic:
202  * @group: group the radio menu item is inside
203  * @label: the text of the button, with an underscore in front of the
204  *         mnemonic character
205  * @returns: a new #GtkRadioMenuItem
206  *
207  * Creates a new #GtkRadioMenuItem containing a label. The label
208  * will be created using gtk_label_new_with_mnemonic(), so underscores
209  * in @label indicate the mnemonic for the menu item.
210  **/
211 GtkWidget*
212 gtk_radio_menu_item_new_with_mnemonic (GSList *group,
213                                        const gchar *label)
214 {
215   GtkWidget *radio_menu_item;
216   GtkWidget *accel_label;
217
218   radio_menu_item = gtk_radio_menu_item_new (group);
219   accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
220   gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
221   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
222
223   gtk_container_add (GTK_CONTAINER (radio_menu_item), accel_label);
224   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), radio_menu_item);
225   gtk_widget_show (accel_label);
226
227   return radio_menu_item;
228 }
229
230 /**
231  * gtk_radio_menu_item_new_from_widget:
232  * @group: An existing #GtkRadioMenuItem
233  * 
234  * Creates a new #GtkRadioMenuItem adding it to the same group as @group.
235  * 
236  * Return value: The new #GtkRadioMenuItem
237  * 
238  * Since: 2.4
239  **/
240 GtkWidget *
241 gtk_radio_menu_item_new_from_widget (GtkRadioMenuItem *group)
242 {
243   GSList *list = NULL;
244   
245   g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (group), NULL);
246
247   if (group)
248     list = gtk_radio_menu_item_get_group (group);
249   
250   return gtk_radio_menu_item_new (list);
251 }
252
253 /**
254  * gtk_radio_menu_item_new_with_mnemonic_from_widget:
255  * @group: An existing #GtkRadioMenuItem
256  * @label: the text of the button, with an underscore in front of the
257  *         mnemonic character
258  *
259  * Creates a new GtkRadioMenuItem containing a label. The label will be
260  * created using gtk_label_new_with_mnemonic(), so underscores in label
261  * indicate the mnemonic for the menu item.
262  *
263  * The new #GtkRadioMenuItem is added to the same group as @group.
264  *
265  * Return value: The new #GtkRadioMenuItem
266  * 
267  * Since: 2.4
268  **/
269 GtkWidget *
270 gtk_radio_menu_item_new_with_mnemonic_from_widget (GtkRadioMenuItem *group,
271                                                    const gchar *label)
272 {
273   GSList *list = NULL;
274
275   g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (group), NULL);
276
277   if (group)
278     list = gtk_radio_menu_item_get_group (group);
279
280   return gtk_radio_menu_item_new_with_mnemonic (list, label);
281 }
282
283 /**
284  * gtk_radio_menu_item_new_with_label_from_widget:
285  * @group: an existing #GtkRadioMenuItem 
286  * @label: the text for the label
287  *
288  * Creates a new GtkRadioMenuItem whose child is a simple GtkLabel.
289  * The new #GtkRadioMenuItem is added to the same group as @group.
290  *
291  * Return value: The new #GtkRadioMenuItem
292  * 
293  * Since: 2.4
294  **/
295 GtkWidget *
296 gtk_radio_menu_item_new_with_label_from_widget (GtkRadioMenuItem *group,
297                                                 const gchar *label)
298 {
299   GSList *list = NULL;
300
301   g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (group), NULL);
302
303   if (group)
304     list = gtk_radio_menu_item_get_group (group);
305
306   return gtk_radio_menu_item_new_with_label (list, label);
307 }
308
309 GSList*
310 gtk_radio_menu_item_get_group (GtkRadioMenuItem *radio_menu_item)
311 {
312   g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (radio_menu_item), NULL);
313
314   return radio_menu_item->group;
315 }
316
317
318 static void
319 gtk_radio_menu_item_class_init (GtkRadioMenuItemClass *klass)
320 {
321   GObjectClass *gobject_class;  
322   GtkObjectClass *object_class;
323   GtkMenuItemClass *menu_item_class;
324
325   gobject_class = G_OBJECT_CLASS (klass);
326   object_class = GTK_OBJECT_CLASS (klass);
327   menu_item_class = GTK_MENU_ITEM_CLASS (klass);
328
329   gobject_class->set_property = gtk_radio_menu_item_set_property;
330   gobject_class->get_property = gtk_radio_menu_item_get_property;
331
332   /**
333    * GtkRadioMenuItem:group:
334    * 
335    * The radio menu item whose group this widget belongs to.
336    * 
337    * Since: 2.8
338    */
339   g_object_class_install_property (gobject_class,
340                                    PROP_GROUP,
341                                    g_param_spec_object ("group",
342                                                         P_("Group"),
343                                                         P_("The radio menu item whose group this widget belongs to."),
344                                                         GTK_TYPE_RADIO_MENU_ITEM,
345                                                         GTK_PARAM_WRITABLE));
346
347   object_class->destroy = gtk_radio_menu_item_destroy;
348
349   menu_item_class->activate = gtk_radio_menu_item_activate;
350
351   /**
352    * GtkStyle::group-changed:
353    * @style: the object which received the signal
354    *
355    * Emitted when the group of radio menu items that a radio menu item belongs
356    * to changes. This is emitted when a radio menu item switches from
357    * being alone to being part of a group of 2 or more menu items, or
358    * vice-versa, and when a button is moved from one group of 2 or
359    * more menu items ton a different one, but not when the composition
360    * of the group that a menu item belongs to changes.
361    *
362    * Since: 2.4
363    */
364   group_changed_signal = g_signal_new (I_("group-changed"),
365                                        G_OBJECT_CLASS_TYPE (object_class),
366                                        G_SIGNAL_RUN_FIRST,
367                                        G_STRUCT_OFFSET (GtkRadioMenuItemClass, group_changed),
368                                        NULL, NULL,
369                                        _gtk_marshal_VOID__VOID,
370                                        G_TYPE_NONE, 0);
371 }
372
373 static void
374 gtk_radio_menu_item_init (GtkRadioMenuItem *radio_menu_item)
375 {
376   radio_menu_item->group = g_slist_prepend (NULL, radio_menu_item);
377   gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (radio_menu_item), TRUE);
378 }
379
380 static void
381 gtk_radio_menu_item_destroy (GtkObject *object)
382 {
383   GtkRadioMenuItem *radio_menu_item = GTK_RADIO_MENU_ITEM (object);
384   GtkWidget *old_group_singleton = NULL;
385   GtkRadioMenuItem *tmp_menu_item;
386   GSList *tmp_list;
387   gboolean was_in_group;
388
389   was_in_group = radio_menu_item->group && radio_menu_item->group->next;
390   
391   radio_menu_item->group = g_slist_remove (radio_menu_item->group,
392                                            radio_menu_item);
393   if (radio_menu_item->group && !radio_menu_item->group->next)
394     old_group_singleton = radio_menu_item->group->data;
395
396   tmp_list = radio_menu_item->group;
397
398   while (tmp_list)
399     {
400       tmp_menu_item = tmp_list->data;
401       tmp_list = tmp_list->next;
402
403       tmp_menu_item->group = radio_menu_item->group;
404     }
405
406   /* this radio menu item is no longer in the group */
407   radio_menu_item->group = NULL;
408   
409   if (old_group_singleton)
410     g_signal_emit (old_group_singleton, group_changed_signal, 0);
411   if (was_in_group)
412     g_signal_emit (radio_menu_item, group_changed_signal, 0);
413   
414   if (GTK_OBJECT_CLASS (gtk_radio_menu_item_parent_class)->destroy)
415     (* GTK_OBJECT_CLASS (gtk_radio_menu_item_parent_class)->destroy) (object);
416 }
417
418 static void
419 gtk_radio_menu_item_activate (GtkMenuItem *menu_item)
420 {
421   GtkRadioMenuItem *radio_menu_item = GTK_RADIO_MENU_ITEM (menu_item);
422   GtkCheckMenuItem *check_menu_item = GTK_CHECK_MENU_ITEM (menu_item);
423   GtkCheckMenuItem *tmp_menu_item;
424   GSList *tmp_list;
425   gint toggled;
426
427   toggled = FALSE;
428
429   if (check_menu_item->active)
430     {
431       tmp_menu_item = NULL;
432       tmp_list = radio_menu_item->group;
433
434       while (tmp_list)
435         {
436           tmp_menu_item = tmp_list->data;
437           tmp_list = tmp_list->next;
438
439           if (tmp_menu_item->active && (tmp_menu_item != check_menu_item))
440             break;
441
442           tmp_menu_item = NULL;
443         }
444
445       if (tmp_menu_item)
446         {
447           toggled = TRUE;
448           check_menu_item->active = !check_menu_item->active;
449         }
450     }
451   else
452     {
453       toggled = TRUE;
454       check_menu_item->active = !check_menu_item->active;
455
456       tmp_list = radio_menu_item->group;
457       while (tmp_list)
458         {
459           tmp_menu_item = tmp_list->data;
460           tmp_list = tmp_list->next;
461
462           if (tmp_menu_item->active && (tmp_menu_item != check_menu_item))
463             {
464               gtk_menu_item_activate (GTK_MENU_ITEM (tmp_menu_item));
465               break;
466             }
467         }
468     }
469
470   if (toggled)
471     gtk_check_menu_item_toggled (check_menu_item);
472
473   gtk_widget_queue_draw (GTK_WIDGET (radio_menu_item));
474 }
475
476 #define __GTK_RADIO_MENU_ITEM_C__
477 #include "gtkaliasdef.c"