Re: Add GtkRadioGroup?



On Thu, 2010-10-28 at 22:38 +0200, Alexander Larsson wrote:
> 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?

Hi,
   I like the idea of not using the GSList too.

But I wonder, don't we already accomplish this with
GtkRadioAction ?

I'm not sure the two entities would play nicely together
either, maybe it makes sense to deprecate or even remove
GSList interaction and just converge towards usage of
a GtkRadioAction.

Cheers,
        -Tristan


> 
> 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__ */
> 
> 
> 
> 




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