Logo Search packages:      
Sourcecode: glrr-widgets version File versions  Download package

gtkmpaned.c

/*
   Copyright (c) 2004, 2005 by AOSASA Shigeru and Red Hat, Inc.
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are
   met:

   - Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

   - Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials provided
   with the distribution.  

   - Neither the name of the AOSASA Shigeru, Red Hat, Inc
   nor the names of its contributors may be used to endorse or
   promote products derived from this software without specific
   prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
   This software development was supported by
   Information-technorogy Promotion Agency, Japan (IPA).
*/

#include "gtkmpaned.h"

#include "gtksimplebutton.h"


/* XXX */
#define GRIP_D1_LEN 5


enum {
  PROP_0,
};

enum {
  CHILD_PROP_0,
  CHILD_PROP_SHRINK,
  CHILD_PROP_EXPAND,
  CHILD_PROP_FILL,
  CHILD_PROP_MIN,
  CHILD_PROP_MAX,
  CHILD_PROP_FIXED
};


static void gtk_mpaned_class_init (GtkMPanedClass *klass);
static void gtk_mpaned_init     (GtkMPaned        *mpaned);
static void gtk_mpaned_set_property (GObject      *object,
                             guint     property_id,
                             const GValue *value,
                             GParamSpec     *pspec);
static void gtk_mpaned_get_property (GObject      *object,
                             guint     property_id,
                             GValue   *value,
                             GParamSpec     *pspec);
static void gtk_mpaned_size_request  (GtkWidget      *widget,
                              GtkRequisition *requisition);
static void gtk_mpaned_size_allocate (GtkWidget      *widget,
                              GtkAllocation  *allocation);
static void  gtk_mpaned_add            (GtkContainer *container,
                                  GtkWidget      *widget);
static void  gtk_mpaned_remove               (GtkContainer *container,
                                  GtkWidget      *widget);
static void  gtk_mpaned_forall               (GtkContainer *container,
                                  gboolean        include_internals,
                                  GtkCallback     callback,
                                  gpointer        callback_data);
static GType gtk_mpaned_child_type     (GtkContainer *container);
static void  gtk_mpaned_set_child_property (GtkContainer *container,
                                  GtkWidget      *child,
                                  guint     property_id,
                                  const GValue *value,
                                  GParamSpec     *pspec);
static void  gtk_mpaned_get_child_property (GtkContainer *container,
                                  GtkWidget      *child,
                                  guint     property_id,
                                  GValue   *value,
                                  GParamSpec     *pspec);

static void set_child_property (GtkMPaned      *mpaned,
                        GtkMPanedChild *child_info,
                        gboolean    shrink,
                        gboolean    expand,
                        gboolean    fill,
                        gint        d1_min,
                        gint        d1_max,
                        gint        d1_fixed);

static gboolean simple_button_button_press   (GtkWidget          *widget,
                                    GdkEventButton *event,
                                    gpointer          user_data);
static gboolean simple_button_button_release (GtkWidget          *widget,
                                    GdkEventButton *event,
                                    gpointer          user_data);
static gboolean simple_button_motion_notify  (GtkWidget          *widget,
                                    GdkEventMotion *event,
                                    gpointer          user_data);
static gboolean simple_button_expose           (GtkWidget        *widget,
                                    GdkEventExpose *event,
                                    gpointer          user_data);

static void mpaned_update_grips (GtkMPaned *mpaned);
static void mpaned_resize     (GtkMPaned *mpaned);

static GtkMPanedGrip* grip_new         (GtkMPaned     *mpaned);
static void       grip_destroy (GtkMPanedGrip *grip);
static void       grip_move      (GtkMPanedGrip *grip,
                            gint       offset);

static GList*          children_dup                    (GList          *children);
static void            children_copy                         (GList          *from,
                                                GList      *to);
static void            children_free                         (GList          *children);
static GtkMPanedChild* children_find_child_info_by_widget    (GList          *children,
                                                GtkWidget      *widget);
static GList*          children_grep_visible_children      (GList            *children);
static GList*          children_grep_auto_resizable_children (GList          *children);
static GList*          children_grep_shrinkable_children     (GList          *children);
static GList*          children_grep_expandable_children     (GList          *children);
static void            children_update                     (GList      *children,
                                                GtkOrientation  orientation);
static void            children_update_length              (GList      *children,
                                                GtkOrientation  orientation);
static void            children_update_position            (GList      *children,
                                                GtkOrientation  orientation);
static gint            children_get_shrinkable_length      (GList      *children);
static gint            children_get_expandable_length      (GList            *children);
static gint            children_get_natural_length         (GList      *children);
static gint            children_get_actual_length          (GList      *children);
static gint            children_get_min_length             (GList      *children);
static gint            children_get_d2_len_req_max         (GList      *children);
static gint            children_shrink                     (GList      *children,
                                                gint        shrink_length);
static gint            children_expand                     (GList      *children,
                                                gint        expand_length);
static void            children_recompute_length           (GList      *children,
                                                gint        children_length);
static gint            children_reset_natural_length       (GList      *children);
static gint            children_shrink_average             (GList      *children,
                                                gint        shrink_length);
static gint            children_expand_average             (GList      *children,
                                                gint        expand_length);

static void child_info_copy              (GtkMPanedChild *from,
                                    GtkMPanedChild *to);
static void child_info_update_len        (GtkMPanedChild *child_info,
                                    GtkOrientation  orientation);
static void child_info_update_len_req          (GtkMPanedChild *child_info,
                                    GtkOrientation  orientation);
static gint child_info_get_shrinkable_length (GtkMPanedChild *child_info);
static gint child_info_get_expandable_length (GtkMPanedChild *child_info);
static gint child_info_get_natural_length    (GtkMPanedChild *child_info);
static gint child_info_get_min_length          (GtkMPanedChild *child_info);
static gint child_info_get_max_length          (GtkMPanedChild *child_info);
static gint child_info_shrink            (GtkMPanedChild *child_info,
                                    gint        shrink_length);
static gint child_info_expand            (GtkMPanedChild *child_info,
                                    gint        expand_length);

static void dump_children   (GList      *children);
static void dump_child_info (GtkMPanedChild *child_info);

static gint length_clamp    (gint len,
                       gint min,
                       gint max);



static GtkContainerClass *parent_class = NULL;


GType
gtk_mpaned_get_type (void)
{
  static GType mpaned_type = 0;

  if (!mpaned_type)
    {
      static const GTypeInfo mpaned_info =
      {
      sizeof (GtkMPanedClass),
      NULL,       /* base_init */
      NULL,       /* base_finalize */
      (GClassInitFunc) gtk_mpaned_class_init,
      NULL,       /* class_finalize */
      NULL,       /* class_data */
      sizeof (GtkMPaned),
      0,          /* n_preallocs */
      (GInstanceInitFunc) gtk_mpaned_init,
      NULL,       /* value_table */
      };

      mpaned_type = g_type_register_static (GTK_TYPE_CONTAINER,
                                        "GtkMPaned",
                                        &mpaned_info, 0);
    }

  return mpaned_type;
}

