Add GtkRadioGroup?



One thing I remember being really confused about when learning gtk+ is
the GSList * usage for the group in GtkRadioButton. We have added some
scaffolding now that makes this somewhat better, but whats the chance of
actually fixing this by adding a real GtkRadioGroup class and using it
for radio buttons/menus/toolitems/actions?

It'll be a slight api break, but it should be trivial to fix up any
problems and the compiler should catch them all.

In addition to removing the GSList crap we can also add proper signals
for when the group contents changes (added/removed items) and a single
signal for the group when we get a new active item.

Below is a small example patch, mostly just compile tested. If there is
interest in doing this I'll try to find some time to do a full patch.

Opinions?

diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 0774710..4345413 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -258,6 +258,7 @@ gtk_public_h_sources =          \
 	gtkprogressbar.h	\
 	gtkradioaction.h	\
 	gtkradiobutton.h	\
+	gtkradiogroup.h		\
 	gtkradiomenuitem.h	\
 	gtkradiotoolbutton.h	\
 	gtkrange.h		\
@@ -378,6 +379,7 @@ gtk_private_h_sources =		\
 	gtkprintoperation-private.h\
 	gtkprintutils.h		\
 	gtkprivate.h		\
+	gtkradiogroupprivate.h	\
 	gtkrbtree.h		\
 	gtkrecentchooserdefault.h \
 	gtkrecentchooserprivate.h \
@@ -530,6 +532,7 @@ gtk_base_c_sources =            \
 	gtkprogressbar.c	\
 	gtkradioaction.c	\
 	gtkradiobutton.c	\
+	gtkradiogroup.c		\
 	gtkradiomenuitem.c	\
 	gtkradiotoolbutton.c	\
 	gtkrange.c		\
diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c
index 7a51b95..3baf611 100644
--- a/gtk/gtkradiobutton.c
+++ b/gtk/gtkradiobutton.c
@@ -28,6 +28,7 @@
 #include "gtklabel.h"
 #include "gtkmarshalers.h"
 #include "gtkradiobutton.h"
