Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Gtk+/Gnome Application Development
Prev Home Next

Size Negotiation

GtkVBox's purpose in life is size negotiation; it passes size requests up from its children, and then divides a size allocation among them. This leads to the layout behavior described in the section called GtkBox in the chapter called GTK+ Basics.

Here is the size request implementation:


static void
gtk_vbox_size_request (GtkWidget      *widget,
                       GtkRequisition *requisition)
{
  GtkBox *box;
  GtkBoxChild *child;
  GtkRequisition child_requisition;
  GList *children;
  gint nvis_children;
  gint height;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_VBOX (widget));
  g_return_if_fail (requisition != NULL);

  box = GTK_BOX (widget);
  requisition->width = 0;
  requisition->height = 0;
  nvis_children = 0;

  children = box->children;
  while (children)
    {
      child = children->data;
      children = children->next;

      if (GTK_WIDGET_VISIBLE (child->widget))
        {
          gtk_widget_size_request (child->widget, &child_requisition);

          if (box->homogeneous)
            {
              height = child_requisition.height + child->padding * 2;
              requisition->height = MAX (requisition->height, height);
            }
          else
            {
              requisition->height += child_requisition.height + child->padding * 2;
            }

          requisition->width = MAX (requisition->width, child_requisition.width);

          nvis_children += 1;
        }
    }

  if (nvis_children > 0)
    {
      if (box->homogeneous)
        requisition->height *= nvis_children;
      requisition->height += (nvis_children - 1) * box->spacing;
    }

  requisition->width += GTK_CONTAINER (box)->border_width * 2;
  requisition->height += GTK_CONTAINER (box)->border_width * 2;
}
      

If the box is homogenous, it multiplies the maximum child requisition times the number of children; otherwise, it sums the child requisitions. Then it adds padding, spacing, and border width, as appropriate. Recall that all containers must honor their border width, set with gtk_container_set_border_width() and available as the border_width field in the GtkContainer instance struct.

When reading this code, it may help to know that GtkBox stores a small struct for each child widget in its children field. The struct looks like this:


typedef struct _GtkBoxChild   GtkBoxChild;

struct _GtkBoxChild
{
  GtkWidget *widget;
  guint16 padding;
  guint expand : 1;
  guint fill : 1;
  guint pack : 1;
};
      

Size allocation is more complex; here, all the box-packing flags come into play. It will probably take you a while to fully understand this function, but there is no need to; the important thing is to see how layout takes place via size allocation.


static void
gtk_vbox_size_allocate (GtkWidget     *widget,
                        GtkAllocation *allocation)
{
  GtkBox *box;
  GtkBoxChild *child;
  GList *children;
  GtkAllocation child_allocation;
  gint nvis_children;
  gint nexpand_children;
  gint child_height;
  gint height;
  gint extra;
  gint y;

  g_return_if_fail (widget != NULL);
  g_return_if_fail (GTK_IS_VBOX (widget));
  g_return_if_fail (allocation != NULL);

  box = GTK_BOX (widget);
  widget->allocation = *allocation;

  nvis_children = 0;
  nexpand_children = 0;
  children = box->children;

  while (children)
    {
      child = children->data;
      children = children->next;

      if (GTK_WIDGET_VISIBLE (child->widget))
        {
          nvis_children += 1;
          if (child->expand)
            nexpand_children += 1;
        }
    }

  if (nvis_children > 0)
    {
      if (box->homogeneous)
        {
          height = (allocation->height -
                   GTK_CONTAINER (box)->border_width * 2 -
                   (nvis_children - 1) * box->spacing);
          extra = height / nvis_children;
        }
      else if (nexpand_children > 0)
        {
          height = (gint) allocation->height - (gint) widget->requisition.height;
          extra = height / nexpand_children;
        }
      else
        {
          height = 0;
          extra = 0;
        }

      y = allocation->y + GTK_CONTAINER (box)->border_width;
      child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width;
      child_allocation.width = MAX (1, (gint) allocation->width - (gint) GTK_CONTAINER (box)->border_width * 2);

      children = box->children;
      while (children)
        {
          child = children->data;
          children = children->next;

          if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
            {
              if (box->homogeneous)
                {
                  if (nvis_children == 1)
                    child_height = height;
                  else
                    child_height = extra;

                  nvis_children -= 1;
                  height -= extra;
                }
              else
                {
                  GtkRequisition child_requisition;

                  gtk_widget_get_child_requisition (child->widget, &child_requisition);
                  child_height = child_requisition.height + child->padding * 2;

                  if (child->expand)
                    {
                      if (nexpand_children == 1)
                        child_height += height;
                      else
                        child_height += extra;

                      nexpand_children -= 1;
                      height -= extra;
                    }
                }

              if (child->fill)
                {
                  child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
                  child_allocation.y = y + child->padding;
                }
              else
                {
                  GtkRequisition child_requisition;

                  gtk_widget_get_child_requisition (child->widget, &child_requisition);
                  child_allocation.height = child_requisition.height;
                  child_allocation.y = y + (child_height - child_allocation.height) / 2;
                }

              gtk_widget_size_allocate (child->widget, &child_allocation);

              y += child_height + box->spacing;
            }
        }

      y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width;

      children = box->children;
      while (children)
        {
          child = children->data;
          children = children->next;

          if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
            {
              GtkRequisition child_requisition;
              gtk_widget_get_child_requisition (child->widget, &child_requisition);

              if (box->homogeneous)
                {
                  if (nvis_children == 1)
                    child_height = height;
                  else
                    child_height = extra;

                  nvis_children -= 1;
                  height -= extra;
                }
              else
                {
                  child_height = child_requisition.height + child->padding * 2;

                  if (child->expand)
                    {
                      if (nexpand_children == 1)
                        child_height += height;
                      else
                        child_height += extra;

                      nexpand_children -= 1;
                      height -= extra;
                    }
                }

              if (child->fill)
                {
                  child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
                  child_allocation.y = y + child->padding - child_height;
                }
              else
                {
                  child_allocation.height = child_requisition.height;
                  child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height;
                }

              gtk_widget_size_allocate (child->widget, &child_allocation);

              y -= (child_height + box->spacing);
            }
        }
    }
}
      
Gtk+/Gnome Application Development
Prev Home Next

 
 
  Published under free license. Design by Interspire