static void
gtk_mpaned_class_init (GtkMPanedClass *klass)
{
  GObjectClass     *gobject_class;
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = G_OBJECT_CLASS (klass);
  object_class = (GtkObjectClass*) klass;
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;

  parent_class = g_type_class_peek_parent (klass);

  gobject_class->set_property = gtk_mpaned_set_property;
  gobject_class->get_property = gtk_mpaned_get_property;

  widget_class->size_request = gtk_mpaned_size_request;
  widget_class->size_allocate = gtk_mpaned_size_allocate;

  container_class->add = gtk_mpaned_add;
  container_class->remove = gtk_mpaned_remove;
  container_class->forall = gtk_mpaned_forall;
  container_class->child_type = gtk_mpaned_child_type;
  container_class->set_child_property = gtk_mpaned_set_child_property;
  container_class->get_child_property = gtk_mpaned_get_child_property;


  gtk_container_class_install_child_property (container_class,
                                    CHILD_PROP_SHRINK,
                                    g_param_spec_boolean ("shrink", 
                                                    "Shrink", 
                                                    "XXX",
                                                    FALSE,
                                                    G_PARAM_READWRITE));

  gtk_container_class_install_child_property (container_class,
                                    CHILD_PROP_EXPAND,
                                    g_param_spec_boolean ("expand", 
                                                    "Expand", 
                                                    "XXX",
                                                    TRUE,
                                                    G_PARAM_READWRITE));

  gtk_container_class_install_child_property (container_class,
                                    CHILD_PROP_FILL,
                                    g_param_spec_boolean ("fill",
                                                    "Fill",
                                                    "XXX",
                                                    TRUE,
                                                    G_PARAM_READWRITE));

  gtk_container_class_install_child_property (container_class,
                                    CHILD_PROP_MIN,
                                    g_param_spec_int ("min",
                                                "Min",
                                                "XXX",
                                                -1,
                                                G_MAXINT,
                                                -1,
                                                G_PARAM_READWRITE));

  gtk_container_class_install_child_property (container_class,
                                    CHILD_PROP_MAX,
                                    g_param_spec_int ("max",
                                                "Max",
                                                "XXX",
                                                -1,
                                                G_MAXINT,
                                                -1,
                                                G_PARAM_READWRITE));

  gtk_container_class_install_child_property (container_class,
                                    CHILD_PROP_FIXED,
                                    g_param_spec_int ("fixed",
                                                "Fixed",
                                                "XXX",
                                                -1,
                                                G_MAXINT,
                                                -1,
                                                G_PARAM_READWRITE));
}

static void
gtk_mpaned_init (GtkMPaned *mpaned)
{
  GTK_WIDGET_SET_FLAGS (mpaned, GTK_NO_WINDOW);

  mpaned->orientation = GTK_ORIENTATION_VERTICAL;

  mpaned->children = NULL;
  mpaned->grips = NULL;

  mpaned->in_drag = FALSE;
  mpaned->button_press_x = 0;
  mpaned->button_press_y = 0;
}

