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, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25 #include "config.h"
26
27 #include "gtkradiobutton.h"
28
29 #include "gtkcontainerprivate.h"
30 #include "gtkbuttonprivate.h"
31 #include "gtktogglebuttonprivate.h"
32 #include "gtkcheckbuttonprivate.h"
33 #include "gtklabel.h"
34 #include "gtkmarshalers.h"
35 #include "gtkprivate.h"
36 #include "gtkintl.h"
37 #include "a11y/gtkradiobuttonaccessible.h"
38 #include "gtkstylecontextprivate.h"
39
40 /**
41 * SECTION:gtkradiobutton
42 * @Short_description: A choice from multiple check buttons
43 * @Title: GtkRadioButton
44 * @See_also: #GtkComboBox
45 *
46 * A single radio button performs the same basic function as a #GtkCheckButton,
47 * as its position in the object hierarchy reflects. It is only when multiple
48 * radio buttons are grouped together that they become a different user
49 * interface component in their own right.
50 *
51 * Every radio button is a member of some group of radio buttons. When one is
52 * selected, all other radio buttons in the same group are deselected. A
53 * #GtkRadioButton is one way of giving the user a choice from many options.
54 *
55 * Radio button widgets are created with gtk_radio_button_new(), passing %NULL
56 * as the argument if this is the first radio button in a group. In subsequent
57 * calls, the group you wish to add this button to should be passed as an
58 * argument. Optionally, gtk_radio_button_new_with_label() can be used if you
59 * want a text label on the radio button.
60 *
61 * Alternatively, when adding widgets to an existing group of radio buttons,
62 * use gtk_radio_button_new_from_widget() with a #GtkRadioButton that already
63 * has a group assigned to it. The convenience function
64 * gtk_radio_button_new_with_label_from_widget() is also provided.
65 *
66 * To retrieve the group a #GtkRadioButton is assigned to, use
67 * gtk_radio_button_get_group().
68 *
69 * To remove a #GtkRadioButton from one group and make it part of a new one,
70 * use gtk_radio_button_set_group().
71 *
72 * The group list does not need to be freed, as each #GtkRadioButton will remove
73 * itself and its list item when it is destroyed.
74 *
75 * # CSS nodes
76 *
77 * |[<!-- language="plain" -->
78 * radiobutton
79 * ├── radio
80 * ╰── <child>
81 * ]|
82 *
83 * A GtkRadioButton with indicator (see gtk_toggle_button_set_mode()) has a
84 * main CSS node with name radiobutton and a subnode with name radio.
85 *
86 * |[<!-- language="plain" -->
87 * button.radio
88 * ├── radio
89 * ╰── <child>
90 * ]|
91 *
92 * A GtkRadioButton without indicator changes the name of its main node
93 * to button and adds a .radio style class to it. The subnode is invisible
94 * in this case.
95 *
96 * ## How to create a group of two radio buttons.
97 *
98 * |[<!-- language="C" -->
99 * void create_radio_buttons (void) {
100 *
101 * GtkWidget *window, *radio1, *radio2, *box, *entry;
102 * window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
103 * box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
104 * gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
105 *
106 * // Create a radio button with a GtkEntry widget
107 * radio1 = gtk_radio_button_new (NULL);
108 * entry = gtk_entry_new ();
109 * gtk_container_add (GTK_CONTAINER (radio1), entry);
110 *
111 *
112 * // Create a radio button with a label
113 * radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1),
114 * "I’m the second radio button.");
115 *
116 * // Pack them into a box, then show all the widgets
117 * gtk_box_pack_start (GTK_BOX (box), radio1);
118 * gtk_box_pack_start (GTK_BOX (box), radio2);
119 * gtk_container_add (GTK_CONTAINER (window), box);
120 * gtk_widget_show_all (window);
121 * return;
122 * }
123 * ]|
124 *
125 * When an unselected button in the group is clicked the clicked button
126 * receives the #GtkToggleButton::toggled signal, as does the previously
127 * selected button.
128 * Inside the #GtkToggleButton::toggled handler, gtk_toggle_button_get_active()
129 * can be used to determine if the button has been selected or deselected.
130 */
131
132
133 struct _GtkRadioButtonPrivate
134 {
135 GSList *group;
136 };
137
138 enum {
139 PROP_0,
140 PROP_GROUP,
141 LAST_PROP
142 };
143
144 static GParamSpec *radio_button_props[LAST_PROP] = { NULL, };
145
146 static void gtk_radio_button_destroy (GtkWidget *widget);
147 static gboolean gtk_radio_button_focus (GtkWidget *widget,
148 GtkDirectionType direction);
149 static void gtk_radio_button_clicked (GtkButton *button);
150 static void gtk_radio_button_set_property (GObject *object,
151 guint prop_id,
152 const GValue *value,
153 GParamSpec *pspec);
154 static void gtk_radio_button_get_property (GObject *object,
155 guint prop_id,
156 GValue *value,
157 GParamSpec *pspec);
158
159 G_DEFINE_TYPE_WITH_PRIVATE (GtkRadioButton, gtk_radio_button, GTK_TYPE_CHECK_BUTTON)
160
161 static guint group_changed_signal = 0;
162
163 static void
gtk_radio_button_class_init(GtkRadioButtonClass * class)164 gtk_radio_button_class_init (GtkRadioButtonClass *class)
165 {
166 GObjectClass *gobject_class;
167 GtkButtonClass *button_class;
168 GtkWidgetClass *widget_class;
169
170 gobject_class = G_OBJECT_CLASS (class);
171 widget_class = (GtkWidgetClass*) class;
172 button_class = (GtkButtonClass*) class;
173
174 gobject_class->set_property = gtk_radio_button_set_property;
175 gobject_class->get_property = gtk_radio_button_get_property;
176
177 /**
178 * GtkRadioButton:group:
179 *
180 * Sets a new group for a radio button.
181 */
182 radio_button_props[PROP_GROUP] =
183 g_param_spec_object ("group",
184 P_("Group"),
185 P_("The radio button whose group this widget belongs to."),
186 GTK_TYPE_RADIO_BUTTON,
187 GTK_PARAM_WRITABLE);
188
189 g_object_class_install_properties (gobject_class, LAST_PROP, radio_button_props);
190
191 widget_class->destroy = gtk_radio_button_destroy;
192 widget_class->focus = gtk_radio_button_focus;
193
194 button_class->clicked = gtk_radio_button_clicked;
195
196 class->group_changed = NULL;
197
198 /**
199 * GtkRadioButton::group-changed:
200 * @button: the object which received the signal
201 *
202 * Emitted when the group of radio buttons that a radio button belongs
203 * to changes. This is emitted when a radio button switches from
204 * being alone to being part of a group of 2 or more buttons, or
205 * vice-versa, and when a button is moved from one group of 2 or
206 * more buttons to a different one, but not when the composition
207 * of the group that a button belongs to changes.
208 *
209 * Since: 2.4
210 */
211 group_changed_signal = g_signal_new (I_("group-changed"),
212 G_OBJECT_CLASS_TYPE (gobject_class),
213 G_SIGNAL_RUN_FIRST,
214 G_STRUCT_OFFSET (GtkRadioButtonClass, group_changed),
215 NULL, NULL,
216 NULL,
217 G_TYPE_NONE, 0);
218
219 gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RADIO_BUTTON_ACCESSIBLE);
220 gtk_widget_class_set_css_name (widget_class, "radiobutton");
221 }
222
223 static void
gtk_radio_button_init(GtkRadioButton * radio_button)224 gtk_radio_button_init (GtkRadioButton *radio_button)
225 {
226 GtkRadioButtonPrivate *priv;
227 GtkCssNode *css_node;
228
229 radio_button->priv = gtk_radio_button_get_instance_private (radio_button);
230 priv = radio_button->priv;
231
232 gtk_widget_set_receives_default (GTK_WIDGET (radio_button), FALSE);
233
234 _gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), TRUE);
235
236 priv->group = g_slist_prepend (NULL, radio_button);
237
238 css_node = gtk_check_button_get_indicator_node (GTK_CHECK_BUTTON (radio_button));
239 gtk_css_node_set_name (css_node, I_("radio"));
240 }
241
242 static void
gtk_radio_button_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)243 gtk_radio_button_set_property (GObject *object,
244 guint prop_id,
245 const GValue *value,
246 GParamSpec *pspec)
247 {
248 GtkRadioButton *radio_button;
249
250 radio_button = GTK_RADIO_BUTTON (object);
251
252 switch (prop_id)
253 {
254 GSList *slist;
255 GtkRadioButton *button;
256
257 case PROP_GROUP:
258 button = g_value_get_object (value);
259
260 if (button)
261 slist = gtk_radio_button_get_group (button);
262 else
263 slist = NULL;
264 gtk_radio_button_set_group (radio_button, slist);
265 break;
266 default:
267 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
268 break;
269 }
270 }
271
272 static void
gtk_radio_button_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)273 gtk_radio_button_get_property (GObject *object,
274 guint prop_id,
275 GValue *value,
276 GParamSpec *pspec)
277 {
278 switch (prop_id)
279 {
280 default:
281 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
282 break;
283 }
284 }
285
286 /**
287 * gtk_radio_button_set_group:
288 * @radio_button: a #GtkRadioButton.
289 * @group: (element-type GtkRadioButton) (allow-none): an existing radio
290 * button group, such as one returned from gtk_radio_button_get_group(), or %NULL.
291 *
292 * Sets a #GtkRadioButton’s group. It should be noted that this does not change
293 * the layout of your interface in any way, so if you are changing the group,
294 * it is likely you will need to re-arrange the user interface to reflect these
295 * changes.
296 */
297 void
gtk_radio_button_set_group(GtkRadioButton * radio_button,GSList * group)298 gtk_radio_button_set_group (GtkRadioButton *radio_button,
299 GSList *group)
300 {
301 GtkRadioButtonPrivate *priv;
302 GtkWidget *old_group_singleton = NULL;
303 GtkWidget *new_group_singleton = NULL;
304
305 g_return_if_fail (GTK_IS_RADIO_BUTTON (radio_button));
306
307 if (g_slist_find (group, radio_button))
308 return;
309
310 priv = radio_button->priv;
311
312 if (priv->group)
313 {
314 GSList *slist;
315
316 priv->group = g_slist_remove (priv->group, radio_button);
317
318 if (priv->group && !priv->group->next)
319 old_group_singleton = g_object_ref (priv->group->data);
320
321 for (slist = priv->group; slist; slist = slist->next)
322 {
323 GtkRadioButton *tmp_button;
324
325 tmp_button = slist->data;
326
327 tmp_button->priv->group = priv->group;
328 }
329 }
330
331 if (group && !group->next)
332 new_group_singleton = g_object_ref (group->data);
333
334 priv->group = g_slist_prepend (group, radio_button);
335
336 if (group)
337 {
338 GSList *slist;
339
340 for (slist = group; slist; slist = slist->next)
341 {
342 GtkRadioButton *tmp_button;
343
344 tmp_button = slist->data;
345
346 tmp_button->priv->group = priv->group;
347 }
348 }
349
350 g_object_ref (radio_button);
351
352 g_object_notify_by_pspec (G_OBJECT (radio_button), radio_button_props[PROP_GROUP]);
353 g_signal_emit (radio_button, group_changed_signal, 0);
354 if (old_group_singleton)
355 {
356 g_signal_emit (old_group_singleton, group_changed_signal, 0);
357 g_object_unref (old_group_singleton);
358 }
359 if (new_group_singleton)
360 {
361 g_signal_emit (new_group_singleton, group_changed_signal, 0);
362 g_object_unref (new_group_singleton);
363 }
364
365 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), group == NULL);
366
367 g_object_unref (radio_button);
368 }
369
370 /**
371 * gtk_radio_button_join_group:
372 * @radio_button: the #GtkRadioButton object
373 * @group_source: (allow-none): a radio button object whos group we are
374 * joining, or %NULL to remove the radio button from its group
375 *
376 * Joins a #GtkRadioButton object to the group of another #GtkRadioButton object
377 *
378 * Use this in language bindings instead of the gtk_radio_button_get_group()
379 * and gtk_radio_button_set_group() methods
380 *
381 * A common way to set up a group of radio buttons is the following:
382 * |[<!-- language="C" -->
383 * GtkRadioButton *radio_button;
384 * GtkRadioButton *last_button;
385 *
386 * while (some_condition)
387 * {
388 * radio_button = gtk_radio_button_new (NULL);
389 *
390 * gtk_radio_button_join_group (radio_button, last_button);
391 * last_button = radio_button;
392 * }
393 * ]|
394 *
395 * Since: 3.0
396 */
397 void
gtk_radio_button_join_group(GtkRadioButton * radio_button,GtkRadioButton * group_source)398 gtk_radio_button_join_group (GtkRadioButton *radio_button,
399 GtkRadioButton *group_source)
400 {
401 g_return_if_fail (GTK_IS_RADIO_BUTTON (radio_button));
402 g_return_if_fail (group_source == NULL || GTK_IS_RADIO_BUTTON (group_source));
403
404 if (group_source)
405 {
406 GSList *group;
407 group = gtk_radio_button_get_group (group_source);
408
409 if (!group)
410 {
411 /* if we are not already part of a group we need to set up a new one
412 and then get the newly created group */
413 gtk_radio_button_set_group (group_source, NULL);
414 group = gtk_radio_button_get_group (group_source);
415 }
416
417 gtk_radio_button_set_group (radio_button, group);
418 }
419 else
420 {
421 gtk_radio_button_set_group (radio_button, NULL);
422 }
423 }
424
425 /**
426 * gtk_radio_button_new:
427 * @group: (element-type GtkRadioButton) (allow-none): an existing
428 * radio button group, or %NULL if you are creating a new group.
429 *
430 * Creates a new #GtkRadioButton. To be of any practical value, a widget should
431 * then be packed into the radio button.
432 *
433 * Returns: a new radio button
434 */
435 GtkWidget*
gtk_radio_button_new(GSList * group)436 gtk_radio_button_new (GSList *group)
437 {
438 GtkRadioButton *radio_button;
439
440 radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON, NULL);
441
442 if (group)
443 gtk_radio_button_set_group (radio_button, group);
444
445 return GTK_WIDGET (radio_button);
446 }
447
448 /**
449 * gtk_radio_button_new_with_label:
450 * @group: (element-type GtkRadioButton) (allow-none): an existing
451 * radio button group, or %NULL if you are creating a new group.
452 * @label: the text label to display next to the radio button.
453 *
454 * Creates a new #GtkRadioButton with a text label.
455 *
456 * Returns: a new radio button.
457 */
458 GtkWidget*
gtk_radio_button_new_with_label(GSList * group,const gchar * label)459 gtk_radio_button_new_with_label (GSList *group,
460 const gchar *label)
461 {
462 GtkWidget *radio_button;
463
464 radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON, "label", label, NULL) ;
465
466 if (group)
467 gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_button), group);
468
469 return radio_button;
470 }
471
472
473 /**
474 * gtk_radio_button_new_with_mnemonic:
475 * @group: (element-type GtkRadioButton) (allow-none): the radio button
476 * group, or %NULL
477 * @label: the text of the button, with an underscore in front of the
478 * mnemonic character
479 *
480 * Creates a new #GtkRadioButton containing a label, adding it to the same
481 * group as @group. The label will be created using
482 * gtk_label_new_with_mnemonic(), so underscores in @label indicate the
483 * mnemonic for the button.
484 *
485 * Returns: a new #GtkRadioButton
486 */
487 GtkWidget*
gtk_radio_button_new_with_mnemonic(GSList * group,const gchar * label)488 gtk_radio_button_new_with_mnemonic (GSList *group,
489 const gchar *label)
490 {
491 GtkWidget *radio_button;
492
493 radio_button = g_object_new (GTK_TYPE_RADIO_BUTTON,
494 "label", label,
495 "use-underline", TRUE,
496 NULL);
497
498 if (group)
499 gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_button), group);
500
501 return radio_button;
502 }
503
504 /**
505 * gtk_radio_button_new_from_widget: (constructor)
506 * @radio_group_member: (allow-none): an existing #GtkRadioButton.
507 *
508 * Creates a new #GtkRadioButton, adding it to the same group as
509 * @radio_group_member. As with gtk_radio_button_new(), a widget
510 * should be packed into the radio button.
511 *
512 * Returns: (transfer none): a new radio button.
513 */
514 GtkWidget*
gtk_radio_button_new_from_widget(GtkRadioButton * radio_group_member)515 gtk_radio_button_new_from_widget (GtkRadioButton *radio_group_member)
516 {
517 GSList *l = NULL;
518 if (radio_group_member)
519 l = gtk_radio_button_get_group (radio_group_member);
520 return gtk_radio_button_new (l);
521 }
522
523 /**
524 * gtk_radio_button_new_with_label_from_widget: (constructor)
525 * @radio_group_member: (allow-none): widget to get radio group from or %NULL
526 * @label: a text string to display next to the radio button.
527 *
528 * Creates a new #GtkRadioButton with a text label, adding it to
529 * the same group as @radio_group_member.
530 *
531 * Returns: (transfer none): a new radio button.
532 */
533 GtkWidget*
gtk_radio_button_new_with_label_from_widget(GtkRadioButton * radio_group_member,const gchar * label)534 gtk_radio_button_new_with_label_from_widget (GtkRadioButton *radio_group_member,
535 const gchar *label)
536 {
537 GSList *l = NULL;
538 if (radio_group_member)
539 l = gtk_radio_button_get_group (radio_group_member);
540 return gtk_radio_button_new_with_label (l, label);
541 }
542
543 /**
544 * gtk_radio_button_new_with_mnemonic_from_widget: (constructor)
545 * @radio_group_member: (allow-none): widget to get radio group from or %NULL
546 * @label: the text of the button, with an underscore in front of the
547 * mnemonic character
548 *
549 * Creates a new #GtkRadioButton containing a label. The label
550 * will be created using gtk_label_new_with_mnemonic(), so underscores
551 * in @label indicate the mnemonic for the button.
552 *
553 * Returns: (transfer none): a new #GtkRadioButton
554 **/
555 GtkWidget*
gtk_radio_button_new_with_mnemonic_from_widget(GtkRadioButton * radio_group_member,const gchar * label)556 gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *radio_group_member,
557 const gchar *label)
558 {
559 GSList *l = NULL;
560 if (radio_group_member)
561 l = gtk_radio_button_get_group (radio_group_member);
562 return gtk_radio_button_new_with_mnemonic (l, label);
563 }
564
565
566 /**
567 * gtk_radio_button_get_group:
568 * @radio_button: a #GtkRadioButton.
569 *
570 * Retrieves the group assigned to a radio button.
571 *
572 * Returns: (element-type GtkRadioButton) (transfer none): a linked list
573 * containing all the radio buttons in the same group
574 * as @radio_button. The returned list is owned by the radio button
575 * and must not be modified or freed.
576 */
577 GSList*
gtk_radio_button_get_group(GtkRadioButton * radio_button)578 gtk_radio_button_get_group (GtkRadioButton *radio_button)
579 {
580 g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_button), NULL);
581
582 return radio_button->priv->group;
583 }
584
585
586 static void
gtk_radio_button_destroy(GtkWidget * widget)587 gtk_radio_button_destroy (GtkWidget *widget)
588 {
589 GtkWidget *old_group_singleton = NULL;
590 GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget);
591 GtkRadioButtonPrivate *priv = radio_button->priv;
592 GtkRadioButton *tmp_button;
593 GSList *tmp_list;
594 gboolean was_in_group;
595
596 was_in_group = priv->group && priv->group->next;
597
598 priv->group = g_slist_remove (priv->group, radio_button);
599 if (priv->group && !priv->group->next)
600 old_group_singleton = priv->group->data;
601
602 tmp_list = priv->group;
603
604 while (tmp_list)
605 {
606 tmp_button = tmp_list->data;
607 tmp_list = tmp_list->next;
608
609 tmp_button->priv->group = priv->group;
610 }
611
612 /* this button is no longer in the group */
613 priv->group = NULL;
614
615 if (old_group_singleton)
616 g_signal_emit (old_group_singleton, group_changed_signal, 0);
617 if (was_in_group)
618 g_signal_emit (radio_button, group_changed_signal, 0);
619
620 GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->destroy (widget);
621 }
622
623 static gboolean
gtk_radio_button_focus(GtkWidget * widget,GtkDirectionType direction)624 gtk_radio_button_focus (GtkWidget *widget,
625 GtkDirectionType direction)
626 {
627 GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget);
628 GtkRadioButtonPrivate *priv = radio_button->priv;
629 GSList *tmp_slist;
630
631 /* Radio buttons with draw_indicator unset focus "normally", since
632 * they look like buttons to the user.
633 */
634 if (!gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON (widget)))
635 return GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->focus (widget, direction);
636
637 if (gtk_widget_is_focus (widget))
638 {
639 GList *children, *focus_list, *tmp_list;
640 GtkWidget *toplevel;
641 GtkWidget *new_focus = NULL;
642 GSList *l;
643
644 if (direction == GTK_DIR_TAB_FORWARD ||
645 direction == GTK_DIR_TAB_BACKWARD)
646 return FALSE;
647
648 toplevel = gtk_widget_get_toplevel (widget);
649 children = NULL;
650 for (l = priv->group; l; l = l->next)
651 children = g_list_prepend (children, l->data);
652
653 focus_list = _gtk_container_focus_sort (GTK_CONTAINER (toplevel), children, direction, widget);
654 tmp_list = g_list_find (focus_list, widget);
655
656 if (tmp_list)
657 {
658 tmp_list = tmp_list->next;
659
660 while (tmp_list)
661 {
662 GtkWidget *child = tmp_list->data;
663
664 if (gtk_widget_get_mapped (child) && gtk_widget_is_sensitive (child))
665 {
666 new_focus = child;
667 break;
668 }
669
670 tmp_list = tmp_list->next;
671 }
672 }
673
674 if (!new_focus)
675 {
676 tmp_list = focus_list;
677
678 while (tmp_list)
679 {
680 GtkWidget *child = tmp_list->data;
681
682 if (gtk_widget_get_mapped (child) && gtk_widget_is_sensitive (child))
683 {
684 new_focus = child;
685 break;
686 }
687
688 tmp_list = tmp_list->next;
689 }
690 }
691
692 g_list_free (focus_list);
693 g_list_free (children);
694
695 if (new_focus)
696 {
697 gtk_widget_grab_focus (new_focus);
698
699 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
700 }
701
702 return TRUE;
703 }
704 else
705 {
706 GtkRadioButton *selected_button = NULL;
707
708 /* We accept the focus if, we don't have the focus and
709 * - we are the currently active button in the group
710 * - there is no currently active radio button.
711 */
712 tmp_slist = priv->group;
713 while (tmp_slist)
714 {
715 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tmp_slist->data)) &&
716 gtk_widget_get_visible (tmp_slist->data))
717 selected_button = tmp_slist->data;
718 tmp_slist = tmp_slist->next;
719 }
720
721 if (selected_button && selected_button != radio_button)
722 return FALSE;
723
724 gtk_widget_grab_focus (widget);
725 return TRUE;
726 }
727 }
728
729 static void
gtk_radio_button_clicked(GtkButton * button)730 gtk_radio_button_clicked (GtkButton *button)
731 {
732 GtkRadioButton *radio_button = GTK_RADIO_BUTTON (button);
733 GtkRadioButtonPrivate *priv = radio_button->priv;
734 GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
735 GtkToggleButton *tmp_button;
736 GSList *tmp_list;
737 gint toggled;
738
739 toggled = FALSE;
740
741 g_object_ref (GTK_WIDGET (button));
742
743 if (gtk_toggle_button_get_active (toggle_button))
744 {
745 tmp_button = NULL;
746 tmp_list = priv->group;
747
748 while (tmp_list)
749 {
750 tmp_button = tmp_list->data;
751 tmp_list = tmp_list->next;
752
753 if (tmp_button != toggle_button &&
754 gtk_toggle_button_get_active (tmp_button))
755 break;
756
757 tmp_button = NULL;
758 }
759
760 if (tmp_button)
761 {
762 toggled = TRUE;
763 _gtk_toggle_button_set_active (toggle_button,
764 !gtk_toggle_button_get_active (toggle_button));
765 }
766 }
767 else
768 {
769 toggled = TRUE;
770 _gtk_toggle_button_set_active (toggle_button,
771 !gtk_toggle_button_get_active (toggle_button));
772
773 tmp_list = priv->group;
774 while (tmp_list)
775 {
776 tmp_button = tmp_list->data;
777 tmp_list = tmp_list->next;
778
779 if (gtk_toggle_button_get_active (tmp_button) && (tmp_button != toggle_button))
780 {
781 gtk_button_clicked (GTK_BUTTON (tmp_button));
782 break;
783 }
784 }
785 }
786
787 if (toggled)
788 {
789 gtk_toggle_button_toggled (toggle_button);
790
791 g_object_notify (G_OBJECT (toggle_button), "active");
792 }
793
794 gtk_widget_queue_draw (GTK_WIDGET (button));
795
796 g_object_unref (button);
797 }
798