summaryrefslogtreecommitdiff
path: root/gtk/gtkwidget.c
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.van.berkom@gmail.com>2010-10-21 22:53:06 +0900
committerTristan Van Berkom <tristan.van.berkom@gmail.com>2010-10-21 22:53:06 +0900
commit86b3c1b65e6fefc6f686279b1bc15b10895b61fe (patch)
tree8f1c5ec622a2e25e76261775ae9dec14d77b0f2a /gtk/gtkwidget.c
parent5e8baa5f634fab61c1e9837bb26b2d10f07e8c72 (diff)
downloadgtk+-86b3c1b65e6fefc6f686279b1bc15b10895b61fe.tar.gz
Enhanced GtkWidget documentation with regards to height-for-width geometry management.
Diffstat (limited to 'gtk/gtkwidget.c')
-rw-r--r--gtk/gtkwidget.c229
1 files changed, 173 insertions, 56 deletions
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 49420c9e0a..a681dd3375 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -72,73 +72,190 @@
* <refsect2 id="geometry-management">
* <title>Height-for-width Geometry Management</title>
* <para>
- * GTK+ uses a height-for-width (and width-for-height) geometry management system.
- * Height-for-width means that a widget can change how much vertical space it needs,
- * depending on the amount of horizontal space that it is given (and similar for
- * width-for-height). The most common example is a label that reflows to fill up the
- * available width, wraps to fewer lines, and therefore needs less height.
- *
- * GTK+'s traditional two-pass <link linkend="size-allocation">size-allocation</link>
- * algorithm does not allow this flexibility. #GtkWidget provides a default
- * implementation of the height-for-width methods for existing widgets,
- * which always requests the same height, regardless of the available width.
- *
- * Some important things to keep in mind when implementing
- * height-for-width and when using it in container
- * implementations.
- *
- * The geometry management system will query a logical hierarchy in
+ * GTK+ uses a height-for-width (and width-for-height) geometry management
+ * system Height-for-width means that a widget can change how much
+ * vertical space it needs, depending on the amount of horizontal space
+ * that it is given (and similar for width-for-height). The most common
+ * example is a label that reflows to fill up the available width, wraps
+ * to fewer lines, and therefore needs less height.
+ *
+ * Height-for-width geometry management is implemented in GTK+ by way
+ * of five virtual methods:
+ * <variablelist>
+ * <varlistentry>
+ * <term>#GtkWidgetClass.get_request_mode()</term>
+ * <listitem>
+ * This allows a widget to tell it's parent container whether
+ * it preferrs to be allocated in %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH
+ * or %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT mode.
+ *
+ * %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH means the widget preferrs to
+ * have #GtkWidgetClass.get_preferred_width() called and then
+ * #GtkWidgetClass.get_preferred_height_for_width() and is the
+ * default return for unimplemented cases.
+ *
+ * However it's important to note (as described below) that any
+ * widget which trades height-for-width must respond properly to
+ * both #GtkSizeRequestModes since it might be queried in either
+ * orientation by it's parent container.
+ * </listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>#GtkWidgetClass.get_preferred_width()</term>
+ * <listitem>
+ * This is called by containers to obtain the minimum and
+ * natural width of a widget. A widget will never be allocated
+ * a width less than it's minimum and will only ever be allocated
+ * a width greater than the natural width once all of the said
+ * widget's siblings have received their natural widths.
+ *
+ * Furthermore a widget will only ever be allocated a width greater
+ * than it's natural width if it was configured to receive extra
+ * expand space from it's parent container.
+ * </listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>#GtkWidgetClass.get_preferred_height()</term>
+ * <listitem>
+ * This is called by containers to obtain the minimum and
+ * natural height of a widget.
+ *
+ * A widget that does not actually trade any height for width
+ * or width for height only has to implement these two virtual
+ * methods (#GtkWidgetClass.get_preferred_width() and
+ * #GtkWidgetClass.get_preferred_height()).
+ * </listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>#GtkWidgetClass.get_preferred_height_for_width()</term>
+ * <listitem>
+ * This is similar to #GtkWidgetClass.get_preferred_height() except
+ * that it is passed a contextual width to request height for. By
+ * implementing this virtual method it is possible for a #GtkLabel
+ * to tell it's parent how much height would be required if the
+ * label were to be allocated a said width.
+ * </listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>#GtkWidgetClass.get_preferred_width_for_height()</term>
+ * <listitem>
+ * This is analogous to #GtkWidgetClass.get_preferred_height_for_width()
+ * except that it operates in the oposite orientation. It's rare that
+ * a widget actually does %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT requests
+ * but can happen when for example; a widget or container gets additional
+ * columns to compensate for a smaller allocated height.
+ * </listitem>
+ * </varlistentry>
+ * </variablelist>
+ *
+ * There are some important things to keep in mind when implementing
+ * height-for-width and when using it in container implementations.
+ *
+ * The geometry management system will query a widget hierarchy in
* only one orientation at a time. When widgets are initially queried
- * for their minimum sizes it is generally done in a dual pass
- * in the direction chosen by the toplevel.
- *
- * For instance when queried in the normal height-for-width mode:
- * First the default minimum and natural width for each widget
- * in the interface will computed and collectively returned to
- * the toplevel by way of gtk_widget_get_preferred_width().
- * Next, the toplevel will use the minimum width to query for the
- * minimum height contextual to that width using
- * gtk_widget_get_preferred_height_for_width(), which will also
- * be a highly recursive operation. This minimum-for-minimum size can
- * be used to set the minimum size constraint on the toplevel.
- *
- * When allocating, each container can use the minimum and natural
- * sizes reported by their children to allocate natural sizes and
- * expose as much content as possible with the given allocation.
- *
- * That means that the request operation at allocation time will
- * usually fire again in contexts of different allocated sizes than
- * the ones originally queried for. #GtkWidget caches a
- * small number of results to avoid re-querying for the same
- * allocated size in one allocation cycle.
- *
- * A widget that does not actually do height-for-width
- * or width-for-height size negotiations only has to implement
- * #GtkWidgetClass.get_preferred_width() and
- * #GtkWidgetClass.get_preferred_height().
+ * for their minimum sizes it is generally done in two initial passes
+ * in the #GtkSizeRequestMode chosen by the toplevel.
+ *
+ * For example, when queried in the normal
+ * %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH mode:
+ * First, the default minimum and natural width for each widget
+ * in the interface will be computed using gtk_width_get_preferred_width().
+ * Because the preferred widths for each container depends on the preferred
+ * widths of thier children, this information propagates up the hierarchy,
+ * and finally a minimum and natural width is determined for the entire
+ * toplevel. Next, the toplevel will use the minimum width to query for the
+ * minimum height contextual to that width using
+ * gtk_widget_get_preferred_height_for_width(), which will also be a highly
+ * recursive operation. The minimum height for the minimum width is normally
+ * used to set the minimum size constraint on the toplevel
+ * (unless gtk_window_set_geometry_hints() is explicitly used instead).
+ *
+ * After the toplevel window has initially requested it's size in both
+ * dimensions it can go on to allocate itself a reasonable size (or a size
+ * previously specified with gtk_window_set_default_size()). During the
+ * recursive allocation process it's important to note that request cycles
+ * will be recursively executed while container widgets allocate their children.
+ * Each container widget, once allocated a size will go on to first share the
+ * space in one orientation among its children and then request each child's
+ * height for their target allocated width or width for allocated height
+ * depending. In this way a #GtkWidget will typically be requested its size
+ * a number of times before actually being allocated a size, the size a
+ * widget is finally allocated can of course differ from the size it
+ * requested. For this reason; #GtkWidget caches a small number of results
+ * to avoid re-querying for the same sizes in one allocation cycle.
+ *
+ * See <link linkend="container-geometry-management">GtkContainer's
+ * geometry management section</link>
+ * to learn more about how height-for-width allocations are performed
+ * by container widgets.
*
* If a widget does move content around to smartly use up the
- * allocated size, then it must support the request properly in
- * both orientations; even if the request only makes sense in
- * one orientation.
+ * allocated size, then it must support the request in both
+ * #GtkSizeRequestModes even if the widget in question only
+ * trades sizes in a single orientation.
*
* For instance, a #GtkLabel that does height-for-width word wrapping
- * will not expect to have #GtkWidgetClass.get_preferred_height() called because that
- * call is specific to a width-for-height request. In this case the
- * label must return the heights contextual to its minimum possible
- * width. By following this rule any widget that handles height-for-width
- * or width-for-height requests will always be allocated at least
- * enough space to fit its own content.
+ * will not expect to have #GtkWidgetClass.get_preferred_height() called
+ * because that call is specific to a width-for-height request. In this
+ * case the label must return the heights required for it's own minimum
+ * possible width. By following this rule any widget that handles
+ * height-for-width or width-for-height requests will always be allocated
+ * at least enough space to fit its own content.
+ *
+ * Here are some examples of how a %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH widget
+ * generally deals with width-for-height requests, for #GtkWidgetClass.get_preferred_height()
+ * it will do:
+ * <programlisting><![CDATA[
+ * static void
+ * foo_widget_get_preferred_height (GtkWidget *widget, gint *min_height, gint *nat_height)
+ * {
+ * if (i_am_in_height_for_width_mode)
+ * {
+ * gint min_width;
+ *
+ * GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
+ * GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width,
+ * min_height, nat_height);
+ * }
+ * else
+ * {
+ * ... some widgets do both, for instance if a GtkLabel is rotated to 90 degrees
+ * it will return the minimum and natural height for the rotated label here.
+ * }
+ * }
+ * ]]></programlisting>
+ *
+ * And in #GtkWidgetClass.get_preferred_width_for_height() it will simply return
+ * the minimum and natural width:
+ *
+ * <programlisting><![CDATA[
+ * static void
+ * foo_widget_get_preferred_width_for_height (GtkWidget *widget, gint for_height,
+ * gint *min_width, gint *nat_width)
+ * {
+ * if (i_am_in_height_for_width_mode)
+ * {
+ * GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, min_width, nat_width);
+ * }
+ * else
+ * {
+ * ... again if a widget is sometimes operating in width-for-height mode
+ * (like a rotated GtkLabel) it can go ahead and do it's real width for
+ * height calculation here.
+ * }
+ * }
+ * ]]></programlisting>
*
* Often a widget needs to get its own request during size request or
* allocation, for example when computing height it may need to also
- * compute width, or when deciding how to use an allocation the widget may
- * need to know its natural size. In these cases, the widget should be
- * careful to call its virtual methods directly, like this:
+ * compute width, or when deciding how to use an allocation the widget
+ * may need to know its natural size. In these cases, the widget should
+ * be careful to call its virtual methods directly, like this:
* <example>
* <title>Widget calling its own size request method.</title>
* <programlisting>
- * GTK_WIDGET_GET_CLASS(widget)-&gt;get_preferred_width (widget), &min, &natural);
+ * GTK_WIDGET_GET_CLASS(widget)-&gt;get_preferred_width (widget),
+ * &min, &natural);
* </programlisting>
* </example>
*