static void
gtk_mpaned_set_property (GObject      *object,
                   guint             property_id,
                   const GValue *value,
                   GParamSpec   *pspec)
{
  GtkMPaned *mpaned;
  
  mpaned = GTK_MPANED (object);

  
  switch (property_id)
    {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gtk_mpaned_get_property (GObject    *object,
                   guint           property_id,
                   GValue         *value,
                   GParamSpec *pspec)
{
  GtkMPaned *mpaned;

  mpaned = GTK_MPANED (object);


  switch (property_id)
    {
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gtk_mpaned_add (GtkContainer *container,
            GtkWidget    *widget)
{
  GtkMPaned *mpaned;
  GtkMPanedChild *child;


  mpaned = GTK_MPANED (container);

  child = g_new (GtkMPanedChild, 1);

  child->widget = widget;
  child->shrink = FALSE;
  child->expand = TRUE;
  child->fill     = TRUE;
  child->auto_resize = TRUE;
  child->d1_min = -1;
  child->d1_max = -1;
  child->d1_fixed = -1; /* XXX not yet */
  child->d1_len = -1;
  child->d2_len = -1;
  child->d1_len_req = -1;
  child->d2_len_req = -1;
  child->d1_pos = 0;
  child->d2_pos = 0;


  mpaned->children = g_list_append (mpaned->children,
                            child);

  gtk_widget_set_parent (widget, GTK_WIDGET (mpaned));
}

static void
gtk_mpaned_remove (GtkContainer *container,
               GtkWidget      *widget)
{
  GtkMPaned *mpaned;
  GtkMPanedChild *child_info;


  mpaned = GTK_MPANED (container);

  child_info = children_find_child_info_by_widget (mpaned->children,
                                       widget);

  if (child_info != NULL)
    {
      gtk_widget_unparent (child_info->widget);

      mpaned->children = g_list_remove (mpaned->children,
                              child_info);

      g_free (child_info);
    }
}

static void
gtk_mpaned_forall (GtkContainer *container,
               gboolean  include_internals,
               GtkCallback     callback,
               gpointer  callback_data)
{
  GtkMPaned *mpaned;

  mpaned = GTK_MPANED (container);


  {
    GtkMPanedChild *child_info;
    GtkWidget *child_widget;
    GList *tmp;

    tmp = mpaned->children;
    while (tmp != NULL)
      {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_widget = child_info->widget;

      (* callback) (child_widget, callback_data);
      }
  }

  if (include_internals == TRUE)
    {
      GtkMPanedGrip *grip_info;
      GtkWidget *grip_widget;
      GList *tmp;

      tmp = mpaned->grips;
      while (tmp != NULL)
      {
        grip_info = tmp->data;
        tmp = g_list_next (tmp);
        
        grip_widget = grip_info->widget;

        (* callback) (grip_widget, callback_data);
      }
    }
}

static GType
gtk_mpaned_child_type (GtkContainer *container)
{
  return GTK_TYPE_WIDGET;
}

static void
set_child_property (GtkMPaned    *mpaned,
                GtkMPanedChild *child_info,
                gboolean          shrink,
                gboolean          expand,
                gboolean          fill,
                gint        d1_min,
                gint        d1_max,
                gint        d1_fixed)
{
  GtkWidget *child_widget;
  gboolean property_changed;

  child_widget = child_info->widget;
  property_changed = FALSE;


  gtk_widget_freeze_child_notify (child_widget);


  if (child_info->shrink != shrink)
    {
      property_changed = TRUE;
      child_info->shrink = shrink;

      gtk_widget_child_notify (child_widget, "shrink");
    }

  if (child_info->expand != expand)
    {
      property_changed = TRUE;
      child_info->expand = expand;

      gtk_widget_child_notify (child_widget, "expand");
    }

  if (child_info->fill != fill)
    {
      property_changed = TRUE;
      child_info->fill = fill;

      gtk_widget_child_notify (child_widget, "fill");
    }

  if (child_info->d1_min != d1_min)
    {
      property_changed = TRUE;
      child_info->d1_min = d1_min;

      gtk_widget_child_notify (child_widget, "min");
    }

  if (child_info->d1_max != d1_max)
    {
      property_changed = TRUE;
      child_info->d1_max = d1_max;

      gtk_widget_child_notify (child_widget, "max");
    }

  if (child_info->d1_fixed != d1_fixed)
    {
      property_changed = TRUE;
      child_info->d1_fixed = d1_fixed;

      gtk_widget_child_notify (child_widget, "fixed");
    }


  if (property_changed == TRUE)
    {
      if (GTK_WIDGET_VISIBLE (child_widget) &&
        GTK_WIDGET_VISIBLE (mpaned))
      {
        gtk_widget_queue_resize (child_widget);
      }
    }


  gtk_widget_thaw_child_notify (child_widget);
}


static void
gtk_mpaned_set_child_property (GtkContainer *container,
                         GtkWidget    *child,
                         guint           property_id,
                         const GValue *value,
                         GParamSpec   *pspec)
{
  GtkMPaned *mpaned;
  GtkMPanedChild *child_info;
  GList *tmp;


  mpaned = GTK_MPANED (container);

  child_info = children_find_child_info_by_widget (mpaned->children,
                                       child);


  switch (property_id)
    {
    case CHILD_PROP_SHRINK:
      set_child_property (mpaned,
                    child_info,
                    g_value_get_boolean (value),
                    child_info->expand,
                    child_info->fill,
                    child_info->d1_min,
                    child_info->d1_max,
                    child_info->d1_fixed);
      break;

    case CHILD_PROP_EXPAND:
      set_child_property (mpaned,
                    child_info,
                    child_info->shrink,
                    g_value_get_boolean (value),
                    child_info->fill,
                    child_info->d1_min,
                    child_info->d1_max,
                    child_info->d1_fixed);
      break;

    case CHILD_PROP_FILL:
      set_child_property (mpaned,
                    child_info,
                    child_info->shrink,
                    child_info->expand,
                    g_value_get_boolean (value),
                    child_info->d1_min,
                    child_info->d1_max,
                    child_info->d1_fixed);
      break;

    case CHILD_PROP_MIN:
      set_child_property (mpaned,
                    child_info,
                    child_info->shrink,
                    child_info->expand,
                    child_info->fill,
                    g_value_get_int (value),
                    child_info->d1_max,
                    child_info->d1_fixed);
      break;

    case CHILD_PROP_MAX:
      set_child_property (mpaned,
                    child_info,
                    child_info->shrink,
                    child_info->expand,
                    child_info->fill,
                    child_info->d1_min,
                    g_value_get_int (value),
                    child_info->d1_fixed);
      break;

    case CHILD_PROP_FIXED:
      set_child_property (mpaned,
                    child_info,
                    child_info->shrink,
                    child_info->expand,
                    child_info->fill,
                    child_info->d1_min,
                    child_info->d1_max,
                    g_value_get_int (value));
      break;

    default:
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
      break;
    }
}

static void
gtk_mpaned_get_child_property (GtkContainer *container,
                         GtkWidget    *child,
                         guint           property_id,
                         GValue         *value,
                         GParamSpec   *pspec)
{
  GtkMPaned *mpaned;
  GtkMPanedChild *child_info;
  GList *tmp;


  mpaned = GTK_MPANED (container);

  child_info = children_find_child_info_by_widget (mpaned->children,
                                       child);


  switch (property_id)
    {
    case CHILD_PROP_SHRINK:
      g_value_set_boolean (value, child_info->shrink);
      break;

    case CHILD_PROP_EXPAND:
      g_value_set_boolean (value, child_info->expand);
      break;

    case CHILD_PROP_FILL:
      g_value_set_boolean (value, child_info->fill);
      break;

    case CHILD_PROP_MIN:
      g_value_set_int (value, child_info->d1_min);
      break;

    case CHILD_PROP_MAX:
      g_value_set_int (value, child_info->d1_max);
      break;

    case CHILD_PROP_FIXED:
      g_value_set_int (value, child_info->d1_fixed);
      break;

    default:
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
      break;
    }
}

static void
gtk_mpaned_size_request (GtkWidget  *widget,
                   GtkRequisition *requisition)
{
  GtkMPaned *mpaned;
  gint d1_len_req;
  gint d2_len_req;


  mpaned = GTK_MPANED (widget);


  {
    children_update (mpaned->children,
                 mpaned->orientation);
  }

  {
    GList *visible_children;

    visible_children = children_grep_visible_children (mpaned->children);

    if (visible_children != 0)
      {
      gint children_d1_len;
      gint children_d2_len;
      gint grips_d1_len;
      gint grips_d2_len;
      gint n_grips;

      n_grips = (g_list_length (visible_children) - 1);

      children_d1_len = children_get_min_length     (visible_children);
      children_d2_len = children_get_d2_len_req_max (visible_children);

      grips_d1_len = (n_grips * GRIP_D1_LEN);
      grips_d2_len = children_d2_len;

      d1_len_req = (children_d1_len + grips_d1_len);
      d2_len_req = MAX (children_d2_len, grips_d2_len);
      }
    else
      {
      d1_len_req = 0;
      d2_len_req = 0;
      }

    if (visible_children != NULL)
      {
      g_list_free (visible_children);
      }
  }

  if (0)
    {
    }
  else if (mpaned->orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      requisition->width  = d1_len_req;
      requisition->height = d2_len_req;
    }
  else /* (mpaned->orientation == GTK_ORIENTATION_VERTICAL) */
    {
      requisition->width  = d2_len_req;
      requisition->height = d1_len_req;
    }
}

static void
gtk_mpaned_size_allocate (GtkWidget *widget,
                    GtkAllocation *allocation)
{
  GtkMPaned *mpaned;
  GList *children;
  GList *visible_children;
  GtkOrientation orientation;
  gint mpaned_d1_pos;
  gint mpaned_d2_pos;
  gint mpaned_d1_len;
  gint mpaned_d2_len;


  mpaned = GTK_MPANED (widget);
  GTK_WIDGET (mpaned)->allocation = *allocation;

  children    = mpaned->children;
  orientation = mpaned->orientation;

  if (0)
    {
    }
  else if (orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      mpaned_d1_pos = allocation->x;
      mpaned_d2_pos = allocation->y;
      mpaned_d1_len = allocation->width;
      mpaned_d2_len = allocation->height;
    }
  else /* (orientation == GTK_ORIENTATION_VERTICAL) */
    {
      mpaned_d1_pos = allocation->y;
      mpaned_d2_pos = allocation->x;
      mpaned_d1_len = allocation->height;
      mpaned_d2_len = allocation->width;
    }


  children_update_length (children, orientation);

  mpaned_resize (mpaned);

  children_update_position (children, orientation);
  mpaned_update_grips (mpaned);


  {
    visible_children = children_grep_visible_children (children);
  }

  {
    GList *tmp;
    GtkMPanedChild *child_info;

    tmp = visible_children;
    while (tmp != NULL)
      {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      gint child_d1_pos;
      gint child_d2_pos;
      gint child_d1_len;
      gint child_d2_len;
      gint child_widget_d1_pos;
      gint child_widget_d2_pos;
      gint child_widget_d1_len;
      gint child_widget_d2_len;
      gboolean child_visible;
      gint child_widget_x;
      gint child_widget_y;
      gint child_widget_width;
      gint child_widget_height;
      GtkAllocation child_allocation;


      child_d1_pos = child_info->d1_pos;
      child_d2_pos = child_info->d2_pos;
      child_d1_len = child_info->d1_len;
      child_d2_len = mpaned_d2_len;

      child_widget_d1_pos = child_d1_pos;
      child_widget_d2_pos = child_d2_pos;

      if (child_info->fill == TRUE)
        {
          child_widget_d1_len = child_d1_len;
          child_widget_d2_len = child_d2_len;
        }
      else
        {
          child_widget_d1_len = MIN (child_info->d1_len_req, child_d1_len);
          child_widget_d2_len = MIN (child_info->d2_len_req, child_d2_len);
        }

      if ((child_widget_d1_len > 0) &&
          (child_widget_d2_len > 0))
        {
          child_visible = TRUE;
        }
      else
        {
          child_visible = FALSE;
        }

      if (0)
        {
        }
      else if (orientation == GTK_ORIENTATION_HORIZONTAL)
        {
          child_widget_x      = child_widget_d1_pos;
          child_widget_y      = child_widget_d2_pos;
          child_widget_width  = child_widget_d1_len;
          child_widget_height = child_widget_d2_len;
        }
      else /* (orientation == GTK_ORIENTATION_VERTICAL) */
        {
          child_widget_x      = child_widget_d2_pos;
          child_widget_y      = child_widget_d1_pos;
          child_widget_width  = child_widget_d2_len;
          child_widget_height = child_widget_d1_len;
        }

      child_allocation.x      = child_widget_x;
      child_allocation.y      = child_widget_y;
      child_allocation.width  = child_widget_width;
      child_allocation.height = child_widget_height;


      gtk_widget_set_child_visible (child_info->widget, child_visible);

      gtk_widget_size_allocate (child_info->widget,
                          &child_allocation);
      }
  }

  {
    GtkMPanedChild *child_info;
    GtkMPanedGrip *grip_info;
    GList *tmp;
    gint n_grips;
    int i;
    gint grip_d1_len;
    gint grip_d2_len;
    gint grip_d1_pos;
    gint grip_d2_pos;
    gint grip_x;
    gint grip_y;
    gint grip_width;
    gint grip_height;
    GtkAllocation grip_allocation;


    n_grips = g_list_length (mpaned->grips);
    for (i = 0; i < n_grips; ++i)
      {
      grip_info  = g_list_nth_data (mpaned->grips, i);
      child_info = g_list_nth_data (visible_children, i);

      grip_d1_pos = (child_info->d1_pos + child_info->d1_len);
      grip_d2_pos = (child_info->d2_pos + 0);
      grip_d1_len = GRIP_D1_LEN;
      grip_d2_len = mpaned_d2_len;

      if (0)
        {
        }
      else if (orientation == GTK_ORIENTATION_HORIZONTAL)
        {
          grip_x  = grip_d1_pos;
          grip_y  = grip_d2_pos;
          grip_width    = grip_d1_len;
          grip_height = grip_d2_len;
        }
      else /* (orientation == GTK_ORIENTATION_VERTICAL) */
        {
          grip_x  = grip_d2_pos;
          grip_y  = grip_d1_pos;
          grip_width    = grip_d2_len;
          grip_height = grip_d1_len;
        }

      grip_allocation.x      = grip_x;
      grip_allocation.y      = grip_y;
      grip_allocation.width  = grip_width;
      grip_allocation.height = grip_height;

      gtk_widget_size_allocate (grip_info->widget, &grip_allocation);
      }
  }

  if (visible_children != NULL)
    {
      g_list_free (visible_children);
    }
}

static void
mpaned_resize (GtkMPaned *mpaned)
{
  gint mpaned_width;
  gint mpaned_height;
  gint mpaned_d1_len;
  gint mpaned_d2_len;
  GList *visible_children;

  mpaned_width    = GTK_WIDGET (mpaned)->allocation.width;
  mpaned_height = GTK_WIDGET (mpaned)->allocation.height;

  if (0)
    { }
  else if (mpaned->orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      mpaned_d1_len = mpaned_width;
      mpaned_d2_len = mpaned_height;
    }
  else /* (mpaned->orientation == GTK_ORIENTATION_VERTICAL) */
    {
      mpaned_d1_len = mpaned_height;
      mpaned_d2_len = mpaned_width;
    }


  children_update (mpaned->children,
               mpaned->orientation);


  visible_children = children_grep_visible_children (mpaned->children);


  {
    gint children_length;

      {
      children_length = (mpaned_d1_len
                     - ((g_list_length (visible_children) - 1)
                        * GRIP_D1_LEN));

      children_recompute_length (visible_children, children_length);
      }

      {
      gint d1_len_req_actual;

      d1_len_req_actual = children_get_actual_length (visible_children);

      if (0)
        {
        }
      else if (d1_len_req_actual < children_length)
        {
          children_expand (g_list_reverse (visible_children),
                       (children_length - d1_len_req_actual));
        }
      else /* (d1_len_req_actual > children_length) */
        {
          children_shrink (g_list_reverse (visible_children),
                       (d1_len_req_actual - children_length));
        }
      }
  }


  if (visible_children != NULL)
    {
      g_list_free (visible_children);
    }
}

static void
mpaned_update_grips (GtkMPaned *mpaned)
{
  GtkMPanedChild *child_info;
  GtkWidget *child_widget;
  GList *visible_children;
  guint n_visible_children;
  guint n_grips;
  guint i;

  visible_children = children_grep_visible_children (mpaned->children);

  n_visible_children = g_list_length (visible_children);
  n_grips = (n_visible_children - 1);


  {
    guint n;

    n = g_list_length (mpaned->grips);

    if (n < n_grips)
      {
      GtkMPanedGrip *grip;

      for (i = 0; i < (n_grips - n); ++i)
        {
          grip = grip_new (mpaned);

          mpaned->grips = g_list_append (mpaned->grips, grip);
        }
      }
    else if (n > n_grips)
      {
      GList *tmp;
      GtkMPanedGrip *grip;

      for (i = 0; i < (n - n_grips); ++i)
        {
          tmp = g_list_last (mpaned->grips);

          grip = tmp->data;
          tmp = g_list_delete_link (tmp, tmp);

          grip_destroy (grip);
        }
      }
  }
  
  if (visible_children != NULL)
    {
      g_list_free (visible_children);
    }
}

static GtkMPanedGrip*
grip_new (GtkMPaned *mpaned)
{
  GtkMPanedGrip *grip;

  grip = g_new (GtkMPanedGrip, 1);

  grip->mpaned = mpaned;

  grip->widget = gtk_simple_button_new ();

  g_signal_connect (grip->widget,
                "button_press_event",
                G_CALLBACK (simple_button_button_press),
                grip);
  g_signal_connect (grip->widget,
                "button_release_event",
                G_CALLBACK (simple_button_button_release),
                grip);
  g_signal_connect (grip->widget,
                "motion_notify_event",
                G_CALLBACK (simple_button_motion_notify),
                grip);
  g_signal_connect (grip->widget,
                "expose_event",
                G_CALLBACK (simple_button_expose),
                grip);

  gtk_widget_set_events (grip->widget,
                   GDK_POINTER_MOTION_MASK);

  gtk_widget_show (grip->widget);
  gtk_widget_set_parent (grip->widget, GTK_WIDGET (mpaned));


  return grip;
}

static void
grip_destroy (GtkMPanedGrip *grip)
{
  gtk_widget_destroy (grip->widget);
  g_free (grip);
}

static gboolean
simple_button_button_press (GtkWidget        *widget,
                      GdkEventButton *event,
                      gpointer          user_data)
{
  GtkMPanedGrip *grip;
  GtkMPaned *mpaned;

  grip = user_data;
  mpaned = grip->mpaned;


  if (event->button == 1)
    {
      if (mpaned->in_drag != TRUE)
      {
        mpaned->in_drag = TRUE;
        mpaned->orig_children = children_dup (mpaned->children);
        gtk_widget_get_pointer (GTK_WIDGET (mpaned),
                          &mpaned->button_press_x,
                          &mpaned->button_press_y);
      }
    }
  else
    {
      if (mpaned->in_drag == TRUE)
      {
        children_copy (mpaned->orig_children,
                   mpaned->children);

        children_free (mpaned->orig_children);
        
        mpaned->in_drag = FALSE;
        mpaned->orig_children = NULL;
        mpaned->button_press_x = 0;
        mpaned->button_press_y = 0;


        gtk_widget_queue_resize (GTK_WIDGET (mpaned));
      }
    }


  return TRUE;
}

static gboolean
simple_button_button_release (GtkWidget        *widget,
                        GdkEventButton *event,
                        gpointer          user_data)
{
  GtkMPanedGrip *grip;
  GtkMPaned *mpaned;

  grip = user_data;
  mpaned = grip->mpaned;


  if (mpaned->in_drag == TRUE)
    {
      children_free (mpaned->orig_children);

      mpaned->in_drag = FALSE;
      mpaned->orig_children = NULL;
      mpaned->button_press_x = 0;
      mpaned->button_press_y = 0;


      gtk_widget_queue_resize (GTK_WIDGET (mpaned));
    }


  return TRUE;
}

static gboolean
simple_button_motion_notify (GtkWidget        *widget,
                       GdkEventMotion *event,
                       gpointer          user_data)
{
  GtkMPanedGrip *grip;
  GtkMPaned *mpaned;

  grip = user_data;
  mpaned = grip->mpaned;


  if (mpaned->in_drag == TRUE)
    {
      gint x;
      gint y;
      gint offset;

      gtk_widget_get_pointer (GTK_WIDGET (mpaned), &x, &y);

      if (0)
      {
      }
      else if (mpaned->orientation == GTK_ORIENTATION_HORIZONTAL)
      {
        offset = (x - mpaned->button_press_x);
      }
      else /* (mpaned->orientation == GTK_ORIENTATION_VERTICAL) */
      {
        offset = (y - mpaned->button_press_y);
      }

      grip_move (grip, offset);
    }


  return TRUE;
}


static gboolean
simple_button_expose (GtkWidget          *widget,
                  GdkEventExpose *event,
                  gpointer          user_data)
{
  if (GTK_WIDGET_VISIBLE (widget) &&
      GTK_WIDGET_MAPPED (widget))
    {
      GtkMPanedGrip *grip;
      GtkMPaned *mpaned;
      GtkOrientation orientation;
      gint x;
      gint y;
      gint width;
      gint height;

      grip = user_data;
      mpaned = grip->mpaned;

      x          = widget->allocation.x;
      y          = widget->allocation.y;
      width  = widget->allocation.width;
      height = widget->allocation.height;

      orientation = ((mpaned->orientation == GTK_ORIENTATION_HORIZONTAL)
                 ? GTK_ORIENTATION_VERTICAL
                 : GTK_ORIENTATION_HORIZONTAL);

      gtk_paint_handle (GTK_WIDGET (widget)->style,
                  GTK_WIDGET (widget)->window,
                  GTK_WIDGET_STATE (widget),
                  GTK_SHADOW_NONE,
                  NULL,
                  GTK_WIDGET (widget),
                  "paned", /* XXX */
                  x, y, width, height,
                  orientation);
    }

  GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);

  return TRUE;
}

static void
grip_move (GtkMPanedGrip *grip,
         gint             offset)
{
  GtkMPaned *mpaned;
  GList *visible_children;
  gint grip_pos;
  gint negative_side_shrinkable_length;
  gint negative_side_expandable_length;
  gint positive_side_shrinkable_length;
  gint positive_side_expandable_length;
  GList *negative_side_children;
  GList *positive_side_children;


  mpaned = grip->mpaned;

  children_copy (mpaned->orig_children,
             mpaned->children);
  
  visible_children = children_grep_visible_children (mpaned->children);

  {
    GList *negative_side;
    GList *positive_side;
    GtkMPanedChild *child_info;
    GList *tmp;

    grip_pos = g_list_index (mpaned->grips, grip);

    tmp = g_list_nth (visible_children, grip_pos);
    
    negative_side = tmp;
    positive_side = g_list_next (tmp);

    negative_side_children = NULL;
    positive_side_children = NULL;

    tmp = negative_side;
    while (tmp != NULL)
      {
      child_info = tmp->data;
      tmp = g_list_previous (tmp);

      negative_side_children = g_list_append (negative_side_children, child_info);
      }

    tmp = positive_side;
    while (tmp != NULL)
      {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      positive_side_children = g_list_append (positive_side_children, child_info);
      }
  }

  {
    negative_side_shrinkable_length = children_get_shrinkable_length (negative_side_children);
    negative_side_expandable_length = children_get_expandable_length (negative_side_children);

    positive_side_shrinkable_length = children_get_shrinkable_length (positive_side_children);
    positive_side_expandable_length = children_get_expandable_length (positive_side_children);
  }

  if (offset < 0)
    {
      if (((negative_side_shrinkable_length > 0) || (negative_side_shrinkable_length == -1)) &&
        ((positive_side_expandable_length > 0) || (positive_side_expandable_length == -1)))
      {
        gint length;

        if (0)
          {
          }
        else if ((negative_side_shrinkable_length != -1) &&
               (positive_side_expandable_length != -1))
          {
            length = MIN (ABS (offset),
                      MIN (negative_side_shrinkable_length,
                         positive_side_expandable_length));
          }
        else if ((negative_side_shrinkable_length != -1) &&
               (positive_side_expandable_length == -1))
          {
            length = MIN (ABS (offset),
                      negative_side_shrinkable_length);
          }
        else if ((negative_side_shrinkable_length == -1) &&
               (positive_side_expandable_length != -1))
          {
            length = MIN (ABS (offset),
                      positive_side_expandable_length);
          }
        else /* ((negative_side_shrinkable_length == -1) &&
               (positive_side_expandable_length == -1)) */
          {
            length = ABS (offset);
            /* not reached */
          }

        if (length > 0)
          {
            gint shrinked_length;
            gint expanded_length;


            shrinked_length = children_shrink (negative_side_children, length);
            expanded_length = children_expand (positive_side_children, length);

            if ((shrinked_length != length) ||
              (expanded_length != length))
            {
              g_print ("%s: shrinked_length != expanded_length\n", __FUNCTION__);
            }

            gtk_widget_queue_resize (GTK_WIDGET (mpaned));
          }
      }
    }

  if (offset > 0)
    {
      if (((negative_side_expandable_length > 0) || (negative_side_expandable_length == -1)) &&
        ((positive_side_shrinkable_length > 0) || (positive_side_shrinkable_length == -1)))
      {
        gint length;

        if (0)
          {
          }
        else if ((negative_side_expandable_length != -1) &&
               (positive_side_shrinkable_length != -1))
          {
            length = MIN (ABS (offset),
                      MIN (negative_side_expandable_length,
                         positive_side_shrinkable_length));
          }
        else if ((negative_side_expandable_length != -1) &&
               (positive_side_shrinkable_length == -1))
          {
            length = MIN (ABS (offset),
                      negative_side_expandable_length);
          }
        else if ((negative_side_expandable_length == -1) &&
               (positive_side_shrinkable_length != -1))
          {
            length = MIN (ABS (offset),
                      positive_side_shrinkable_length);
          }
        else /* ((negative_side_expandable_length == -1) &&
               (positive_side_shrinkable_length == -1)) */
          {
            length = ABS (offset);
            /* not reached */
          }

        if (length > 0)
          {
            gint expanded_length;
            gint shrinked_length;


            expanded_length = children_expand (negative_side_children, length);
            shrinked_length = children_shrink (positive_side_children, length);

            if ((expanded_length != length) ||
              (shrinked_length != length))
            {
              g_print ("%s: expanded_length != shrinked_length\n", __FUNCTION__);
            }


            gtk_widget_queue_resize (GTK_WIDGET (mpaned));
          }
      }
    }

  {
    if (visible_children != NULL)
      {
      g_list_free (visible_children);
      }


    if (negative_side_children != NULL)
      {
      g_list_free (negative_side_children);
      }
    if (positive_side_children != NULL)
      {
      g_list_free (positive_side_children);
      }
  }
}

static void
dump_children (GList *children)
{
  GtkMPanedChild *child_info;
  GList *tmp;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      dump_child_info (child_info);
    }

  g_print ("\n");
}

static void
dump_child_info (GtkMPanedChild *child_info)
{
  g_print ("%p    %s %d %d\n",
         child_info,
         ((child_info->auto_resize == TRUE) ? "TRUE" : "FALSE"),
         child_info->d1_len,
         child_info->d1_len_req);
}


static GList*
children_grep_visible_children (GList *children)
{
  GList *visible_children;
  GList *tmp;
  GtkMPanedChild *child_info;
  GtkWidget *child_widget;

  visible_children = NULL;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_widget = child_info->widget;

      if (GTK_WIDGET_VISIBLE (child_widget))
      {
        visible_children = g_list_append (visible_children,
                                  child_info);
      }
    }

  return visible_children;
}

static GList*
children_grep_auto_resizable_children (GList *children)
{
  GList *auto_resizable_children;
  GList *tmp;
  GtkMPanedChild *child_info;

  auto_resizable_children = NULL;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      if (child_info->auto_resize == TRUE)
      {
        auto_resizable_children = g_list_append (auto_resizable_children,
                                       child_info);
      }
    }

  return auto_resizable_children;
}