+#include "gtkradiogroupprivate.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 
@@ -105,7 +106,7 @@
 
 struct _GtkRadioButtonPrivate
 {
-  GSList *group;
+  GtkRadioGroup *group;
 };
 
 enum {
@@ -211,7 +212,8 @@ gtk_radio_button_init (GtkRadioButton *radio_button)
 
   GTK_BUTTON (radio_button)->depress_on_activate = FALSE;
 
-  priv->group = g_slist_prepend (NULL, radio_button);
+  priv->group = g_object_ref_sink (gtk_radio_group_new ());
+  _gtk_radio_group_add_item (priv->group, G_OBJECT (radio_button));
 
   _gtk_button_set_depressed (GTK_BUTTON (radio_button), TRUE);
   gtk_widget_set_state (GTK_WIDGET (radio_button), GTK_STATE_ACTIVE);
@@ -229,17 +231,17 @@ gtk_radio_button_set_property (GObject      *object,
 
   switch (prop_id)
     {
-      GSList *slist;
+      GtkRadioGroup *group;
       GtkRadioButton *button;
 
     case PROP_GROUP:
         button = g_value_get_object (value);
 
       if (button)
-	slist = gtk_radio_button_get_group (button);
+	group = gtk_radio_button_get_group (button);
       else
-	slist = NULL;
-      gtk_radio_button_set_group (radio_button, slist);
+	group = NULL;
+      gtk_radio_button_set_group (radio_button, group);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -264,8 +266,9 @@ gtk_radio_button_get_property (GObject    *object,
 /**
  * gtk_radio_button_set_group:
  * @radio_button: a #GtkRadioButton.
- * @group: (transfer none) (element-type GtkRadioButton): an existing radio
- *     button group, such as one returned from gtk_radio_button_get_group().
+ * @group: a ¤GtkRadioGroup: an existing radio
+ *     button group, such as one returned from gtk_radio_button_get_group(), or %NULL
+ *     to create a new group for the button.
  *
  * Sets a #GtkRadioButton's group. It should be noted that this does not change
  * the layout of your interface in any way, so if you are changing the group,
@@ -274,57 +277,40 @@ gtk_radio_button_get_property (GObject    *object,
  */
 void
 gtk_radio_button_set_group (GtkRadioButton *radio_button,
-			    GSList         *group)
+			    GtkRadioGroup *group)
 {
   GtkRadioButtonPrivate *priv;
-  GtkWidget *old_group_singleton = NULL;
-  GtkWidget *new_group_singleton = NULL;
+  GObject *old_group_singleton;
+  GObject *new_group_singleton;
+  GObject *old_group_active;
 
   g_return_if_fail (GTK_IS_RADIO_BUTTON (radio_button));
-  g_return_if_fail (!g_slist_find (group, radio_button));
 
   priv = radio_button->priv;
 
-  if (priv->group)
-    {
-      GSList *slist;
+  if (priv->group == group)
+    return;
 
-      priv->group = g_slist_remove (priv->group, radio_button);
+  if (group == NULL)
+    group = gtk_radio_group_new ();
 
-      if (priv->group && !priv->group->next)
-	old_group_singleton = g_object_ref (priv->group->data);
+  _gtk_radio_group_remove_item (priv->group, G_OBJECT (radio_button));
+  old_group_singleton = _gtk_radio_group_get_singleton (priv->group);
 
-      for (slist = priv->group; slist; slist = slist->next)
-	{
-	  GtkRadioButton *tmp_button;
-	  
-	  tmp_button = slist->data;
+  /* Ensure some widget is active in the old group */
+  old_group_active = gtk_radio_group_get_active_item (priv->group);
+  if (old_group_active)
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (old_group_active), TRUE);
 
-	  tmp_button->priv->group = priv->group;
-	}
-    }
-  
-  if (group && !group->next)
-    new_group_singleton = g_object_ref (group->data);
+  g_object_unref (priv->group);
 
-  priv->group = g_slist_prepend (group, radio_button);
+  priv->group = g_object_ref_sink (group);
+  new_group_singleton = _gtk_radio_group_get_singleton (group);
 
-  if (group)
-    {
-      GSList *slist;
-      
-      for (slist = group; slist; slist = slist->next)
-	{
-	  GtkRadioButton *tmp_button;
-	  
-	  tmp_button = slist->data;
-
-	  tmp_button->priv->group = priv->group;
-	}
-    }
+  _gtk_radio_group_add_item (group, G_OBJECT (radio_button));
 
   g_object_ref (radio_button);
-  
+
   g_object_notify (G_OBJECT (radio_button), "group");
   g_signal_emit (radio_button, group_changed_signal, 0);
   if (old_group_singleton)
@@ -338,7 +324,8 @@ gtk_radio_button_set_group (GtkRadioButton *radio_button,
       g_object_unref (new_group_singleton);
     }
 
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button), group == NULL);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_button),
+				gtk_radio_group_get_active_item (group) == G_OBJECT (radio_button));
 
   g_object_unref (radio_button);
 }