static GList*
children_grep_shrinkable_children (GList *children)
{
  GList *shrinkable_children;
  GList *tmp;
  GtkMPanedChild *child_info;
  gint child_shrinkable_length;

  shrinkable_children = NULL;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_shrinkable_length = child_info_get_shrinkable_length (child_info);

      if (child_shrinkable_length != 0)
      {
        shrinkable_children = g_list_append (shrinkable_children,
                                     child_info);
      }
    }

  return shrinkable_children;
}

static GList*
children_grep_expandable_children (GList *children)
{
  GList *expandable_children;
  GList *tmp;
  GtkMPanedChild *child_info;
  gint child_expandable_length;

  expandable_children = NULL;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_expandable_length = child_info_get_expandable_length (child_info);

      if (child_expandable_length != 0)
      {
        expandable_children = g_list_append (expandable_children,
                                     child_info);
      }
    }

  return expandable_children;
}


static GList*
children_dup (GList *children)
{
  GList *tmp1;
  GList *tmp2;

  GtkMPanedChild *child_info1;
  GtkMPanedChild *child_info2;


  tmp1 = children;
  tmp2 = NULL;

  while (tmp1 != NULL)
    {
      child_info1 = tmp1->data;
      child_info2 = g_new (GtkMPanedChild, 1);

      child_info_copy (child_info1, child_info2);

      tmp1 = g_list_next (tmp1);
      tmp2 = g_list_append (tmp2, child_info2);
    }

  return tmp2;
}

static void
children_copy (GList *from,
             GList *to)
{
  gint n;
  gint i;
  GtkMPanedChild *child_info1;
  GtkMPanedChild *child_info2;

  n = g_list_length (from);
  for (i = 0; i < n; ++i)
    {
      child_info1 = g_list_nth_data (from, i);
      child_info2 = g_list_nth_data (to,   i);

      child_info_copy (child_info1, child_info2);
    }
}

static void
children_free (GList *children)
{
  GtkMPanedChild *child_info;
  GList *tmp;
  
  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      g_free (child_info);
    }

  g_list_free (children);
}

static GtkMPanedChild *
children_find_child_info_by_widget (GList     *children,
                            GtkWidget *widget)
{
  GtkMPanedChild *child_info;
  GtkMPanedChild *tmp_child_info;
  GList *tmp;


  child_info = NULL;

  tmp = children;
  while (tmp != NULL)
    {
      tmp_child_info = tmp->data;
      tmp = g_list_next (tmp);

      if (tmp_child_info->widget == widget)
      {
        child_info = tmp_child_info;
        break;
      }
    }

  return child_info;
}

static gint
children_get_shrinkable_length (GList *children)
{
  gint shrinkable_length;
  gint child_shrinkable_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  shrinkable_length = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_shrinkable_length = child_info_get_shrinkable_length (child_info);

      if (child_shrinkable_length == -1)
      {
        shrinkable_length = -1;

        break;
      }
      else
      {
        shrinkable_length += child_shrinkable_length;
      }
    }


  return shrinkable_length;
}