@@ -379,17 +366,8 @@ gtk_radio_button_join_group (GtkRadioButton *radio_button,
 
   if (group_source)
     {
-      GSList *group;
+      GtkRadioGroup *group;
       group = gtk_radio_button_get_group (group_source);
-
-      if (!group)
-        {
-          /* if we are not already part of a group we need to set up a new one
-             and then get the newly created group */
-          gtk_radio_button_set_group (group_source, NULL);
-          group = gtk_radio_button_get_group (group_source);
-        }
-
       gtk_radio_button_set_group (radio_button, group);
     }
   else
@@ -408,7 +386,7 @@ gtk_radio_button_join_group (GtkRadioButton *radio_button,
  * Returns: a new radio button
  */
 GtkWidget*
-gtk_radio_button_new (GSList *group)
+gtk_radio_button_new (GtkRadioGroup *group)
 {
   GtkRadioButton *radio_button;
 
@@ -431,7 +409,7 @@ gtk_radio_button_new (GSList *group)
  * Returns: (transfer full): a new radio button.
  */
 GtkWidget*
-gtk_radio_button_new_with_label (GSList      *group,
+gtk_radio_button_new_with_label (GtkRadioGroup *group,
 				 const gchar *label)
 {
   GtkWidget *radio_button;
@@ -459,7 +437,7 @@ gtk_radio_button_new_with_label (GSList      *group,
  * Returns: (transfer full): a new #GtkRadioButton
  */
 GtkWidget*
-gtk_radio_button_new_with_mnemonic (GSList      *group,
+gtk_radio_button_new_with_mnemonic (GtkRadioGroup *group,
 				    const gchar *label)
 {
   GtkWidget *radio_button;
@@ -488,10 +466,10 @@ gtk_radio_button_new_with_mnemonic (GSList      *group,
 GtkWidget*
 gtk_radio_button_new_from_widget (GtkRadioButton *radio_group_member)
 {
-  GSList *l = NULL;
+  GtkRadioGroup *group = NULL;
   if (radio_group_member)
-    l = gtk_radio_button_get_group (radio_group_member);
-  return gtk_radio_button_new (l);
+    group = gtk_radio_button_get_group (radio_group_member);
+  return gtk_radio_button_new (group);
 }
 
 /**
@@ -508,10 +486,10 @@ GtkWidget*
 gtk_radio_button_new_with_label_from_widget (GtkRadioButton *radio_group_member,
 					     const gchar    *label)
 {
-  GSList *l = NULL;
+  GtkRadioGroup *group = NULL;
   if (radio_group_member)
-    l = gtk_radio_button_get_group (radio_group_member);
-  return gtk_radio_button_new_with_label (l, label);
+    group = gtk_radio_button_get_group (radio_group_member);
+  return gtk_radio_button_new_with_label (group, label);
 }
 
 /**
@@ -530,10 +508,10 @@ GtkWidget*
 gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *radio_group_member,
 					        const gchar    *label)
 {
-  GSList *l = NULL;
+  GtkRadioGroup *group = NULL;
   if (radio_group_member)
-    l = gtk_radio_button_get_group (radio_group_member);
-  return gtk_radio_button_new_with_mnemonic (l, label);
+    group = gtk_radio_button_get_group (radio_group_member);
+  return gtk_radio_button_new_with_mnemonic (group, label);
 }
 
 
@@ -548,7 +526,7 @@ gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *radio_group_memb
  * as @radio_button. The returned list is owned by the radio button
  * and must not be modified or freed.
  */
-GSList*
+GtkRadioGroup *
 gtk_radio_button_get_group (GtkRadioButton *radio_button)
 {
   g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_button), NULL);
@@ -560,32 +538,28 @@ gtk_radio_button_get_group (GtkRadioButton *radio_button)
 static void
 gtk_radio_button_destroy (GtkWidget *widget)
 {
-  GtkWidget *old_group_singleton = NULL;
+  GObject *old_group_singleton = NULL;
+  GObject *old_group_active;
   GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget);
   GtkRadioButtonPrivate *priv = radio_button->priv;
-  GtkRadioButton *tmp_button;
-  GSList *tmp_list;
-  gboolean was_in_group;
-
-  was_in_group = priv->group && priv->group->next;
-
-  priv->group = g_slist_remove (priv->group, radio_button);
-  if (priv->group && !priv->group->next)
-    old_group_singleton = priv->group->data;
-
-  tmp_list = priv->group;
+  gboolean was_in_group = FALSE;
 
-  while (tmp_list)
+  if (priv->group)
     {
-      tmp_button = tmp_list->data;
-      tmp_list = tmp_list->next;
-
-      tmp_button->priv->group = priv->group;
+      _gtk_radio_group_remove_item (priv->group, G_OBJECT (radio_button));
+      was_in_group = !_gtk_radio_group_is_empty (priv->group);
+      old_group_singleton = _gtk_radio_group_get_singleton (priv->group);
+
+      /* Ensure some widget is active in the old group */
+      old_group_active = gtk_radio_group_get_active_item (priv->group);
+      if (old_group_active)
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (old_group_active), TRUE);
+
+      /* this button is no longer in the group */
+      g_object_unref (priv->group);
+      priv->group = NULL;
     }
 
-  /* this button is no longer in the group */
-  priv->group = NULL;
-
   if (old_group_singleton)
     g_signal_emit (old_group_singleton, group_changed_signal, 0);
   if (was_in_group)
@@ -647,7 +621,6 @@ gtk_radio_button_focus (GtkWidget         *widget,
 {
   GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget);
   GtkRadioButtonPrivate *priv = radio_button->priv;
-  GSList *tmp_slist;
 
   /* Radio buttons with draw_indicator unset focus "normally", since
    * they look like buttons to the user.
@@ -668,12 +641,12 @@ gtk_radio_button_focus (GtkWidget         *widget,
 	{
 	case GTK_DIR_LEFT:
 	case GTK_DIR_RIGHT:
-	  focus_list = g_slist_copy (priv->group);
+	  focus_list = g_slist_copy (gtk_radio_group_get_items (priv->group));
 	  focus_list = g_slist_sort_with_data (focus_list, left_right_compare, toplevel);
 	  break;
 	case GTK_DIR_UP:
 	case GTK_DIR_DOWN:
-	  focus_list = g_slist_copy (priv->group);
+	  focus_list = g_slist_copy (gtk_radio_group_get_items (priv->group));
 	  focus_list = g_slist_sort_with_data (focus_list, up_down_compare, toplevel);
 	  break;
 	case GTK_DIR_TAB_FORWARD:
@@ -756,22 +729,15 @@ gtk_radio_button_focus (GtkWidget         *widget,
     }
   else
     {
-      GtkRadioButton *selected_button = NULL;
-      
+      GObject *selected_button;
+
       /* We accept the focus if, we don't have the focus and
        *  - we are the currently active button in the group
        *  - there is no currently active radio button.
        */
-      
-      tmp_slist = priv->group;
-      while (tmp_slist)
-	{
-	  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tmp_slist->data)))
-	    selected_button = tmp_slist->data;
-	  tmp_slist = tmp_slist->next;
-	}
-      
-      if (selected_button && selected_button != radio_button)
+
+      selected_button = gtk_radio_group_get_active_item (priv->group);
+      if (selected_button && selected_button != G_OBJECT (radio_button))
 	return FALSE;
 
       gtk_widget_grab_focus (widget);
@@ -785,9 +751,8 @@ gtk_radio_button_clicked (GtkButton *button)
   GtkRadioButton *radio_button = GTK_RADIO_BUTTON (button);
   GtkRadioButtonPrivate *priv = radio_button->priv;
   GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
-  GtkToggleButton *tmp_button;
+  GObject *active_item;
   GtkStateType new_state;
-  GSList *tmp_list;
   gint toggled;
   gboolean depressed;
 
@@ -797,22 +762,9 @@ gtk_radio_button_clicked (GtkButton *button)
 
   if (gtk_toggle_button_get_active (toggle_button))
     {
-      tmp_button = NULL;
-      tmp_list = priv->group;
-
-      while (tmp_list)
-	{
-	  tmp_button = tmp_list->data;
-	  tmp_list = tmp_list->next;
-
-          if (tmp_button != toggle_button &&
-              gtk_toggle_button_get_active (tmp_button))
-	    break;
+      active_item = gtk_radio_group_get_active_item (priv->group);
 
-	  tmp_button = NULL;
-	}
-
-      if (!tmp_button)
+      if (active_item == NULL || active_item == G_OBJECT (button))
 	{
 	  new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
 	}
@@ -830,18 +782,10 @@ gtk_radio_button_clicked (GtkButton *button)
       _gtk_toggle_button_set_active (toggle_button,
                                      !gtk_toggle_button_get_active (toggle_button));
 
-      tmp_list = priv->group;
-      while (tmp_list)
-	{
-	  tmp_button = tmp_list->data;
-	  tmp_list = tmp_list->next;
-
-	  if (gtk_toggle_button_get_active (tmp_button) && (tmp_button != toggle_button))
-	    {
-	      gtk_button_clicked (GTK_BUTTON (tmp_button));
-	      break;
-	    }
-	}
+      active_item = gtk_radio_group_get_active_item (priv->group);
+      _gtk_radio_group_set_active_item (priv->group, G_OBJECT (toggle_button));
+      if (active_item != G_OBJECT (toggle_button))
+	gtk_button_clicked (GTK_BUTTON (active_item));
 
       new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
     }
diff --git a/gtk/gtkradiobutton.h b/gtk/gtkradiobutton.h
index 2fe40c6..1ee2454 100644
--- a/gtk/gtkradiobutton.h
+++ b/gtk/gtkradiobutton.h
@@ -33,6 +33,7 @@
 
 
 #include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkradiogroup.h>
 
 
 G_BEGIN_DECLS
@@ -74,21 +75,22 @@ struct _GtkRadioButtonClass
 
 GType	   gtk_radio_button_get_type	     (void) G_GNUC_CONST;
 
-GtkWidget* gtk_radio_button_new                           (GSList         *group);
-GtkWidget* gtk_radio_button_new_from_widget               (GtkRadioButton *radio_group_member);
-GtkWidget* gtk_radio_button_new_with_label                (GSList         *group,
-                                                           const gchar    *label);
-GtkWidget* gtk_radio_button_new_with_label_from_widget    (GtkRadioButton *radio_group_member,
-                                                           const gchar    *label);
-GtkWidget* gtk_radio_button_new_with_mnemonic             (GSList         *group,
-                                                           const gchar    *label);
-GtkWidget* gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *radio_group_member,
-                                                           const gchar    *label);
-GSList*    gtk_radio_button_get_group                     (GtkRadioButton *radio_button);
-void       gtk_radio_button_set_group                     (GtkRadioButton *radio_button,
-                                                           GSList         *group);
-void            gtk_radio_button_join_group        (GtkRadioButton        *radio_button,
-                                                    GtkRadioButton        *group_source);
+GtkWidget*     gtk_radio_button_new                           (GtkRadioGroup  *group);
+GtkWidget*     gtk_radio_button_new_from_widget               (GtkRadioButton *radio_group_member);
+GtkWidget*     gtk_radio_button_new_with_label                (GtkRadioGroup  *group,
+							       const gchar    *label);
+GtkWidget*     gtk_radio_button_new_with_label_from_widget    (GtkRadioButton *radio_group_member,
+							       const gchar    *label);
+GtkWidget*     gtk_radio_button_new_with_mnemonic             (GtkRadioGroup  *group,
+							       const gchar    *label);
+GtkWidget*     gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *radio_group_member,
+							       const gchar    *label);
+GtkRadioGroup *gtk_radio_button_get_group                     (GtkRadioButton *radio_button);
+void           gtk_radio_button_set_group                     (GtkRadioButton *radio_button,
+							       GtkRadioGroup  *group);
+void           gtk_radio_button_join_group                    (GtkRadioButton *radio_button,
+							       GtkRadioButton *group_source);
+
 G_END_DECLS
 
 #endif /* __GTK_RADIO_BUTTON_H__ */
diff --git a/gtk/gtkradiogroup.c b/gtk/gtkradiogroup.c
new file mode 100644
index 0000000..06dface
--- /dev/null
+++ b/gtk/gtkradiogroup.c
@@ -0,0 +1,263 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
+#include "gtkradiogroupprivate.h"
+#include "gtkprivate.h"
+#include "gtkmarshalers.h"
+#include "gtkintl.h"
+
+/**
+ * SECTION:gtkradiogroup
+ * @Short_description: A group of object having radiobutton like behaviour
+ * @Title: GtkRadioGroup
+ * @See_also: #GtkRadioButton, ...TODO
+ *
+ * ....TODO
+ */
+
+
+struct _GtkRadioGroupPrivate
+{
+  GSList *items;
+  GObject *active;
+};
+
+enum {
+  PROP_0,
+  PROP_ACTIVE_ITEM
+};
+
+
+static void     gtk_radio_group_set_property   (GObject             *object,
+						 guint                prop_id,
+						 const GValue        *value,
+						 GParamSpec          *pspec);
+static void     gtk_radio_group_get_property   (GObject             *object,
+						 guint                prop_id,
+						 GValue              *value,
+						 GParamSpec          *pspec);
+
+G_DEFINE_TYPE (GtkRadioGroup, gtk_radio_group, G_TYPE_INITIALLY_UNOWNED)
+
+enum {
+  CHANGED,
+  ACTIVE_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+gtk_radio_group_class_init (GtkRadioGroupClass *class)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (class);
+
+  gobject_class->set_property = gtk_radio_group_set_property;
+  gobject_class->get_property = gtk_radio_group_get_property;
+
+  /**
+   * GtkRadioGroup:active-item:
+   *
+   * Sets a new group for a radio group.
+   */
+  g_object_class_install_property (gobject_class,
+				   PROP_ACTIVE_ITEM,
+				   g_param_spec_object ("active-item",
+							P_("Active item"),
+							P_("The active item in the radio group."),
+							G_TYPE_OBJECT,
+							GTK_PARAM_WRITABLE));
+  class->changed = NULL;
+  class->active_changed = NULL;
+
+  /**
+   * GtkRadioGroup::active-changed:
+   * @object: the new active object
+   *
+   * ...TODO fix
+   */
+  signals[ACTIVE_CHANGED] = g_signal_new (I_("active-changed"),
+					  G_OBJECT_CLASS_TYPE (gobject_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (GtkRadioGroupClass, active_changed),
+					  NULL, NULL,
+					  _gtk_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 0);
+
+
+  /* TODO: add changed signal */
+
+  g_type_class_add_private (class, sizeof (GtkRadioGroupPrivate));
+}
+
+static void
+gtk_radio_group_init (GtkRadioGroup *radio_group)
+{
+  GtkRadioGroupPrivate *priv;
+
+  radio_group->priv = G_TYPE_INSTANCE_GET_PRIVATE (radio_group,
+                                                    GTK_TYPE_RADIO_GROUP,
+                                                    GtkRadioGroupPrivate);
+  priv = radio_group->priv;
+
+  priv->items = NULL;
+  priv->active = NULL;
+}
+
+static void
+gtk_radio_group_set_property (GObject      *object,
+			       guint         prop_id,
+			       const GValue *value,
+			       GParamSpec   *pspec)
+{
+  GtkRadioGroup *radio_group;
+
+  radio_group = GTK_RADIO_GROUP (object);
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_radio_group_get_property (GObject    *object,
+			       guint       prop_id,
+			       GValue     *value,
+			       GParamSpec *pspec)
+{
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+/**
+ * gtk_radio_group_new:
+ *
+ * Creates a new empty #GtkRadioGroup.
+ *
+ * Returns: a new radio group
+ */
+GtkRadioGroup*
+gtk_radio_group_new (void)
+{
+  GtkRadioGroup *radio_group;
+
+  radio_group = g_object_new (GTK_TYPE_RADIO_GROUP, NULL);
+
+  return radio_group;
+}
+
+GSList*
+gtk_radio_group_get_items (GtkRadioGroup *radio_group)
+{
+  g_return_val_if_fail (GTK_IS_RADIO_GROUP (radio_group), NULL);
+
+  return radio_group->priv->items;
+}
+
+GObject *
+gtk_radio_group_get_active_item (GtkRadioGroup *radio_group)
+{
+  g_return_val_if_fail (GTK_IS_RADIO_GROUP (radio_group), NULL);
+
+  return radio_group->priv->active;
+}
+
+gboolean
+_gtk_radio_group_is_empty (GtkRadioGroup *radio_group)
+{
+  return radio_group->priv->items == NULL;
+}
+
+GObject *
+_gtk_radio_group_get_singleton (GtkRadioGroup *radio_group)
+{
+  GtkRadioGroupPrivate *priv;
+
+  priv = radio_group->priv;
+  if (priv->items != NULL && priv->items->next == NULL)
+    return g_object_ref (priv->items->data);
+  return NULL;
+}
+
+void
+_gtk_radio_group_add_item (GtkRadioGroup *radio_group,
+			   GObject       *item)
+{
+  GtkRadioGroupPrivate *priv;
+
+  g_return_if_fail (GTK_IS_RADIO_GROUP (radio_group));
+  g_return_if_fail (!g_slist_find (radio_group->priv->items, item));
+
+  priv = radio_group->priv;
+  priv->items = g_slist_prepend (priv->items, item);
+  if (priv->active == NULL)
+    priv->active = item;
+}
+
+/* Caller must emit active-changed if removed was active?? */
+void
+_gtk_radio_group_remove_item (GtkRadioGroup *radio_group,
+			      GObject       *item)
+{
+  GtkRadioGroupPrivate *priv;
+
+  g_return_if_fail (GTK_IS_RADIO_GROUP (radio_group));
+  g_return_if_fail (g_slist_find (radio_group->priv->items, item));
+
+  priv = radio_group->priv;
+  priv->items = g_slist_remove (priv->items, item);
+
+  if (priv->active == item)
+    {
+      if (priv->items)
+	priv->active = priv->items->data;
+      else
+	priv->active = NULL;
+    }
+}
+
+void
+_gtk_radio_group_set_active_item (GtkRadioGroup *radio_group,
+				  GObject       *item)
+{
+  radio_group->priv->active = item;
+}
+
+void
+_gtk_radio_group_emit_active_changed (GtkRadioGroup *radio_group)
+{
+  g_signal_emit (radio_group, signals[ACTIVE_CHANGED], 0, radio_group->priv->active);
+}
diff --git a/gtk/gtkradiogroup.h b/gtk/gtkradiogroup.h
new file mode 100644
index 0000000..3906bf8
--- /dev/null
+++ b/gtk/gtkradiogroup.h
@@ -0,0 +1,82 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_RADIO_GROUP_H__
+#define __GTK_RADIO_GROUP_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_RADIO_GROUP		 (gtk_radio_group_get_type ())
+#define GTK_RADIO_GROUP(obj)		 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_RADIO_GROUP, GtkRadioGroup))
+#define GTK_RADIO_GROUP_CLASS(klass)	 (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_RADIO_GROUP, GtkRadioGroupClass))
+#define GTK_IS_RADIO_GROUP(obj)		 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_RADIO_GROUP))
+#define GTK_IS_RADIO_GROUP_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RADIO_GROUP))
+#define GTK_RADIO_GROUP_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_RADIO_GROUP, GtkRadioGroupClass))
+
+
+typedef struct _GtkRadioGroup              GtkRadioGroup;
+typedef struct _GtkRadioGroupPrivate       GtkRadioGroupPrivate;
+typedef struct _GtkRadioGroupClass         GtkRadioGroupClass;
+
+struct _GtkRadioGroup
+{
+  GInitiallyUnowned parent_instance;
+
+  /*< private >*/
+  GtkRadioGroupPrivate *priv;
+};
+
+struct _GtkRadioGroupClass
+{
+  GInitiallyUnownedClass parent_class;
+
+  /* Signals */
+  void (*changed) (GtkRadioGroup *radio_group);
+  void (*active_changed) (GtkRadioGroup *radio_group, GObject *active);
+
+  /* Padding for future expansion */
+  void (*_gtk_reserved1) (void);
+  void (*_gtk_reserved2) (void);
+  void (*_gtk_reserved3) (void);
+  void (*_gtk_reserved4) (void);
+};
+
+
+GType	   gtk_radio_group_get_type	     (void) G_GNUC_CONST;
+
+GtkRadioGroup* gtk_radio_group_new             (void);
+GSList*        gtk_radio_group_get_items       (GtkRadioGroup *radio_group);
+GObject *      gtk_radio_group_get_active_item (GtkRadioGroup *radio_group);
+
+G_END_DECLS
+
+#endif /* __GTK_RADIO_GROUP_H__ */
diff --git a/gtk/gtkradiogroupprivate.h b/gtk/gtkradiogroupprivate.h
new file mode 100644
index 0000000..29ef587
--- /dev/null
+++ b/gtk/gtkradiogroupprivate.h
@@ -0,0 +1,46 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GTK_RADIO_GROUP_PRIVATE_H__
+#define __GTK_RADIO_GROUP_PRIVATE_H__
+
+#include <gtk/gtkradiogroup.h>
+
+G_BEGIN_DECLS
+
+void     _gtk_radio_group_add_item            (GtkRadioGroup *radio_group,
+					       GObject       *item);
+void     _gtk_radio_group_remove_item         (GtkRadioGroup *radio_group,
+					       GObject       *item);
+gboolean _gtk_radio_group_is_empty            (GtkRadioGroup *radio_group);
+GObject *_gtk_radio_group_get_singleton       (GtkRadioGroup *radio_group);
+void     _gtk_radio_group_set_active_item     (GtkRadioGroup *radio_group,
+					       GObject       *item);
+void     _gtk_radio_group_emit_active_changed (GtkRadioGroup *radio_group);
+
+G_END_DECLS
+
+#endif /* __GTK_RADIO_GROUP_PRIVATE_H__ */




-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
       alexl redhat com            alexander larsson gmail com 
He's a hate-fuelled sweet-toothed waffle chef on the edge. She's a 
manipulative punk former first lady from a different time and place. They 
fight crime! 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]