static gint
children_get_expandable_length (GList *children)
{
  gint expandable_length;
  gint child_expandable_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  expandable_length = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_expandable_length = child_info_get_expandable_length (child_info);

      if (child_expandable_length == -1)
      {
        expandable_length = -1;

        break;
      }
      else
      {
        expandable_length += child_expandable_length;
      }
    }


  return expandable_length;
}

static gint
children_get_natural_length (GList *children)
{
  gint natural_length;
  gint child_natural_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  natural_length = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_natural_length = child_info_get_natural_length (child_info);

      natural_length += child_natural_length;
    }


  return natural_length;
}

static gint
children_get_actual_length (GList *children)
{
  gint actual_length;
  gint child_actual_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  actual_length = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_actual_length = child_info->d1_len;

      actual_length += child_actual_length;
    }


  return actual_length;
}

static gint
children_get_min_length (GList *children)
{
  gint min_length;
  gint child_min_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  min_length = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_min_length = child_info_get_min_length (child_info);

      min_length += child_min_length;
    }


  return min_length;
}

static gint
children_get_d2_len_req_max (GList *children)
{
  gint d2_len_req_max;
  gint child_d2_len_req;
  GtkMPanedChild *child_info;
  GList *tmp;


  d2_len_req_max = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_d2_len_req = child_info->d2_len_req;

      d2_len_req_max = MAX (d2_len_req_max, child_d2_len_req);
    }


  return d2_len_req_max;
}

static gint
children_shrink (GList *children,
             gint shrink_length)
{
  gint child_shrinkable_length;
  gint child_shrink_length;
  gint tmp_length;
  gint shrinked_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  tmp_length = shrink_length;

  tmp = children;
  while ((tmp != NULL) &&
       (tmp_length > 0))
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_shrinkable_length
      = child_info_get_shrinkable_length (child_info);

      if (child_shrinkable_length == -1)
      {
        child_shrink_length = MIN (tmp_length,
                             child_info->d1_len);
      }
      else
      {
        child_shrink_length = MIN (tmp_length,
                             child_shrinkable_length);
      }

      child_info->auto_resize = FALSE;
      child_info->d1_len = (child_info->d1_len - child_shrink_length);


      tmp_length -= child_shrink_length;
    }


  shrinked_length = (shrink_length - tmp_length);


  return shrinked_length;
}

static gint
children_expand (GList *children,
             gint expand_length)
{
  gint child_expandable_length;
  gint child_expand_length;
  gint tmp_length;
  gint expanded_length;
  GtkMPanedChild *child_info;
  GList *tmp;


  tmp_length = expand_length;

  tmp = children;
  while ((tmp != NULL) &&
       (tmp_length > 0))
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_expandable_length
      = child_info_get_expandable_length (child_info);

      if (child_expandable_length == -1)
      {
        child_expand_length = tmp_length;
      }
      else
      {
        child_expand_length = MIN (tmp_length,
                             child_expandable_length);
      }

      child_info->auto_resize = FALSE;
      child_info->d1_len = (child_info->d1_len + child_expand_length);


      tmp_length -= child_expand_length;
    }


  expanded_length = (expand_length - tmp_length);


  return expanded_length;
}

static void
children_recompute_length (GList *children,
                     gint       children_length)
{
  GList *auto_resizable_children;
  gint tmp1;
  gint tmp2;
  gint tmp3;
  gint tmp4;
  gint tmp5;
  gint tmp6;


  auto_resizable_children = children_grep_auto_resizable_children (children);

  if (auto_resizable_children != NULL)
    {
      tmp1 = children_get_actual_length (children);
      tmp2 = children_get_actual_length (auto_resizable_children);

      children_reset_natural_length (auto_resizable_children);

      tmp3 = children_get_actual_length (auto_resizable_children);

      tmp4 = (tmp1 - tmp2); /* non auto length */
      tmp5 = (children_length - tmp4);
      tmp6 = (tmp3);

      if (tmp5 == tmp6)
      {
      }
      else if (tmp5 < tmp6)
      {
        gint shrinked_length;
        shrinked_length
          = children_shrink_average (auto_resizable_children,
                               (tmp6 - tmp5));
      }
      else /* (tmp5 > tmp6) */
      {
        gint expanded_length;
        expanded_length
          = children_expand_average (auto_resizable_children,
                               (tmp5 - tmp6));
      }
    }


  if (auto_resizable_children != NULL)
    {
      g_list_free (auto_resizable_children);
    }
}

static gint
children_reset_natural_length (GList *children)
{
  GtkMPanedChild *child_info;
  GList *tmp;
  gint natural_length;
  gint diff;

  diff = 0;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      natural_length = child_info_get_natural_length (child_info);

      diff += (natural_length - child_info->d1_len);

      child_info->d1_len = natural_length;
    }

  return diff;
}

static gint
children_shrink_average (GList *children,
                   gint shrink_length)
{
  gint shrinked_length;
  GList *shrinkable_children;
  gint n_shrinkable_children;
  GtkMPanedChild *child_info;
  GList *tmp;
  gint shrink_per_child;

  shrinked_length = 0;

  while (shrinked_length < shrink_length)
    {
      shrinkable_children   = children_grep_shrinkable_children (children);
      n_shrinkable_children = g_list_length (shrinkable_children);

      if (n_shrinkable_children > 0)
      {
        shrink_per_child = ((shrink_length - shrinked_length)
                        / n_shrinkable_children);

        tmp = shrinkable_children;
        while ((tmp != NULL) &&
             (shrinked_length < shrink_length))
          {
            child_info = tmp->data;
            tmp = g_list_next (tmp);

            if (shrink_per_child > 0)
            {
              shrinked_length += child_info_shrink (child_info,
                                          shrink_per_child);
            }
            else
            {
              shrinked_length += child_info_shrink (child_info,
                                          1);
            }
          }
      }
      else
      {
        break;
      }

      if (shrinkable_children != NULL)
      {
        g_list_free (shrinkable_children);
      }
    }


  return shrinked_length;
}

static gint
children_expand_average (GList *children,
                   gint expand_length)
{
  gint expanded_length;
  GList *expandable_children;
  gint n_expandable_children;
  GtkMPanedChild *child_info;
  GList *tmp;
  gint expand_per_child;

  expanded_length = 0;

  while (expanded_length < expand_length)
    {
      expandable_children   = children_grep_expandable_children (children);
      n_expandable_children = g_list_length (expandable_children);

      if (n_expandable_children > 0)
      {
        expand_per_child = ((expand_length - expanded_length)
                        / n_expandable_children);

        tmp = expandable_children;
        while ((tmp != NULL) &&
             (expanded_length < expand_length))
          {
            child_info = tmp->data;
            tmp = g_list_next (tmp);

            if (expand_per_child > 0)
            {
              expanded_length += child_info_expand (child_info,
                                          expand_per_child);
            }
            else
            {
              expanded_length += child_info_expand (child_info,
                                          1);
            }
          }
      }
      else
      {
        break;
      }

      if (expandable_children != NULL)
      {
        g_list_free (expandable_children);
      }
    }


  return expanded_length;
}


static void
children_update (GList        *children,
             GtkOrientation    orientation)
{
  children_update_length   (children, orientation);
  children_update_position (children, orientation);
}

static void
children_update_length (GList        *children,
                  GtkOrientation    orientation)
{
  GtkMPanedChild *child_info;
  GList *tmp;

  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      child_info_update_len_req (child_info, orientation);
      child_info_update_len   (child_info, orientation);
    }
}

static void
child_info_update_len_req (GtkMPanedChild *child_info,
                     GtkOrientation  orientation)
{
  gint tmp_d1_len_req;
  gint tmp_d2_len_req;
  GtkRequisition child_requisition;

  gtk_widget_size_request (child_info->widget, &child_requisition);

  if (0)
    {
    }
  else if (orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      tmp_d1_len_req = child_requisition.width;
      tmp_d2_len_req = child_requisition.height;
    }
  else /* (orientation == GTK_ORIENTATION_VERTICAL) */
    {
      tmp_d1_len_req = child_requisition.height;
      tmp_d2_len_req = child_requisition.width;
    }

  child_info->d1_len_req = tmp_d1_len_req;
  child_info->d2_len_req = tmp_d2_len_req;
}

static void
child_info_update_len (GtkMPanedChild *child_info,
                   GtkOrientation  orientation)
{
  gint tmp_d1_len;
  gint tmp_d2_len;


  tmp_d1_len = -1;
  tmp_d2_len = -1;

  if (child_info->d1_len < 0)
    {
      tmp_d1_len = child_info_get_min_length (child_info);
    }
  else
    {
      tmp_d1_len = length_clamp (child_info->d1_len,
                         child_info_get_min_length (child_info),
                         child_info_get_max_length (child_info));
    }

  child_info->d1_len = tmp_d1_len;
  child_info->d2_len = tmp_d2_len;
}

static void
children_update_position (GList            *children,
                    GtkOrientation  orientation)
{
  gint d1_pos;
  gint d2_pos;
  GList *tmp;
  GtkMPanedChild *child_info;

  d1_pos = 0;
  d2_pos = 0;


  tmp = children;
  while (tmp != NULL)
    {
      child_info = tmp->data;
      tmp = g_list_next (tmp);

      if (GTK_WIDGET_VISIBLE (child_info->widget))
      {
        gint child_d1_len;
        gint child_d2_len;

        child_d1_len = child_info->d1_len;
        child_d2_len = child_info->d2_len;

        child_info->d1_pos = d1_pos;
        child_info->d2_pos = d2_pos;

        d1_pos += child_d1_len + GRIP_D1_LEN;
        d2_pos += 0;
      }
    }
}


static gint
child_info_get_shrinkable_length (GtkMPanedChild *child_info)
{
  gint shrinkable_length;
  gint min;


  min = child_info_get_min_length (child_info);


  if (min < 0) /* unlimited */
    {
      shrinkable_length = child_info->d1_len;
    }
  else
    {
      if (child_info->d1_len > min)
      {
        shrinkable_length = (child_info->d1_len - min);
      }
      else
      {
        shrinkable_length = 0;
      }
    }


  return shrinkable_length;
}

static gint
child_info_get_expandable_length (GtkMPanedChild *child_info)
{
  gint expandable_length;
  gint max;


  max = child_info_get_max_length (child_info);


  if (max < 0) /* unlimited */
    {
      expandable_length = -1; /* unlimited */
    }
  else
    {
      if (child_info->d1_len < max)
      {
        expandable_length = (max - child_info->d1_len);
      }
      else
      {
        expandable_length = 0;
      }
    }


  return expandable_length;
}

static gint
child_info_get_natural_length (GtkMPanedChild *child_info)
{
  gint natural_length;
  gint min;
  gint max;


  min = child_info_get_min_length (child_info);
  max = child_info_get_max_length (child_info);


  natural_length = length_clamp (child_info->d1_len_req,
                         min,
                         max);


  return natural_length;
}

static gint
child_info_get_min_length (GtkMPanedChild *child_info)
{
  gint tmp_min;
  gint min;


  if (child_info->d1_min < 0) /* unlimited */
    {
      if (child_info->shrink != TRUE)
      {
        tmp_min = child_info->d1_len_req;
      }
      else
      {
        tmp_min = child_info->d1_min; /* unlimited */
      }
    }
  else
    {
      if ((child_info->d1_min < child_info->d1_len_req) &&
        (child_info->shrink != TRUE))
      {
        tmp_min = child_info->d1_len_req;
      }
      else if ((child_info->d1_min > child_info->d1_len_req) &&
             (child_info->expand != TRUE))
      {
        tmp_min = child_info->d1_len_req;
      }
      else
      {
        tmp_min = child_info->d1_min;
      }
    }

  if (tmp_min < 0)
    {
      min = 0;
    }
  else
    {
      min = tmp_min;
    }


  return min;
}

static gint
child_info_get_max_length (GtkMPanedChild *child_info)
{
  gint max;


  if (child_info->d1_max < 0) /* unlimited */
    {
      if (child_info->expand != TRUE)
      {
        max = child_info->d1_len_req;
      }
      else
      {
        max = child_info->d1_max; /* unlimited */
      }
    }
  else
    {
      if ((child_info->d1_max < child_info->d1_len_req) &&
        (child_info->shrink != TRUE))
      {
        max = child_info->d1_len_req;
      }
      else if ((child_info->d1_max > child_info->d1_len_req) &&
             (child_info->expand != TRUE))
      {
        max = child_info->d1_len_req;
      }
      else
      {
        max = child_info->d1_max;
      }
    }


  return max;
}

static gint
child_info_shrink (GtkMPanedChild *child_info,
               gint              shrink_length)
{
  gint shrinkable_length;
  gint shrinked_length;
  gint tmp_shrink_length;

  shrinkable_length = child_info_get_shrinkable_length (child_info);

  if (shrinkable_length < 0) /* unlimited */
    {
      tmp_shrink_length = shrink_length;
    }
  else
    {
      tmp_shrink_length = MIN (shrink_length, shrinkable_length);
    }

  child_info->d1_len -= tmp_shrink_length;
  shrinked_length     = tmp_shrink_length;

  return shrinked_length;
}

static gint
child_info_expand (GtkMPanedChild *child_info,
               gint              expand_length)
{
  gint expandable_length;
  gint expanded_length;
  gint tmp_expand_length;

  expandable_length = child_info_get_expandable_length (child_info);

  if (expandable_length < 0) /* unlimited */
    {
      tmp_expand_length = expand_length;
    }
  else
    {
      tmp_expand_length = MIN (expand_length, expandable_length);
    }

  child_info->d1_len += tmp_expand_length;
  expanded_length     = tmp_expand_length;

  return expanded_length;
}



static void
child_info_copy (GtkMPanedChild *from,
             GtkMPanedChild *to)
{
  to->widget        = from->widget;
  to->shrink        = from->shrink;
  to->expand        = from->expand;
  to->fill    = from->fill;
  to->auto_resize = from->auto_resize;
  to->d1_min        = from->d1_min;
  to->d1_max        = from->d1_max;
  to->d1_fixed      = from->d1_fixed;
  to->d1_len        = from->d1_len;
  to->d2_len        = from->d2_len;
  to->d1_len_req  = from->d1_len_req;
  to->d2_len_req  = from->d2_len_req;
  to->d1_pos        = from->d1_pos;
  to->d2_pos        = from->d2_pos;
}



static gint
length_clamp (gint len,
            gint min,
            gint max)
{
  gint r;


  if (0)
    {
    }
  else if ((min >= 0) &&
         (len < min))
    {
      r = min;
    }
  else if ((max >= 0) &&
         (len > max))
    {
      r = max;
    }
  else
    {
      r = len;
    }


  return r;
}

Generated by  Doxygen 1.6.0   Back to index