Merge branch 'native-layout-incubator'

Conflicts:
	configure.in
	docs/reference/gtk/tmpl/gtkaction.sgml
	docs/reference/gtk/tmpl/gtkbuilder.sgml
	gdk/directfb/gdkkeys-directfb.c
	gdk/gdk.symbols
	gdk/x11/gdkwindow-x11.c
	gtk/gtkalignment.c
	gtk/gtkbox.c
	gtk/gtkbutton.c
	gtk/gtkcelleditable.c
	gtk/gtkfilechooser.c
	gtk/gtkframe.c
	gtk/gtkinvisible.c
	gtk/gtklabel.c
	gtk/gtkscrolledwindow.c
	gtk/gtksearchenginetracker.c
	gtk/gtktextview.c
	gtk/gtktoolbutton.c
	gtk/gtktooltip.c
	gtk/gtkviewport.c
	gtk/gtkwidget.c
	gtk/gtkwindow.c
	po-properties/ca@valencia.po
	po-properties/es.po
	po-properties/kn.po
	po-properties/mr.po
	po/ca.po
	po/ca@valencia.po
	po/el.po
	po/es.po
	po/gl.po
	po/id.po
	po/kn.po
	po/lv.po
	po/mr.po
	po/th.po
This commit is contained in:
Matthias Clasen 2010-04-30 17:56:50 -04:00
commit db76c77b81
30 changed files with 3921 additions and 1087 deletions

View File

@ -33,9 +33,16 @@ in a two-dimensional grid.
</para>
<para>
To fulfill its task, a layout container must negotiate the size requirements
with its parent and its children. This negotiation is carried out in two
phases, <firstterm>size requisition</firstterm> and <firstterm>size
allocation</firstterm>.
with its parent and its children. The basic form of this negotiation is
carried out in two phases, <firstterm>size requisition</firstterm> and
<firstterm>size allocation</firstterm>, which are implemented by the
size_request() and size_allocate() virtual functions in #GtkWidget.
</para>
<para>
GTK+ also supports a more complicated form of size negotiation called
<firstterm>width-for-height</firstterm> (and its dual
<firstterm>height-for-width</firstterm>). See #GtkExtendedLayout
to learn more about width-for-height geometry management.
</para>
<refsect2 id="size-requisition"><title>Size Requisition</title>
<para>

View File

@ -141,7 +141,7 @@ the clipboard. Only labels that contain useful-to-copy information
</para>
</refsect2>
<refsect2>
<refsect2 id="label-text-layout">
<title>Text layout</title>
<para>
@ -159,7 +159,19 @@ gtk_label_set_justify() sets how the lines in a label align
with one another. If you want to set how the label as a whole
aligns in its available space, see gtk_misc_set_alignment().
</para>
<para>
The #GtkLabel:width-chars and #GtkLabel:max-width-chars properties
can be used to control the size allocation of ellipsized or wrapped
labels. For ellipsizing labels, if either is specified (and less
than the actual text size), it is used as the minimum width, and the actual
text size is used as the natural width of the label. For wrapping labels,
width-chars is used as the minimum width, if specified, and max-width-chars
is used as the natural width. Even if max-width-chars specified, wrapping
labels will be rewrapped to use all of the available width.
</para>
<note><para>Note that the interpretation of #GtkLabel:width-chars and
#GtkLabel:max-width-chars has changed a bit with the introduction of
width-for-height geometry management and #GtkExtendedLayout.</para></note>
</refsect2>
<refsect2>

View File

@ -212,6 +212,7 @@ gtk_public_h_sources = \
gtkenums.h \
gtkeventbox.h \
gtkexpander.h \
gtkextendedlayout.h \
gtkfilechooser.h \
gtkfilechooserbutton.h \
gtkfilechooserdialog.h \
@ -466,6 +467,7 @@ gtk_base_c_sources = \
gtkentrycompletion.c \
gtkeventbox.c \
gtkexpander.c \
gtkextendedlayout.c \
gtkfilechooser.c \
gtkfilechooserbutton.c \
gtkfilechooserdefault.c \

View File

@ -83,6 +83,7 @@
#include <gtk/gtkenums.h>
#include <gtk/gtkeventbox.h>
#include <gtk/gtkexpander.h>
#include <gtk/gtkextendedlayout.h>
#include <gtk/gtkfixed.h>
#include <gtk/gtkfilechooser.h>
#include <gtk/gtkfilechooserbutton.h>

View File

@ -1504,6 +1504,17 @@ gtk_expander_set_use_underline
#endif
#endif
#if IN_HEADER(__GTK_EXTENDED_LAYOUT_H__)
#if IN_FILE(__GTK_EXTENDED_LAYOUT_C__)
gtk_extended_layout_get_type G_GNUC_CONST
gtk_extended_layout_get_desired_height
gtk_extended_layout_get_desired_width
gtk_extended_layout_get_height_for_width
gtk_extended_layout_get_width_for_height
gtk_extended_layout_is_height_for_width
#endif
#endif
#if IN_HEADER(__GTK_FILE_CHOOSER_H__)
#if IN_FILE(__GTK_FILE_CHOOSER_C__)
gtk_file_chooser_add_filter

View File

@ -45,6 +45,7 @@
#include "config.h"
#include "gtkalignment.h"
#include "gtkextendedlayout.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
@ -73,8 +74,6 @@ struct _GtkAlignmentPrivate
guint padding_right;
};
static void gtk_alignment_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_alignment_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_alignment_set_property (GObject *object,
@ -86,7 +85,17 @@ static void gtk_alignment_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (GtkAlignment, gtk_alignment, GTK_TYPE_BIN)
static void gtk_alignment_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_alignment_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_alignment_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
G_DEFINE_TYPE_WITH_CODE (GtkAlignment, gtk_alignment, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_alignment_extended_layout_init))
static void
gtk_alignment_class_init (GtkAlignmentClass *class)
@ -100,7 +109,6 @@ gtk_alignment_class_init (GtkAlignmentClass *class)
gobject_class->set_property = gtk_alignment_set_property;
gobject_class->get_property = gtk_alignment_get_property;
widget_class->size_request = gtk_alignment_size_request;
widget_class->size_allocate = gtk_alignment_size_allocate;
g_object_class_install_property (gobject_class,
@ -462,34 +470,6 @@ gtk_alignment_set (GtkAlignment *alignment,
}
static void
gtk_alignment_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkBin *bin;
GtkAlignmentPrivate *priv;
bin = GTK_BIN (widget);
priv = GTK_ALIGNMENT_GET_PRIVATE (widget);
requisition->width = GTK_CONTAINER (widget)->border_width * 2;
requisition->height = GTK_CONTAINER (widget)->border_width * 2;
if (bin->child && gtk_widget_get_visible (bin->child))
{
GtkRequisition child_requisition;
gtk_widget_size_request (bin->child, &child_requisition);
requisition->width += child_requisition.width;
requisition->height += child_requisition.height;
/* Request extra space for the padding: */
requisition->width += (priv->padding_left + priv->padding_right);
requisition->height += (priv->padding_top + priv->padding_bottom);
}
}
static void
gtk_alignment_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -497,7 +477,6 @@ gtk_alignment_size_allocate (GtkWidget *widget,
GtkAlignment *alignment;
GtkBin *bin;
GtkAllocation child_allocation;
GtkRequisition child_requisition;
gint width, height;
gint border_width;
gint padding_horizontal, padding_vertical;
@ -512,7 +491,10 @@ gtk_alignment_size_allocate (GtkWidget *widget,
if (bin->child && gtk_widget_get_visible (bin->child))
{
gtk_widget_get_child_requisition (bin->child, &child_requisition);
GtkExtendedLayout *layout = GTK_EXTENDED_LAYOUT (bin->child);
gint child_nat_width;
gint child_nat_height;
gint child_width, child_height;
border_width = GTK_CONTAINER (alignment)->border_width;
@ -523,15 +505,36 @@ gtk_alignment_size_allocate (GtkWidget *widget,
width = MAX (1, allocation->width - padding_horizontal - 2 * border_width);
height = MAX (1, allocation->height - padding_vertical - 2 * border_width);
if (width > child_requisition.width)
child_allocation.width = (child_requisition.width *
if (gtk_extended_layout_is_height_for_width (layout))
{
gtk_extended_layout_get_desired_width (layout, NULL, &child_nat_width);
child_width = MIN (width, child_nat_width);
gtk_extended_layout_get_height_for_width (layout, child_width, NULL, &child_nat_height);
child_height = MIN (height, child_nat_height);
}
else
{
gtk_extended_layout_get_desired_height (layout, NULL, &child_nat_height);
child_height = MIN (height, child_nat_height);
gtk_extended_layout_get_width_for_height (layout, child_height, NULL, &child_nat_width);
child_width = MIN (width, child_nat_width);
}
if (width > child_width)
child_allocation.width = (child_width *
(1.0 - alignment->xscale) +
width * alignment->xscale);
else
child_allocation.width = width;
if (height > child_requisition.height)
child_allocation.height = (child_requisition.height *
if (height > child_height)
child_allocation.height = (child_height *
(1.0 - alignment->yscale) +
height * alignment->yscale);
else
@ -548,6 +551,75 @@ gtk_alignment_size_allocate (GtkWidget *widget,
}
}
static void
gtk_alignment_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_alignment_get_desired_width;
iface->get_desired_height = gtk_alignment_get_desired_height;
}
static void
gtk_alignment_get_desired_size (GtkExtendedLayout *layout,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
{
GtkWidget *child;
GtkAlignmentPrivate *priv;
gint minimum, natural;
priv = GTK_ALIGNMENT_GET_PRIVATE (layout);
natural = minimum = GTK_CONTAINER (layout)->border_width * 2;
if ((child = gtk_bin_get_child (GTK_BIN (layout))) && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
/* Request extra space for the padding: */
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum += (priv->padding_left + priv->padding_right);
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (child),
&child_min, &child_nat);
}
else
{
minimum += (priv->padding_top + priv->padding_bottom);
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (child),
&child_min, &child_nat);
}
natural = minimum;
minimum += child_min;
natural += child_nat;
}
if (minimum_size)
*minimum_size = minimum;
if (natural_size)
*natural_size = natural;
}
static void
gtk_alignment_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_alignment_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
}
static void
gtk_alignment_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_alignment_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
}
/**
* gtk_alignment_set_padding:
* @alignment: a #GtkAlignment

View File

@ -1167,13 +1167,14 @@ gtk_assistant_size_request (GtkWidget *widget,
requisition->height = height;
}
static void
gtk_assistant_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkAssistant *assistant = GTK_ASSISTANT (widget);
GtkAssistantPrivate *priv = assistant->priv;
GtkRequisition header_requisition;
GtkRequisition header_requisition, action_requisition, sidebar_requisition;
GtkAllocation child_allocation, header_allocation;
gint header_padding, content_padding;
gboolean rtl;
@ -1200,24 +1201,28 @@ gtk_assistant_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (priv->header_image, &header_allocation);
/* Action area */
gtk_widget_get_child_requisition (priv->action_area, &action_requisition);
child_allocation.x = GTK_CONTAINER (widget)->border_width;
child_allocation.y = allocation->height -
GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
GTK_CONTAINER (widget)->border_width - action_requisition.height;
child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
child_allocation.height = priv->action_area->requisition.height;
child_allocation.height = action_requisition.height;
gtk_widget_size_allocate (priv->action_area, &child_allocation);
/* Sidebar */
gtk_widget_get_child_requisition (priv->sidebar_image, &sidebar_requisition);
if (rtl)
child_allocation.x = allocation->width -
GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
GTK_CONTAINER (widget)->border_width - sidebar_requisition.width;
else
child_allocation.x = GTK_CONTAINER (widget)->border_width;
child_allocation.y = GTK_CONTAINER (widget)->border_width +
priv->header_image->allocation.height + 2 * header_padding;
child_allocation.width = priv->sidebar_image->requisition.width;
child_allocation.width = sidebar_requisition.width;
child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height;

View File

@ -39,6 +39,7 @@
#include "config.h"
#include "gtkbin.h"
#include "gtkextendedlayout.h"
#include "gtkintl.h"
#include "gtkalias.h"
@ -53,7 +54,22 @@ static void gtk_bin_forall (GtkContainer *container,
static GType gtk_bin_child_type (GtkContainer *container);
G_DEFINE_ABSTRACT_TYPE (GtkBin, gtk_bin, GTK_TYPE_CONTAINER)
static void gtk_bin_extended_layout_init (GtkExtendedLayoutIface *iface);
static gboolean gtk_bin_is_height_for_width (GtkExtendedLayout *layout);
static void gtk_bin_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width);
static void gtk_bin_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height);
static GtkExtendedLayoutIface *parent_extended_layout_iface;
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkBin, gtk_bin, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_bin_extended_layout_init))
static void
gtk_bin_class_init (GtkBinClass *class)
@ -141,6 +157,109 @@ gtk_bin_forall (GtkContainer *container,
(* callback) (bin->child, callback_data);
}
/* GtkBin widgets define the padding and borders independantly so
* we cannot provide a generic get_desired_size() for the same reason
* we never implemented size_request() here.
*
* But for cases where the GtkBin class's padding is constant and
* does not vary based on allocation (most cases), we can at least
* deduce a common code path for the get_width_for_height()/get_height_for_width()
* cases by using the delta of the base size requsts.
*/
static void
gtk_bin_extended_layout_init (GtkExtendedLayoutIface *iface)
{
parent_extended_layout_iface = g_type_interface_peek_parent (iface);
iface->is_height_for_width = gtk_bin_is_height_for_width;
iface->get_width_for_height = gtk_bin_get_width_for_height;
iface->get_height_for_width = gtk_bin_get_height_for_width;
}
static gboolean
gtk_bin_is_height_for_width (GtkExtendedLayout *layout)
{
GtkBin *bin = GTK_BIN (layout);
if (bin->child)
return gtk_extended_layout_is_height_for_width (GTK_EXTENDED_LAYOUT (bin->child));
return TRUE;
}
static void
get_child_padding_delta (GtkBin *bin,
gint *delta_h,
gint *delta_v)
{
gint hmin, vmin, child_hmin, child_vmin;
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (bin), &hmin, NULL);
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (bin), &vmin, NULL);
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (bin->child), &child_hmin, NULL);
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (bin->child), &child_vmin, NULL);
*delta_h = hmin - child_hmin;
*delta_v = vmin - child_vmin;
}
static void
gtk_bin_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width)
{
GtkBin *bin = GTK_BIN (layout);
gint hdelta, vdelta, child_min, child_nat;
if (bin->child)
{
get_child_padding_delta (bin, &hdelta, &vdelta);
gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (bin->child),
height - vdelta,
&child_min, &child_nat);
if (minimum_width)
*minimum_width = child_min + hdelta;
if (natural_width)
*natural_width = child_nat + hdelta;
}
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, minimum_width, natural_width);
}
static void
gtk_bin_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height)
{
GtkBin *bin = GTK_BIN (layout);
gint hdelta, vdelta, child_min, child_nat;
if (bin->child)
{
get_child_padding_delta (bin, &hdelta, &vdelta);
gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (bin->child),
width - hdelta,
&child_min, &child_nat);
if (minimum_height)
*minimum_height = child_min + vdelta;
if (natural_height)
*natural_height = child_nat + vdelta;
}
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, minimum_height, natural_height);
}
/**
* gtk_bin_get_child:
* @bin: a #GtkBin

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@
#include "gtkstock.h"
#include "gtkiconfactory.h"
#include "gtkactivatable.h"
#include "gtkextendedlayout.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
@ -111,8 +112,6 @@ static void gtk_button_unrealize (GtkWidget * widget);
static void gtk_button_map (GtkWidget * widget);
static void gtk_button_unmap (GtkWidget * widget);
static void gtk_button_style_set (GtkWidget * widget, GtkStyle * prev_style);
static void gtk_button_size_request (GtkWidget * widget,
GtkRequisition * requisition);
static void gtk_button_size_allocate (GtkWidget * widget,
GtkAllocation * allocation);
static gint gtk_button_expose (GtkWidget * widget, GdkEventExpose * event);
@ -159,11 +158,21 @@ static void gtk_button_set_related_action (GtkButton *button,
static void gtk_button_set_use_action_appearance (GtkButton *button,
gboolean use_appearance);
static void gtk_button_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_button_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_button_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static guint button_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
gtk_button_activatable_interface_init))
gtk_button_activatable_interface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_button_extended_layout_init))
static void
gtk_button_class_init (GtkButtonClass *klass)
@ -191,7 +200,6 @@ gtk_button_class_init (GtkButtonClass *klass)
widget_class->map = gtk_button_map;
widget_class->unmap = gtk_button_unmap;
widget_class->style_set = gtk_button_style_set;
widget_class->size_request = gtk_button_size_request;
widget_class->size_allocate = gtk_button_size_allocate;
widget_class->expose_event = gtk_button_expose;
widget_class->button_press_event = gtk_button_button_press;
@ -1332,49 +1340,6 @@ gtk_button_get_props (GtkButton *button,
gtk_widget_style_get (widget, "interior-focus", interior_focus, NULL);
}
static void
gtk_button_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkButton *button = GTK_BUTTON (widget);
GtkBorder default_border;
GtkBorder inner_border;
gint focus_width;
gint focus_pad;
gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
gtk_widget_style_get (GTK_WIDGET (widget),
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
requisition->width = ((GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->xthickness) * 2 +
inner_border.left + inner_border.right);
requisition->height = ((GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->ythickness) * 2 +
inner_border.top + inner_border.bottom);
if (gtk_widget_get_can_default (widget))
{
requisition->width += default_border.left + default_border.right;
requisition->height += default_border.top + default_border.bottom;
}
if (GTK_BIN (button)->child && gtk_widget_get_visible (GTK_BIN (button)->child))
{
GtkRequisition child_requisition;
gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
requisition->width += child_requisition.width;
requisition->height += child_requisition.height;
}
requisition->width += 2 * (focus_width + focus_pad);
requisition->height += 2 * (focus_width + focus_pad);
}
static void
gtk_button_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -1803,6 +1768,95 @@ gtk_button_finish_activate (GtkButton *button,
gtk_button_clicked (button);
}
static void
gtk_button_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_button_get_desired_width;
iface->get_desired_height = gtk_button_get_desired_height;
}
static void
gtk_button_get_desired_size (GtkExtendedLayout *layout,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
{
GtkButton *button = GTK_BUTTON (layout);
GtkWidget *child;
GtkBorder default_border;
GtkBorder inner_border;
gint focus_width;
gint focus_pad;
gint minimum, natural;
gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
gtk_widget_style_get (GTK_WIDGET (layout),
"focus-line-width", &focus_width,
"focus-padding", &focus_pad,
NULL);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum = ((GTK_CONTAINER (layout)->border_width +
GTK_WIDGET (layout)->style->xthickness) * 2 +
inner_border.left + inner_border.right);
if (gtk_widget_get_can_default (GTK_WIDGET (layout)))
minimum += default_border.left + default_border.right;
}
else
{
minimum = ((GTK_CONTAINER (layout)->border_width +
GTK_WIDGET (layout)->style->ythickness) * 2 +
inner_border.top + inner_border.bottom);
if (gtk_widget_get_can_default (GTK_WIDGET (layout)))
minimum += default_border.top + default_border.bottom;
}
minimum += 2 * (focus_width + focus_pad);
natural = minimum;
if ((child = gtk_bin_get_child (GTK_BIN (button))) &&
gtk_widget_get_visible (child))
{
gint child_min, child_nat;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (child),
&child_min, &child_nat);
else
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (child),
&child_min, &child_nat);
minimum += child_min;
natural += child_nat;
}
if (minimum_size)
*minimum_size = minimum;
if (natural_size)
*natural_size = natural;
}
static void
gtk_button_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_button_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
}
static void
gtk_button_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_button_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
}
/**
* gtk_button_set_label:
* @button: a #GtkButton

View File

@ -1370,6 +1370,9 @@ _gtk_container_queue_resize (GtkContainer *container)
{
GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_WIDTH_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_HEIGHT_REQUEST_NEEDED);
if ((resize_container && widget == GTK_WIDGET (resize_container)) ||
!widget->parent)
break;

View File

@ -47,7 +47,8 @@ typedef enum {
GTK_DEBUG_GEOMETRY = 1 << 8,
GTK_DEBUG_ICONTHEME = 1 << 9,
GTK_DEBUG_PRINTING = 1 << 10,
GTK_DEBUG_BUILDER = 1 << 11
GTK_DEBUG_BUILDER = 1 << 11,
GTK_DEBUG_EXTENDED_LAYOUT = 1 << 12,
} GtkDebugFlag;
#ifdef G_ENABLE_DEBUG

527
gtk/gtkextendedlayout.c Normal file
View File

@ -0,0 +1,527 @@
/* gtkextendedlayout.c
* Copyright (C) 2007-2010 Openismus GmbH
*
* Authors:
* Mathias Hasselmann <mathias@openismus.com>
* Tristan Van Berkom <tristan.van.berkom@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
/**
* SECTION:gtkextendedlayout
* @Short_Description: Height-for-width geometry management
* @Title: GtkExtendedLayout
*
* The extended layout is GTK+'s height-for-width (and width-for-height)
* geometry management system.
*
* <refsect2>
* <title>Implementing GtkExtendedLayout</title>
* <para>
* Some important things to keep in mind when implementing
* or using the extended layout.
*
* The Extended Layout system will query a logical 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_extended_layout_get_desired_width().
* Next, the toplevel will use the minimum width to query for the
* minimum height contextual to that width using
* gtk_extended_layout_get_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. #GtkExtendedLayout 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
* get_desired_width() and get_desired_height().
*
* 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.
*
* For instance, a GtkLabel that does height-for-width word wrapping
* will not expect to have get_desired_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.
* </para>
* </refsect2>
*/
#include <config.h>
#include "gtkextendedlayout.h"
#include "gtksizegroup.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
/* With extended layout, a widget may be requested
* its width for 2 or maximum 3 heights in one resize
*/
#define N_CACHED_SIZES 3
typedef struct
{
guint age;
gint for_size;
gint minimum_size;
gint natural_size;
} DesiredSize;
typedef struct {
DesiredSize desired_widths[N_CACHED_SIZES];
DesiredSize desired_heights[N_CACHED_SIZES];
guint8 cached_width_age;
guint8 cached_height_age;
} ExtendedLayoutCache;
static GQuark quark_cache = 0;
GType
gtk_extended_layout_get_type (void)
{
static GType extended_layout_type = 0;
if (G_UNLIKELY(!extended_layout_type))
{
extended_layout_type =
g_type_register_static_simple (G_TYPE_INTERFACE, I_("GtkExtendedLayout"),
sizeof (GtkExtendedLayoutIface),
NULL, 0, NULL, 0);
g_type_interface_add_prerequisite (extended_layout_type, GTK_TYPE_WIDGET);
quark_cache = g_quark_from_static_string ("gtk-extended-layout-cache");
}
return extended_layout_type;
}
/* looks for a cached size request for this for_size. If not
* found, returns the oldest entry so it can be overwritten
*
* Note that this caching code was directly derived from
* the Clutter toolkit.
*/
static gboolean
get_cached_desired_size (gint for_size,
DesiredSize *cached_sizes,
DesiredSize **result)
{
guint i;
*result = &cached_sizes[0];
for (i = 0; i < N_CACHED_SIZES; i++)
{
DesiredSize *cs;
cs = &cached_sizes[i];
if (cs->age > 0 && cs->for_size == for_size)
{
*result = cs;
return TRUE;
}
else if (cs->age < (*result)->age)
{
*result = cs;
}
}
return FALSE;
}
static void
destroy_cache (ExtendedLayoutCache *cache)
{
g_slice_free (ExtendedLayoutCache, cache);
}
static ExtendedLayoutCache *
get_cache (GtkExtendedLayout *layout,
gboolean create)
{
ExtendedLayoutCache *cache;
cache = g_object_get_qdata (G_OBJECT (layout), quark_cache);
if (!cache && create)
{
cache = g_slice_new0 (ExtendedLayoutCache);
cache->cached_width_age = 1;
cache->cached_height_age = 1;
g_object_set_qdata_full (G_OBJECT (layout), quark_cache, cache,
(GDestroyNotify)destroy_cache);
}
return cache;
}
static void
do_size_request (GtkWidget *widget)
{
if (GTK_WIDGET_REQUEST_NEEDED (widget))
{
gtk_widget_ensure_style (widget);
GTK_PRIVATE_UNSET_FLAG (widget, GTK_REQUEST_NEEDED);
g_signal_emit_by_name (widget,
"size-request",
&widget->requisition);
}
}
static void
compute_size_for_orientation (GtkExtendedLayout *layout,
GtkSizeGroupMode orientation,
gint for_size,
gint *minimum_size,
gint *natural_size)
{
ExtendedLayoutCache *cache;
DesiredSize *cached_size;
GtkWidget *widget;
gboolean found_in_cache = FALSE;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
g_return_if_fail (minimum_size != NULL || natural_size != NULL);
widget = GTK_WIDGET (layout);
cache = get_cache (layout, TRUE);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
cached_size = &cache->desired_widths[0];
if (!GTK_WIDGET_WIDTH_REQUEST_NEEDED (layout))
found_in_cache = get_cached_desired_size (for_size, cache->desired_widths, &cached_size);
else
{
memset (cache->desired_widths, 0, N_CACHED_SIZES * sizeof (DesiredSize));
cache->cached_width_age = 1;
}
}
else
{
cached_size = &cache->desired_heights[0];
if (!GTK_WIDGET_HEIGHT_REQUEST_NEEDED (layout))
found_in_cache = get_cached_desired_size (for_size, cache->desired_heights, &cached_size);
else
{
memset (cache->desired_heights, 0, N_CACHED_SIZES * sizeof (DesiredSize));
cache->cached_height_age = 1;
}
}
if (!found_in_cache)
{
gint min_size = 0, nat_size = 0;
gint group_size, requisition_size;
/* Unconditional size request runs but is often unhandled. */
do_size_request (widget);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
requisition_size = widget->requisition.width;
if (for_size < 0)
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, &min_size, &nat_size);
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_width_for_height (layout, for_size, &min_size, &nat_size);
}
else
{
requisition_size = widget->requisition.height;
if (for_size < 0)
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, &min_size, &nat_size);
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_height_for_width (layout, for_size, &min_size, &nat_size);
}
/* Support for dangling "size-request" signals and forward derived
* classes that will not default to a ->get_desired_width() that
* returns the values in the ->requisition cache.
*/
min_size = MAX (min_size, requisition_size);
nat_size = MAX (nat_size, requisition_size);
cached_size->minimum_size = min_size;
cached_size->natural_size = nat_size;
cached_size->for_size = for_size;
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
cached_size->age = cache->cached_width_age;
cache->cached_width_age++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_WIDTH_REQUEST_NEEDED);
}
else
{
cached_size->age = cache->cached_height_age;
cache->cached_height_age++;
GTK_PRIVATE_UNSET_FLAG (layout, GTK_HEIGHT_REQUEST_NEEDED);
}
/* Get size groups to compute the base requisition once one
* of the values have been cached, then go ahead and update
* the cache with the sizegroup computed value.
*
* Note this is also where values from gtk_widget_set_size_request()
* are considered.
*/
group_size =
_gtk_size_group_bump_requisition (GTK_WIDGET (layout),
orientation, cached_size->minimum_size);
cached_size->minimum_size = MAX (cached_size->minimum_size, group_size);
cached_size->natural_size = MAX (cached_size->natural_size, group_size);
}
if (minimum_size)
*minimum_size = cached_size->minimum_size;
if (natural_size)
*natural_size = cached_size->natural_size;
g_assert (cached_size->minimum_size <= cached_size->natural_size);
GTK_NOTE (EXTENDED_LAYOUT,
g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d (hit cache: %s)\n",
layout, G_OBJECT_TYPE_NAME (layout),
orientation == GTK_SIZE_GROUP_HORIZONTAL ?
"width for height" : "height for width" ,
for_size,
cached_size->minimum_size,
cached_size->natural_size,
found_in_cache ? "yes" : "no"));
}
/**
* gtk_extended_layout_is_height_for_width:
* @layout: a #GtkExtendedLayout instance
*
* Gets whether the widget prefers a height-for-width layout
* or a width-for-height layout.
*
* <note><para>#GtkBin widgets generally propagate the preference of
* their child, container widgets need to request something either in
* context of their children or in context of their allocation
* capabilities.</para></note>
*
* Returns: %TRUE if the widget prefers height-for-width, %FALSE if
* the widget should be treated with a width-for-height preference.
*
* Since: 3.0
*/
gboolean
gtk_extended_layout_is_height_for_width (GtkExtendedLayout *layout)
{
GtkExtendedLayoutIface *iface;
g_return_val_if_fail (GTK_IS_EXTENDED_LAYOUT (layout), FALSE);
iface = GTK_EXTENDED_LAYOUT_GET_IFACE (layout);
if (iface->is_height_for_width)
return iface->is_height_for_width (layout);
/* By default widgets are height-for-width. */
return TRUE;
}
/**
* gtk_extended_layout_get_desired_width:
* @layout: a #GtkExtendedLayout instance
* @minimum_width: (allow-none): location to store the minimum width, or %NULL
* @natural_width: (allow-none): location to store the natural width, or %NULL
*
* Retrieves a widget's initial minimum and natural width.
*
* <note><para>This call is specific to height-for-width
* requests.</para></note>
*
* Since: 3.0
*/
void
gtk_extended_layout_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_width,
gint *natural_width)
{
compute_size_for_orientation (layout, GTK_SIZE_GROUP_HORIZONTAL,
-1, minimum_width, natural_width);
}
/**
* gtk_extended_layout_get_desired_height:
* @layout: a #GtkExtendedLayout instance
* @minimum_width: (allow-none): location to store the minimum height, or %NULL
* @natural_width: (allow-none): location to store the natural height, or %NULL
*
* Retrieves a widget's initial minimum and natural height.
*
* <note><para>This call is specific to width-for-height
* requests.</para></note>
*
* Since: 3.0
*/
void
gtk_extended_layout_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_height,
gint *natural_height)
{
compute_size_for_orientation (layout, GTK_SIZE_GROUP_VERTICAL,
-1, minimum_height, natural_height);
}
/**
* gtk_extended_layout_get_width_for_height:
* @layout: a #GtkExtendedLayout instance
* @height: the size which is available for allocation
* @minimum_size: (allow-none): location for storing the minimum size, or %NULL
* @natural_size: (allow-none): location for storing the natural size, or %NULL
*
* Retrieves a widget's desired width if it would be given
* the specified @height.
*
* Since: 3.0
*/
void
gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width)
{
compute_size_for_orientation (layout, GTK_SIZE_GROUP_HORIZONTAL,
height, minimum_width, natural_width);
}
/**
* gtk_extended_layout_get_height_for_width:
* @layout: a #GtkExtendedLayout instance
* @width: the size which is available for allocation
* @minimum_size: (allow-none): location for storing the minimum size, or %NULL
* @natural_size: (allow-none): location for storing the natural size, or %NULL
*
* Retrieves a widget's desired height if it would be given
* the specified @width.
*
* Since: 3.0
*/
void
gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height)
{
compute_size_for_orientation (layout, GTK_SIZE_GROUP_VERTICAL,
width, minimum_height, natural_height);
}
/**
* gtk_extended_layout_get_desired_size:
* @layout: a #GtkExtendedLayout instance
* @width: the size which is available for allocation
* @request_natural: Whether to base the contextual request off of the
* base natural or the base minimum
* @minimum_size: (allow-none): location for storing the minimum size, or %NULL
* @natural_size: (allow-none): location for storing the natural size, or %NULL
*
* Retrieves the minimum and natural size of a widget taking
* into account the widget's preference for height-for-width management.
*
* If request_natural is specified, the non-contextual natural value will
* be used to make the contextual request; otherwise the minimum will be used.
*
* This is used to retrieve a suitable size by container widgets which do
* not impose any restrictions on the child placement.
*
* Since: 3.0
*/
void
gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout,
gboolean request_natural,
GtkRequisition *minimum_size,
GtkRequisition *natural_size)
{
gint min_width, nat_width;
gint min_height, nat_height;
g_return_if_fail (GTK_IS_EXTENDED_LAYOUT (layout));
if (gtk_extended_layout_is_height_for_width (layout))
{
gtk_extended_layout_get_desired_width (layout, &min_width, &nat_width);
gtk_extended_layout_get_height_for_width (layout,
request_natural ? nat_width : min_width,
&min_height, &nat_height);
}
else
{
gtk_extended_layout_get_desired_height (layout, &min_height, &nat_height);
gtk_extended_layout_get_width_for_height (layout,
request_natural ? nat_height : min_height,
&min_width, &nat_width);
}
if (minimum_size)
{
minimum_size->width = min_width;
minimum_size->height = min_height;
}
if (natural_size)
{
natural_size->width = nat_width;
natural_size->height = nat_height;
}
}
#define __GTK_EXTENDED_LAYOUT_C__
#include "gtkaliasdef.c"

89
gtk/gtkextendedlayout.h Normal file
View File

@ -0,0 +1,89 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2007-2010 Openismus GmbH
*
* Authors:
* Mathias Hasselmann <mathias@openismus.com>
* Tristan Van Berkom <tristan.van.berkom@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#ifndef __GTK_EXTENDED_LAYOUT_H__
#define __GTK_EXTENDED_LAYOUT_H__
#include <gtk/gtkwidget.h>
G_BEGIN_DECLS
#define GTK_TYPE_EXTENDED_LAYOUT (gtk_extended_layout_get_type ())
#define GTK_EXTENDED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_EXTENDED_LAYOUT, GtkExtendedLayout))
#define GTK_EXTENDED_LAYOUT_CLASS(klass) ((GtkExtendedLayoutIface*)g_type_interface_peek ((klass), GTK_TYPE_EXTENDED_LAYOUT))
#define GTK_IS_EXTENDED_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_EXTENDED_LAYOUT))
#define GTK_EXTENDED_LAYOUT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_EXTENDED_LAYOUT, GtkExtendedLayoutIface))
typedef struct _GtkExtendedLayout GtkExtendedLayout;
typedef struct _GtkExtendedLayoutIface GtkExtendedLayoutIface;
struct _GtkExtendedLayoutIface
{
GTypeInterface g_iface;
/* virtual table */
gboolean (* is_height_for_width) (GtkExtendedLayout *layout);
void (* get_desired_width) (GtkExtendedLayout *layout,
gint *minimum_width,
gint *natural_width);
void (* get_desired_height) (GtkExtendedLayout *layout,
gint *minimum_height,
gint *natural_height);
void (* get_width_for_height) (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width);
void (* get_height_for_width) (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height);
};
GType gtk_extended_layout_get_type (void) G_GNUC_CONST;
gboolean gtk_extended_layout_is_height_for_width (GtkExtendedLayout *layout);
void gtk_extended_layout_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_width,
gint *natural_width);
void gtk_extended_layout_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_height,
gint *natural_height);
void gtk_extended_layout_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width);
void gtk_extended_layout_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height);
void gtk_extended_layout_get_desired_size (GtkExtendedLayout *layout,
gboolean request_natural,
GtkRequisition *minimum_size,
GtkRequisition *natural_size);
G_END_DECLS
#endif /* __GTK_EXTENDED_LAYOUT_H__ */

View File

@ -323,7 +323,7 @@
* </variablelist>
* <note>
* You can create your own bindings for the
* GtkFileChooserDefault::location-popup signal with custom
* #GtkFileChooserDefault::location-popup signal with custom
* <parameter>path</parameter> strings, and have a crude form
* of easily-to-type bookmarks. For example, say you access
* the path <filename>/home/username/misc</filename> very
@ -504,7 +504,11 @@
* </listitem>
* </varlistentry>
* <varlistentry>
<<<<<<< HEAD
* <term><parameter>bookmark_indes</parameter>&nbsp;:</term>
=======
* <term><parameter>bookmark_index</parameter>&nbsp;:</term>
>>>>>>> native-layout-incubator
* <listitem>
* <simpara>
* index of the bookmark to switch to; the indices start at 0.

View File

@ -31,6 +31,7 @@
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkbuildable.h"
#include "gtkextendedlayout.h"
#include "gtkalias.h"
#define LABEL_PAD 1
@ -81,9 +82,19 @@ static void gtk_frame_buildable_add_child (GtkBuildable *buildable,
GObject *child,
const gchar *type);
static void gtk_frame_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_frame_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_frame_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
G_DEFINE_TYPE_WITH_CODE (GtkFrame, gtk_frame, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_frame_buildable_init))
gtk_frame_buildable_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_frame_extended_layout_init))
static void
gtk_frame_class_init (GtkFrameClass *class)
@ -150,7 +161,6 @@ gtk_frame_class_init (GtkFrameClass *class)
GTK_PARAM_READWRITE));
widget_class->expose_event = gtk_frame_expose;
widget_class->size_request = gtk_frame_size_request;
widget_class->size_allocate = gtk_frame_size_allocate;
container_class->remove = gtk_frame_remove;
@ -601,42 +611,6 @@ gtk_frame_expose (GtkWidget *widget,
return FALSE;
}
static void
gtk_frame_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkFrame *frame = GTK_FRAME (widget);
GtkBin *bin = GTK_BIN (widget);
GtkRequisition child_requisition;
if (frame->label_widget && gtk_widget_get_visible (frame->label_widget))
{
gtk_widget_size_request (frame->label_widget, &child_requisition);
requisition->width = child_requisition.width + 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD;
requisition->height =
MAX (0, child_requisition.height - widget->style->ythickness);
}
else
{
requisition->width = 0;
requisition->height = 0;
}
if (bin->child && gtk_widget_get_visible (bin->child))
{
gtk_widget_size_request (bin->child, &child_requisition);
requisition->width = MAX (requisition->width, child_requisition.width);
requisition->height += child_requisition.height;
}
requisition->width += (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->xthickness) * 2;
requisition->height += (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->ythickness) * 2;
}
static void
gtk_frame_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -652,11 +626,15 @@ gtk_frame_size_allocate (GtkWidget *widget,
/* If the child allocation changed, that means that the frame is drawn
* in a new place, so we must redraw the entire widget.
*/
if (gtk_widget_get_mapped (widget) &&
if (gtk_widget_get_mapped (widget)
#if 0
&&
(new_allocation.x != frame->child_allocation.x ||
new_allocation.y != frame->child_allocation.y ||
new_allocation.width != frame->child_allocation.width ||
new_allocation.height != frame->child_allocation.height))
new_allocation.height != frame->child_allocation.height)
#endif
)
gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
if (bin->child && gtk_widget_get_visible (bin->child))
@ -728,5 +706,103 @@ gtk_frame_real_compute_child_allocation (GtkFrame *frame,
child_allocation->y += allocation->y;
}
static void
gtk_frame_get_desired_size (GtkExtendedLayout *layout,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
{
GtkWidget *widget = GTK_WIDGET (layout);
GtkFrame *frame = GTK_FRAME (widget);
GtkBin *bin = GTK_BIN (widget);
gint child_min, child_nat;
gint minimum, natural;
if (frame->label_widget && gtk_widget_get_visible (frame->label_widget))
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (frame->label_widget),
&child_min, &child_nat);
minimum = child_min + 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD;
natural = child_nat + 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD;
}
else
{
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (frame->label_widget),
&child_min, &child_nat);
minimum = MAX (0, child_min - widget->style->ythickness);
natural = MAX (0, child_nat - widget->style->ythickness);
}
}
else
{
minimum = 0;
natural = 0;
}
if (bin->child && gtk_widget_get_visible (bin->child))
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (bin->child),
&child_min, &child_nat);
minimum = MAX (minimum, child_min);
natural = MAX (natural, child_nat);
}
else
{
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (bin->child),
&child_min, &child_nat);
minimum += child_min;
natural += child_nat;
}
}
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum += (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->xthickness) * 2;
natural += (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->xthickness) * 2;
}
else
{
minimum += (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->ythickness) * 2;
natural += (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->ythickness) * 2;
}
if (minimum_size)
*minimum_size = minimum;
if (natural_size)
*natural_size = natural;
}
static void
gtk_frame_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_frame_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
}
static void
gtk_frame_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_frame_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
}
static void
gtk_frame_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_frame_get_desired_width;
iface->get_desired_height = gtk_frame_get_desired_height;
}
#define __GTK_FRAME_C__
#include "gtkaliasdef.c"

View File

@ -48,6 +48,7 @@
#include "gtkimage.h"
#include "gtkshow.h"
#include "gtktooltip.h"
#include "gtkextendedlayout.h"
#include "gtkprivate.h"
#include "gtkalias.h"
@ -153,6 +154,11 @@ enum {
PROP_TRACK_VISITED_LINKS
};
/* When rotating ellipsizable text we want the natural size to request
* more to ensure the label wont ever ellipsize in an allocation of full natural size.
* */
#define ROTATION_ELLIPSIZE_PADDING 2
static guint signals[LAST_SIGNAL] = { 0 };
static const GdkColor default_link_color = { 0, 0, 0, 0xeeee };
@ -168,8 +174,6 @@ static void gtk_label_get_property (GObject *object,
GParamSpec *pspec);
static void gtk_label_destroy (GtkObject *object);
static void gtk_label_finalize (GObject *object);
static void gtk_label_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_label_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_label_state_changed (GtkWidget *widget,
@ -236,7 +240,7 @@ static void gtk_label_ensure_select_info (GtkLabel *label);
static void gtk_label_clear_select_info (GtkLabel *label);
static void gtk_label_update_cursor (GtkLabel *label);
static void gtk_label_clear_layout (GtkLabel *label);
static void gtk_label_ensure_layout (GtkLabel *label);
static void gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width);
static void gtk_label_invalidate_wrap_width (GtkLabel *label);
static void gtk_label_select_region_index (GtkLabel *label,
gint anchor_index,
@ -301,13 +305,32 @@ static void gtk_label_get_link_colors (GtkWidget *widget,
static void emit_activate_link (GtkLabel *label,
GtkLabelLink *link);
static void gtk_label_extended_layout_init (GtkExtendedLayoutIface *iface);
static gboolean gtk_label_is_height_for_width (GtkExtendedLayout *layout);
static void gtk_label_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_label_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_label_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width);
static void gtk_label_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height);
static GQuark quark_angle = 0;
static GtkBuildableIface *buildable_parent_iface = NULL;
G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_label, GTK_TYPE_MISC,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_label_buildable_interface_init));
gtk_label_buildable_interface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_label_extended_layout_init));
static void
add_move_binding (GtkBindingSet *binding_set,
@ -348,7 +371,6 @@ gtk_label_class_init (GtkLabelClass *class)
object_class->destroy = gtk_label_destroy;
widget_class->size_request = gtk_label_size_request;
widget_class->size_allocate = gtk_label_size_allocate;
widget_class->state_changed = gtk_label_state_changed;
widget_class->style_set = gtk_label_style_set;
@ -645,10 +667,11 @@ gtk_label_class_init (GtkLabelClass *class)
* GtkLabel:width-chars:
*
* The desired width of the label, in characters. If this property is set to
* -1, the width will be calculated automatically, otherwise the label will
* request either 3 characters or the property value, whichever is greater.
* If the "width-chars" property is set to a positive value, then the
* #GtkLabel:max-width-chars property is ignored.
* -1, the width will be calculated automatically.
*
* See the section on <link linkend="label-text-layout">text layout</link>
* for details of how #GtkLabel:width-chars and #GtkLabel:max-width-chars
* determine the width of ellipsized and wrapped labels.
*
* Since: 2.6
**/
@ -705,10 +728,11 @@ gtk_label_class_init (GtkLabelClass *class)
* GtkLabel:max-width-chars:
*
* The desired maximum width of the label, in characters. If this property
* is set to -1, the width will be calculated automatically, otherwise the
* label will request space for no more than the requested number of
* characters. If the #GtkLabel:width-chars property is set to a positive
* value, then the "max-width-chars" property is ignored.
* is set to -1, the width will be calculated automatically.
*
* See the section on <link linkend="label-text-layout">text layout</link>
* for details of how #GtkLabel:width-chars and #GtkLabel:max-width-chars
* determine the width of ellipsized and wrapped labels.
*
* Since: 2.6
**/
@ -1131,7 +1155,6 @@ attribute_from_text (GtkBuilder *builder,
value, &val, error))
attribute = pango_attr_gravity_hint_new (g_value_get_enum (&val));
break;
/* PangoAttrString */
case PANGO_ATTR_FAMILY:
attribute = pango_attr_family_new (value);
@ -2912,17 +2935,25 @@ gtk_label_clear_layout (GtkLabel *label)
}
}
static gint
get_label_char_width (GtkLabel *label)
static void
get_label_width (GtkLabel *label,
gint *minimum,
gint *natural)
{
GtkWidgetAuxInfo *aux_info;
GtkLabelPrivate *priv;
PangoLayout *layout;
PangoContext *context;
PangoFontMetrics *metrics;
gint char_width, digit_width, char_pixels, w;
PangoRectangle rect;
gint char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width;
priv = GTK_LABEL_GET_PRIVATE (label);
aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
context = pango_layout_get_context (label->layout);
layout = pango_layout_copy (label->layout);
context = pango_layout_get_context (layout);
metrics = pango_context_get_metrics (context, GTK_WIDGET (label)->style->font_desc,
pango_context_get_language (context));
@ -2931,23 +2962,87 @@ get_label_char_width (GtkLabel *label)
char_pixels = MAX (char_width, digit_width);
pango_font_metrics_unref (metrics);
if (priv->width_chars < 0)
{
PangoRectangle rect;
/* Fetch the length of the complete unwrapped text */
pango_layout_set_width (layout, -1);
pango_layout_get_extents (layout, NULL, &rect);
text_width = rect.width;
pango_layout_set_width (label->layout, -1);
/* Fetch the width that was guessed by gtk_label_ensure_layout() */
pango_layout_get_extents (label->layout, NULL, &rect);
guess_width = rect.width;
w = char_pixels * MAX (priv->max_width_chars, 3);
w = MIN (rect.width, w);
/* enforce minimum width for ellipsized labels at ~3 chars */
if (label->ellipsize)
ellipsize_chars = 3;
else
ellipsize_chars = 0;
/* "width-chars" Hard-coded minimum width:
* - minimum size should be MAX (width-chars, strlen ("..."));
* - natural size should be MAX (width-chars, strlen (label->text));
*
* "max-width-chars" User specified maximum size requisition
* - minimum size should be MAX (width-chars, 0)
* - natural size should be MIN (max-width-chars, strlen (label->text))
*
* For ellipsizing labels; if max-width-chars is specified: either it is used as
* a minimum size or the label text as a minimum size (natural size still overflows).
*
* For wrapping labels; A reasonable minimum size is useful to naturally layout
* interfaces automatically. In this case if no "width-chars" is specified, the minimum
* width will default to the wrap guess that gtk_label_ensure_layout() does.
*
* In *any* case the minimum width is completely overridden if an explicit width
* request was provided.
*/
if (label->ellipsize || label->wrap)
{
*minimum = char_pixels * MAX (priv->width_chars, ellipsize_chars);
/* Default to the minimum width regularly guessed by GTK+ if no minimum
* width was specified, only allow unwrapping of these labels.
*
* Note that when specifying a small width_chars for a long text;
* an accordingly large size will be required for the label height.
*/
if (label->wrap && priv->width_chars <= 0)
*minimum = guess_width;
if (priv->max_width_chars < 0)
{
*natural = MAX (*minimum, text_width);
}
else
{
/* enforce minimum width for ellipsized labels at ~3 chars */
w = char_pixels * MAX (priv->width_chars, 3);
gint max_char_width = char_pixels * priv->max_width_chars;
gint max_width = MIN (text_width, max_char_width);
/* With max-char-width specified, we let the minimum widths of
* ellipsized text crawl up to the max-char-width
* (note that we dont want to limit the minimum width for wrapping text).
*/
if (label->ellipsize)
*minimum = MIN (text_width, max_width);
*natural = MAX (*minimum, max_width);
}
}
else
{
*minimum = text_width;
*natural = *minimum;
}
return w;
/* if a width-request is set, use that as the requested label width */
if ((label->wrap || label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0) &&
aux_info && aux_info->width > 0)
{
*minimum = aux_info->width * PANGO_SCALE;
*natural = MAX (*natural, *minimum);
}
g_object_unref (layout);
}
static void
@ -2969,14 +3064,38 @@ get_label_wrap_width (GtkLabel *label)
if (priv->wrap_width < 0)
{
if (priv->width_chars > 0 || priv->max_width_chars > 0)
priv->wrap_width = get_label_char_width (label);
if (priv->width_chars > 0)
{
PangoLayout *layout;
PangoContext *context;
PangoFontMetrics *metrics;
PangoRectangle rect;
gint char_width, digit_width, char_pixels, text_width;
layout = pango_layout_copy (label->layout);
context = pango_layout_get_context (layout);
metrics = pango_context_get_metrics (context, GTK_WIDGET (label)->style->font_desc,
pango_context_get_language (context));
char_width = pango_font_metrics_get_approximate_char_width (metrics);
digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
char_pixels = MAX (char_width, digit_width);
pango_font_metrics_unref (metrics);
pango_layout_set_width (layout, -1);
pango_layout_get_extents (layout, NULL, &rect);
g_object_unref (layout);
text_width = rect.width;
priv->wrap_width = PANGO_PIXELS (MAX (text_width, char_pixels * priv->width_chars));
}
else
{
PangoLayout *layout;
layout = gtk_widget_create_pango_layout (GTK_WIDGET (label),
"This long string gives a good enough length for any line to have.");
"This string is just about long enough.");
pango_layout_get_size (layout, &priv->wrap_width, NULL);
g_object_unref (layout);
}
@ -2986,7 +3105,7 @@ get_label_wrap_width (GtkLabel *label)
}
static void
gtk_label_ensure_layout (GtkLabel *label)
gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width)
{
GtkWidget *widget;
PangoRectangle logical_rect;
@ -3001,14 +3120,14 @@ gtk_label_ensure_layout (GtkLabel *label)
PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
gdouble angle = gtk_label_get_angle (label);
if (angle != 0.0 && !label->wrap && !label->ellipsize && !label->select_info)
if (angle != 0.0 && !label->select_info)
{
PangoMatrix matrix = PANGO_MATRIX_INIT;
/* We rotate the standard singleton PangoContext for the widget,
* depending on the fact that it's meant pretty much exclusively
* for our use.
*/
PangoMatrix matrix = PANGO_MATRIX_INIT;
pango_matrix_rotate (&matrix, angle);
pango_context_set_matrix (gtk_widget_get_pango_context (widget), &matrix);
@ -3058,15 +3177,29 @@ gtk_label_ensure_layout (GtkLabel *label)
widget->allocation.width * PANGO_SCALE);
else if (label->wrap)
{
GtkWidgetAuxInfo *aux_info;
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
gint longest_paragraph;
gint width, height;
gint aux_width = 0;
if ((angle == 90 || angle == 270) && aux_info && aux_info->height > 0)
aux_width = aux_info->height;
else if (aux_info && aux_info->width > 0)
aux_width = aux_info->width;
if (aux_width > 0)
pango_layout_set_width (label->layout, aux_width * PANGO_SCALE);
else if (guess_wrap_width == FALSE &&
widget->allocation.width > 1 && widget->allocation.height > 1)
{
if (angle == 90 || angle == 270)
width = widget->allocation.height - label->misc.ypad * 2;
else
width = widget->allocation.width - label->misc.xpad * 2;
pango_layout_set_wrap (label->layout, label->wrap_mode);
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (aux_info && aux_info->width > 0)
pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
pango_layout_set_width (label->layout, MAX (width, 1) * PANGO_SCALE);
}
else
{
GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (label));
@ -3076,7 +3209,6 @@ gtk_label_ensure_layout (GtkLabel *label)
pango_layout_get_extents (label->layout, NULL, &logical_rect);
width = logical_rect.width;
/* Try to guess a reasonable maximum width */
longest_paragraph = width;
@ -3130,77 +3262,15 @@ gtk_label_ensure_layout (GtkLabel *label)
}
}
static void
gtk_label_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv;
gint width, height;
PangoRectangle logical_rect;
GtkWidgetAuxInfo *aux_info;
priv = GTK_LABEL_GET_PRIVATE (widget);
/*
* If word wrapping is on, then the height requisition can depend
* on:
*
* - Any width set on the widget via gtk_widget_set_size_request().
* - The padding of the widget (xpad, set by gtk_misc_set_padding)
*
* Instead of trying to detect changes to these quantities, if we
* are wrapping, we just rewrap for each size request. Since
* size requisitions are cached by the GTK+ core, this is not
* expensive.
*/
if (label->wrap)
gtk_label_clear_layout (label);
gtk_label_ensure_layout (label);
width = label->misc.xpad * 2;
height = label->misc.ypad * 2;
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (label->have_transform)
{
PangoRectangle rect;
PangoContext *context = pango_layout_get_context (label->layout);
const PangoMatrix *matrix = pango_context_get_matrix (context);
pango_layout_get_extents (label->layout, NULL, &rect);
pango_matrix_transform_rectangle (matrix, &rect);
pango_extents_to_pixels (&rect, NULL);
requisition->width = width + rect.width;
requisition->height = height + rect.height;
return;
}
else
pango_layout_get_extents (label->layout, NULL, &logical_rect);
if ((label->wrap || label->ellipsize ||
priv->width_chars > 0 || priv->max_width_chars > 0) &&
aux_info && aux_info->width > 0)
width += aux_info->width;
else if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
{
width += PANGO_PIXELS (get_label_char_width (label));
}
else
width += PANGO_PIXELS (logical_rect.width);
if (label->single_line_mode)
static gint
get_single_line_height (GtkWidget *widget,
PangoLayout *layout)
{
PangoContext *context;
PangoFontMetrics *metrics;
gint ascent, descent;
context = pango_layout_get_context (label->layout);
context = pango_layout_get_context (layout);
metrics = pango_context_get_metrics (context, widget->style->font_desc,
pango_context_get_language (context));
@ -3208,13 +3278,293 @@ gtk_label_size_request (GtkWidget *widget,
descent = pango_font_metrics_get_descent (metrics);
pango_font_metrics_unref (metrics);
height += PANGO_PIXELS (ascent + descent);
return ascent + descent;
}
static void
gtk_label_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->is_height_for_width = gtk_label_is_height_for_width;
iface->get_desired_width = gtk_label_get_desired_width;
iface->get_desired_height = gtk_label_get_desired_height;
iface->get_width_for_height = gtk_label_get_width_for_height;
iface->get_height_for_width = gtk_label_get_height_for_width;
}
static gboolean
gtk_label_is_height_for_width (GtkExtendedLayout *layout)
{
GtkLabel *label = GTK_LABEL (layout);
gdouble angle = gtk_label_get_angle (label);
if (angle == 90 || angle == 270)
return FALSE;
return TRUE;
}
static void
get_size_for_allocation (GtkLabel *label,
GtkOrientation orientation,
gint allocation,
gint *minimum_size,
gint *natural_size)
{
PangoLayout *layout;
GtkWidgetAuxInfo *aux_info =
_gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
gint aux_size;
gint text_height;
gtk_label_ensure_layout (label, FALSE);
layout = pango_layout_copy (label->layout);
if (aux_info)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
aux_size = aux_info->width;
else
aux_size = aux_info->height;
}
else
height += PANGO_PIXELS (logical_rect.height);
aux_size = 0;
requisition->width = width;
requisition->height = height;
if (aux_size > 0)
pango_layout_set_width (layout, aux_size * PANGO_SCALE);
else
pango_layout_set_width (layout, allocation * PANGO_SCALE);
pango_layout_get_pixel_size (layout, NULL, &text_height);
if (minimum_size)
*minimum_size = text_height;
if (natural_size)
*natural_size = text_height;
g_object_unref (layout);
}
static void
gtk_label_get_desired_size (GtkExtendedLayout *layout,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
{
GtkLabel *label = GTK_LABEL (layout);
PangoRectangle required_rect;
PangoRectangle natural_rect;
gdouble angle;
/* "width-chars" Hard-coded minimum width:
* - minimum size should be MAX (width-chars, strlen ("..."));
* - natural size should be MAX (width-chars, strlen (label->text));
*
* "max-width-chars" User specified maximum size requisition
* - minimum size should be MAX (width-chars, 0)
* - natural size should be MIN (max-width-chars, strlen (label->text))
*
*/
/* When calculating ->wrap sometimes we need to invent a size; Ideally we should be doing
* that stuff here instead of inside gtk_label_ensure_layout() */
if (label->wrap)
gtk_label_clear_layout (label);
gtk_label_ensure_layout (label, TRUE);
angle = gtk_label_get_angle (label);
/* Start off with the pixel extents of the rendered layout */
pango_layout_get_extents (label->layout, NULL, &required_rect);
required_rect.x = required_rect.y = 0;
if (label->single_line_mode || label->wrap)
required_rect.height = get_single_line_height (GTK_WIDGET (label), label->layout);
natural_rect = required_rect;
/* Calculate text width itself based on GtkLabel property rules */
get_label_width (label, &required_rect.width, &natural_rect.width);
/* Now that we have minimum and natural sizes in pango extents, apply a possible transform */
if (label->have_transform)
{
PangoLayout *layout = pango_layout_copy (label->layout);
PangoContext *context = pango_layout_get_context (label->layout);
const PangoMatrix *matrix = pango_context_get_matrix (context);
pango_layout_set_width (layout, -1);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
pango_layout_get_extents (layout, NULL, &natural_rect);
g_object_unref (layout);
pango_matrix_transform_rectangle (matrix, &required_rect);
pango_matrix_transform_rectangle (matrix, &natural_rect);
/* Bump the natural size in case of ellipsize to ensure pango has
* enough space in the angles (note, we could alternatively set the
* layout to not ellipsize when we know we have been allocated our
* full natural size, or it may be that pango needs a fix here).
*/
if (label->ellipsize && angle != 0 && angle != 90 && angle != 180 && angle != 270 && angle != 360)
{
/* For some reason we only need this at about 110 degrees, and only
* when gaining in height
*/
natural_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
natural_rect.width += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
}
}
required_rect.width = PANGO_PIXELS_CEIL (required_rect.width);
required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
natural_rect.width = PANGO_PIXELS_CEIL (natural_rect.width);
natural_rect.height = PANGO_PIXELS_CEIL (natural_rect.height);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
/* Note, we cant use get_size_for_allocation() when rotating
* ellipsized labels.
*/
if (!(label->ellipsize && label->have_transform) &&
(angle == 90 || angle == 270))
{
/* Doing a h4w request on a rotated label here, return the
* required width for the minimum height.
*/
get_size_for_allocation (label,
GTK_ORIENTATION_VERTICAL,
required_rect.height,
minimum_size, natural_size);
}
else
{
/* Normal desired width */
*minimum_size = required_rect.width;
*natural_size = natural_rect.width;
}
*minimum_size += label->misc.xpad * 2;
*natural_size += label->misc.xpad * 2;
}
else /* GTK_ORIENTATION_VERTICAL */
{
/* Note, we cant use get_size_for_allocation() when rotating
* ellipsized labels.
*/
if (!(label->ellipsize && label->have_transform) &&
(angle == 0 || angle == 180))
{
/* Doing a w4h request on a label here, return the required
* height for the minimum width.
*/
get_size_for_allocation (label,
GTK_ORIENTATION_HORIZONTAL,
required_rect.width,
minimum_size, natural_size);
}
else
{
/* A vertically rotated label does w4h, so return the base
* desired height (text length)
*/
*minimum_size = required_rect.height;
*natural_size = natural_rect.height;
}
*minimum_size += label->misc.ypad * 2;
*natural_size += label->misc.ypad * 2;
}
/* Restore real allocated size of layout; sometimes size-requests
* are randomly called without a following allocation; for this case
* we need to make sure we dont have a mucked up layout because we
* went and guessed the wrap-size.
*/
if (label->wrap)
gtk_label_clear_layout (label);
gtk_label_ensure_layout (label, FALSE);
}
static void
gtk_label_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_label_get_desired_size (layout,
GTK_ORIENTATION_HORIZONTAL,
minimum_size, natural_size);
}
static void
gtk_label_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_label_get_desired_size (layout,
GTK_ORIENTATION_VERTICAL,
minimum_size, natural_size);
}
static void
gtk_label_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width)
{
GtkLabel *label = GTK_LABEL (layout);
gdouble angle = gtk_label_get_angle (label);
if (label->wrap && (angle == 90 || angle == 270))
{
if (label->wrap)
gtk_label_clear_layout (label);
get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL,
MAX (1, height - (label->misc.ypad * 2)),
minimum_width, natural_width);
if (minimum_width)
*minimum_width += label->misc.xpad * 2;
if (natural_width)
*natural_width += label->misc.xpad * 2;
}
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, minimum_width, natural_width);
}
static void
gtk_label_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height)
{
GtkLabel *label = GTK_LABEL (layout);
gdouble angle = gtk_label_get_angle (label);
if (label->wrap && (angle == 0 || angle == 180 || angle == 360))
{
if (label->wrap)
gtk_label_clear_layout (label);
get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
MAX (1, width - label->misc.xpad * 2),
minimum_height, natural_height);
if (minimum_height)
*minimum_height += label->misc.ypad * 2;
if (natural_height)
*natural_height += label->misc.ypad * 2;
}
else
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, minimum_height, natural_height);
}
static void
@ -3227,20 +3577,85 @@ gtk_label_size_allocate (GtkWidget *widget,
GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate (widget, allocation);
/* The layout may have been recently cleared in get_size_for_orientation(),
* but the width at that point may not be the same as the allocated width
*/
if (label->wrap)
gtk_label_clear_layout (label);
gtk_label_ensure_layout (label, FALSE);
if (label->ellipsize)
{
if (label->layout)
{
gint width;
PangoRectangle logical;
PangoRectangle bounds;
width = (allocation->width - label->misc.xpad * 2) * PANGO_SCALE;
bounds.x = bounds.y = 0;
bounds.width = allocation->width - label->misc.xpad * 2;
bounds.height = allocation->height - label->misc.ypad * 2;
pango_layout_set_width (label->layout, -1);
pango_layout_get_extents (label->layout, NULL, &logical);
pango_layout_get_pixel_extents (label->layout, NULL, &logical);
if (logical.width > width)
pango_layout_set_width (label->layout, width);
if (label->have_transform)
{
PangoContext *context = gtk_widget_get_pango_context (widget);
const PangoMatrix *matrix = pango_context_get_matrix (context);
const gdouble dx = matrix->xx; /* cos (M_PI * angle / 180) */
const gdouble dy = matrix->xy; /* sin (M_PI * angle / 180) */
if (fabs (dy) < 0.01)
{
if (logical.width > bounds.width)
pango_layout_set_width (label->layout, bounds.width * PANGO_SCALE);
}
else if (fabs (dx) < 0.01)
{
if (logical.width > bounds.height)
pango_layout_set_width (label->layout, bounds.height * PANGO_SCALE);
}
else
{
gdouble x0, y0, x1, y1, length;
gboolean vertical;
gint cy;
x0 = bounds.width / 2;
y0 = dx ? x0 * dy / dx : dy * INFINITY;
vertical = fabs (y0) > bounds.height / 2;
if (vertical)
{
y0 = bounds.height/2;
x0 = dy ? y0 * dx / dy : dx * INFINITY;
}
length = 2 * sqrt (x0 * x0 + y0 * y0);
pango_layout_set_width (label->layout, rint (length * PANGO_SCALE));
pango_layout_get_pixel_size (label->layout, NULL, &cy);
x1 = +dy * cy/2;
y1 = -dx * cy/2;
if (vertical)
{
y0 = bounds.height/2 + y1 - y0;
x0 = -y0 * dx/dy;
}
else
{
x0 = bounds.width/2 + x1 - x0;
y0 = -x0 * dy/dx;
}
length = length - sqrt (x0 * x0 + y0 * y0) * 2;
pango_layout_set_width (label->layout, rint (length * PANGO_SCALE));
}
}
else if (logical.width > bounds.width)
pango_layout_set_width (label->layout, bounds.width * PANGO_SCALE);
}
}
@ -3339,32 +3754,48 @@ get_layout_location (GtkLabel *label,
GtkLabelPrivate *priv;
gfloat xalign;
gint req_width, x, y;
gint req_height;
PangoRectangle logical;
gdouble angle;
misc = GTK_MISC (label);
widget = GTK_WIDGET (label);
priv = GTK_LABEL_GET_PRIVATE (label);
angle = gtk_label_get_angle (label);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
xalign = misc->xalign;
else
xalign = 1.0 - misc->xalign;
pango_layout_get_pixel_extents (label->layout, NULL, &logical);
pango_layout_get_extents (label->layout, NULL, &logical);
if (label->ellipsize || priv->width_chars > 0)
/* Do the wrap width delimiting before the transform
*/
if (label->wrap || label->ellipsize || priv->width_chars > 0)
{
int width;
width = pango_layout_get_width (label->layout);
req_width = logical.width;
if (width != -1)
req_width = MIN(PANGO_PIXELS (width), req_width);
req_width += 2 * misc->xpad;
logical.width = MIN (width, logical.width);
}
else
req_width = widget->requisition.width;
if (label->have_transform)
{
PangoContext *context = gtk_widget_get_pango_context (widget);
const PangoMatrix *matrix = pango_context_get_matrix (context);
pango_matrix_transform_rectangle (matrix, &logical);
}
pango_extents_to_pixels (&logical, NULL);
req_width = logical.width;
req_height = logical.height;
req_width += 2 * misc->xpad;
req_height += 2 * misc->ypad;
x = floor (widget->allocation.x + (gint)misc->xpad +
xalign * (widget->allocation.width - req_width));
@ -3373,7 +3804,9 @@ get_layout_location (GtkLabel *label,
x = MAX (x, widget->allocation.x + misc->xpad);
else
x = MIN (x, widget->allocation.x + widget->allocation.width - misc->xpad);
x -= logical.x;
/* bgo#315462 - For single-line labels, *do* align the requisition with
* respect to the allocation, even if we are under-allocated. For multi-line
@ -3390,10 +3823,10 @@ get_layout_location (GtkLabel *label,
*/
if (pango_layout_get_line_count (label->layout) == 1)
y = floor (widget->allocation.y + (gint)misc->ypad
+ (widget->allocation.height - widget->requisition.height) * misc->yalign);
+ (widget->allocation.height - req_height) * misc->yalign);
else
y = floor (widget->allocation.y + (gint)misc->ypad
+ MAX (((widget->allocation.height - widget->requisition.height) * misc->yalign),
+ MAX (((widget->allocation.height - req_height) * misc->yalign),
0));
if (xp)
@ -3430,7 +3863,7 @@ get_cursor_direction (GtkLabel *label)
g_assert (label->select_info);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
for (l = pango_layout_get_lines_readonly (label->layout); l; l = l->next)
{
@ -3475,7 +3908,7 @@ gtk_label_draw_cursor (GtkLabel *label, gint xoffset, gint yoffset)
keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
cursor_direction = get_cursor_direction (label);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
&strong_pos, &weak_pos);
@ -3559,7 +3992,7 @@ gtk_label_expose (GtkWidget *widget,
GtkLabelSelectionInfo *info = label->select_info;
gint x, y;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) &&
label->text && (*label->text != '\0'))
@ -3972,7 +4405,7 @@ get_layout_index (GtkLabel *label,
*index = 0;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
window_to_layout_coords (label, &x, &y);
@ -5016,7 +5449,7 @@ gtk_label_get_layout (GtkLabel *label)
{
g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
return label->layout;
}
@ -5043,7 +5476,7 @@ gtk_label_get_layout_offsets (GtkLabel *label,
{
g_return_if_fail (GTK_IS_LABEL (label));
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
get_layout_location (label, x, y);
}
@ -5188,7 +5621,7 @@ get_better_cursor (GtkLabel *label,
"gtk-split-cursor", &split_cursor,
NULL);
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_cursor_pos (label->layout, index,
&strong_pos, &weak_pos);
@ -5228,7 +5661,7 @@ gtk_label_move_logically (GtkLabel *label,
gint n_attrs;
gint length;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
length = g_utf8_strlen (label->text, -1);
@ -5272,7 +5705,7 @@ gtk_label_move_visually (GtkLabel *label,
gboolean split_cursor;
gboolean strong;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
"gtk-split-cursor", &split_cursor,
@ -5325,7 +5758,7 @@ gtk_label_move_forward_word (GtkLabel *label,
PangoLogAttr *log_attrs;
gint n_attrs;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
@ -5353,7 +5786,7 @@ gtk_label_move_backward_word (GtkLabel *label,
PangoLogAttr *log_attrs;
gint n_attrs;
gtk_label_ensure_layout (label);
gtk_label_ensure_layout (label, FALSE);
pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);

View File

@ -235,7 +235,8 @@ static const GDebugKey gtk_debug_keys[] = {
{"geometry", GTK_DEBUG_GEOMETRY},
{"icontheme", GTK_DEBUG_ICONTHEME},
{"printing", GTK_DEBUG_PRINTING},
{"builder", GTK_DEBUG_BUILDER}
{"builder", GTK_DEBUG_BUILDER},
{"extended-layout", GTK_DEBUG_EXTENDED_LAYOUT},
};
#endif /* G_ENABLE_DEBUG */

View File

@ -461,6 +461,7 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
gint border_width;
gboolean need_sliders = FALSE;
gint up_slider_offset = 0;
GtkRequisition child_requisition;
widget->allocation = *allocation;
@ -487,7 +488,9 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
{
child = BUTTON_DATA (list->data)->button;
width += child->requisition.width + path_bar->spacing;
gtk_widget_get_child_requisition (child, &child_requisition);
width += child_requisition.width + path_bar->spacing;
if (list == path_bar->fake_root)
break;
}
@ -515,19 +518,23 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
* button, then count backwards.
*/
/* Count down the path chain towards the end. */
width = BUTTON_DATA (first_button->data)->button->requisition.width;
gtk_widget_get_child_requisition (BUTTON_DATA (first_button->data)->button, &child_requisition);
width = child_requisition.width;
list = first_button->prev;
while (list && !reached_end)
{
child = BUTTON_DATA (list->data)->button;
if (width + child->requisition.width +
gtk_widget_get_child_requisition (child, &child_requisition);
if (width + child_requisition.width +
path_bar->spacing + slider_space > allocation_width)
reached_end = TRUE;
else if (list == path_bar->fake_root)
break;
else
width += child->requisition.width + path_bar->spacing;
width += child_requisition.width + path_bar->spacing;
list = list->prev;
}
@ -538,13 +545,15 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
{
child = BUTTON_DATA (first_button->next->data)->button;
if (width + child->requisition.width + path_bar->spacing + slider_space > allocation_width)
gtk_widget_get_child_requisition (child, &child_requisition);
if (width + child_requisition.width + path_bar->spacing + slider_space > allocation_width)
{
reached_end = TRUE;
}
else
{
width += child->requisition.width + path_bar->spacing;
width += child_requisition.width + path_bar->spacing;
if (first_button == path_bar->fake_root)
break;
first_button = first_button->next;
@ -582,7 +591,9 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
button_data = BUTTON_DATA (list->data);
child = button_data->button;
child_allocation.width = MIN (child->requisition.width,
gtk_widget_get_child_requisition (child, &child_requisition);
child_allocation.width = MIN (child_requisition.width,
allocation_width - (path_bar->spacing + path_bar->slider_width) * 2);
if (direction == GTK_TEXT_DIR_RTL)
@ -601,7 +612,7 @@ gtk_path_bar_size_allocate (GtkWidget *widget,
break;
}
if (child_allocation.width < child->requisition.width)
if (child_allocation.width < child_requisition.width)
{
if (!gtk_widget_get_has_tooltip (child))
gtk_widget_set_tooltip_text (child, button_data->dir_name);

View File

@ -47,7 +47,10 @@ typedef enum
PRIVATE_GTK_CHILD_VISIBLE = 1 << 10, /* If widget should be mapped when parent is mapped */
PRIVATE_GTK_REDRAW_ON_ALLOC = 1 << 11, /* If we should queue a draw on the entire widget when it is reallocated */
PRIVATE_GTK_ALLOC_NEEDED = 1 << 12, /* If we we should allocate even if the allocation is the same */
PRIVATE_GTK_REQUEST_NEEDED = 1 << 13 /* Whether we need to call gtk_widget_size_request */
PRIVATE_GTK_REQUEST_NEEDED = 1 << 13, /* Whether we need to call gtk_widget_size_request */
PRIVATE_GTK_WIDTH_REQUEST_NEEDED = 1 << 14, /* Whether we need to call gtk_extended_layout_get_desired_width */
PRIVATE_GTK_HEIGHT_REQUEST_NEEDED = 1 << 15 /* Whether we need to call gtk_extended_layout_get_desired_height */
} GtkPrivateFlags;
/* Macros for extracting a widgets private_flags from GtkWidget.
@ -66,6 +69,8 @@ typedef enum
#define GTK_WIDGET_REDRAW_ON_ALLOC(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_REDRAW_ON_ALLOC) != 0)
#define GTK_WIDGET_ALLOC_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_ALLOC_NEEDED) != 0)
#define GTK_WIDGET_REQUEST_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_REQUEST_NEEDED) != 0)
#define GTK_WIDGET_WIDTH_REQUEST_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_WIDTH_REQUEST_NEEDED) != 0)
#define GTK_WIDGET_HEIGHT_REQUEST_NEEDED(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_HEIGHT_REQUEST_NEEDED) != 0)
/* Macros for setting and clearing private widget flags.
* we use a preprocessor string concatenation here for a clear

View File

@ -28,6 +28,7 @@
#include <math.h>
#include <gdk/gdkkeysyms.h>
#include "gtkbindings.h"
#include "gtkextendedlayout.h"
#include "gtkmarshalers.h"
#include "gtkscrolledwindow.h"
#include "gtkwindow.h"
@ -113,8 +114,6 @@ static void gtk_scrolled_window_screen_changed (GtkWidget *widge
GdkScreen *previous_screen);
static gboolean gtk_scrolled_window_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_scrolled_window_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_scrolled_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_scrolled_window_scroll_event (GtkWidget *widget,
@ -142,9 +141,28 @@ static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjus
static void gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
static void gtk_scrolled_window_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_scrolled_window_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_scrolled_window_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_scrolled_window_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height);
static void gtk_scrolled_window_get_width_for_height (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height);
static guint signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
G_DEFINE_TYPE_WITH_CODE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_scrolled_window_extended_layout_init))
static void
add_scroll_binding (GtkBindingSet *binding_set,
@ -198,7 +216,6 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
widget_class->screen_changed = gtk_scrolled_window_screen_changed;
widget_class->expose_event = gtk_scrolled_window_expose;
widget_class->size_request = gtk_scrolled_window_size_request;
widget_class->size_allocate = gtk_scrolled_window_size_allocate;
widget_class->scroll_event = gtk_scrolled_window_scroll_event;
widget_class->focus = gtk_scrolled_window_focus;
@ -380,9 +397,15 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
* gtk_scrolled_window_new:
* @hadjustment: (allow-none): horizontal adjustment
* @vadjustment: (allow-none): vertical adjustment
<<<<<<< HEAD
*
* Creates a new scrolled window.
*
=======
*
* Creates a new scrolled window.
*
>>>>>>> native-layout-incubator
* The two arguments are the scrolled window's adjustments; these will be
* shared with the scrollbars and the child widget to keep the bars in sync
* with the child. Usually you want to pass %NULL for the adjustments, which
@ -1229,98 +1252,6 @@ gtk_scrolled_window_move_focus_out (GtkScrolledWindow *scrolled_window,
g_object_unref (scrolled_window);
}
static void
gtk_scrolled_window_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkScrolledWindow *scrolled_window;
GtkBin *bin;
gint extra_width;
gint extra_height;
gint scrollbar_spacing;
GtkRequisition hscrollbar_requisition;
GtkRequisition vscrollbar_requisition;
GtkRequisition child_requisition;
g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
g_return_if_fail (requisition != NULL);
scrolled_window = GTK_SCROLLED_WINDOW (widget);
bin = GTK_BIN (scrolled_window);
scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
extra_width = 0;
extra_height = 0;
requisition->width = 0;
requisition->height = 0;
gtk_widget_size_request (scrolled_window->hscrollbar,
&hscrollbar_requisition);
gtk_widget_size_request (scrolled_window->vscrollbar,
&vscrollbar_requisition);
if (bin->child && gtk_widget_get_visible (bin->child))
{
gtk_widget_size_request (bin->child, &child_requisition);
if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
requisition->width += child_requisition.width;
else
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
if (aux_info && aux_info->width > 0)
{
requisition->width += aux_info->width;
extra_width = -1;
}
else
requisition->width += vscrollbar_requisition.width;
}
if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
requisition->height += child_requisition.height;
else
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
if (aux_info && aux_info->height > 0)
{
requisition->height += aux_info->height;
extra_height = -1;
}
else
requisition->height += hscrollbar_requisition.height;
}
}
if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
{
requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
extra_height = scrollbar_spacing + hscrollbar_requisition.height;
}
if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
{
requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
extra_width = scrollbar_spacing + vscrollbar_requisition.width;
}
requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
requisition->width += 2 * widget->style->xthickness;
requisition->height += 2 * widget->style->ythickness;
}
}
static void
gtk_scrolled_window_relative_allocation (GtkWidget *widget,
GtkAllocation *allocation)
@ -1795,5 +1726,193 @@ _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
}
}
static void
gtk_scrolled_window_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_scrolled_window_get_desired_width;
iface->get_desired_height = gtk_scrolled_window_get_desired_height;
iface->get_height_for_width = gtk_scrolled_window_get_height_for_width;
iface->get_width_for_height = gtk_scrolled_window_get_width_for_height;
}
static void
gtk_scrolled_window_get_desired_size (GtkExtendedLayout *layout,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
{
GtkScrolledWindow *scrolled_window;
GtkBin *bin;
gint extra_width;
gint extra_height;
gint scrollbar_spacing;
GtkRequisition hscrollbar_requisition;
GtkRequisition vscrollbar_requisition;
GtkRequisition minimum_req, natural_req;
gint min_child_size, nat_child_size;
scrolled_window = GTK_SCROLLED_WINDOW (layout);
bin = GTK_BIN (scrolled_window);
scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
extra_width = 0;
extra_height = 0;
minimum_req.width = 0;
minimum_req.height = 0;
natural_req.width = 0;
natural_req.height = 0;
gtk_widget_size_request (scrolled_window->hscrollbar,
&hscrollbar_requisition);
gtk_widget_size_request (scrolled_window->vscrollbar,
&vscrollbar_requisition);
if (bin->child && gtk_widget_get_visible (bin->child))
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (bin->child),
&min_child_size,
&nat_child_size);
if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
{
minimum_req.width += min_child_size;
natural_req.width += nat_child_size;
}
else
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
if (aux_info && aux_info->width > 0)
{
minimum_req.width += aux_info->width;
natural_req.width += aux_info->width;
extra_width = -1;
}
else
{
minimum_req.width += vscrollbar_requisition.width;
natural_req.width += vscrollbar_requisition.width;
}
}
}
else /* GTK_ORIENTATION_VERTICAL */
{
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (bin->child),
&min_child_size,
&nat_child_size);
if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
{
minimum_req.height += min_child_size;
natural_req.height += nat_child_size;
}
else
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
if (aux_info && aux_info->height > 0)
{
minimum_req.height += aux_info->height;
natural_req.height += aux_info->height;
extra_height = -1;
}
else
{
minimum_req.height += hscrollbar_requisition.height;
natural_req.height += hscrollbar_requisition.height;
}
}
}
}
if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
{
minimum_req.width = MAX (minimum_req.width, hscrollbar_requisition.width);
natural_req.width = MAX (natural_req.width, hscrollbar_requisition.width);
if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
extra_height = scrollbar_spacing + hscrollbar_requisition.height;
}
if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
{
minimum_req.height = MAX (minimum_req.height, vscrollbar_requisition.height);
natural_req.height = MAX (natural_req.height, vscrollbar_requisition.height);
if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
extra_width = scrollbar_spacing + vscrollbar_requisition.width;
}
minimum_req.width += GTK_CONTAINER (layout)->border_width * 2 + MAX (0, extra_width);
minimum_req.height += GTK_CONTAINER (layout)->border_width * 2 + MAX (0, extra_height);
natural_req.width += GTK_CONTAINER (layout)->border_width * 2 + MAX (0, extra_width);
natural_req.height += GTK_CONTAINER (layout)->border_width * 2 + MAX (0, extra_height);
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
minimum_req.width += 2 * GTK_WIDGET (layout)->style->xthickness;
minimum_req.height += 2 * GTK_WIDGET (layout)->style->ythickness;
natural_req.width += 2 * GTK_WIDGET (layout)->style->xthickness;
natural_req.height += 2 * GTK_WIDGET (layout)->style->ythickness;
}
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
if (minimum_size)
*minimum_size = minimum_req.width;
if (natural_size)
*natural_size = natural_req.width;
}
else
{
if (minimum_size)
*minimum_size = minimum_req.height;
if (natural_size)
*natural_size = natural_req.height;
}
}
static void
gtk_scrolled_window_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_scrolled_window_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
}
static void
gtk_scrolled_window_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_scrolled_window_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
}
static void
gtk_scrolled_window_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height)
{
g_return_if_fail (GTK_IS_WIDGET (layout));
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, minimum_height, natural_height);
}
static void
gtk_scrolled_window_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width)
{
g_return_if_fail (GTK_IS_WIDGET (layout));
GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, minimum_width, natural_width);
}
#define __GTK_SCROLLED_WINDOW_C__
#include "gtkaliasdef.c"

View File

@ -25,6 +25,7 @@
#include "gtkprivate.h"
#include "gtksizegroup.h"
#include "gtkbuildable.h"
#include "gtkextendedlayout.h"
#include "gtkalias.h"
enum {
@ -71,6 +72,9 @@ static const gchar size_groups_tag[] = "gtk-size-groups";
static GQuark visited_quark;
static const gchar visited_tag[] = "gtk-size-group-visited";
static GQuark bumping_quark;
static const gchar bumping_tag[] = "gtk-size-group-bumping";
static GSList *
get_size_groups (GtkWidget *widget)
{
@ -102,6 +106,18 @@ is_visited (gpointer object)
return g_object_get_qdata (object, visited_quark) != NULL;
}
static void
mark_bumping (gpointer object, gboolean bumping)
{
g_object_set_qdata (object, bumping_quark, bumping ? "bumping" : NULL);
}
static gboolean
is_bumping (gpointer object)
{
return g_object_get_qdata (object, bumping_quark) != NULL;
}
static void
add_group_to_closure (GtkSizeGroup *group,
GtkSizeGroupMode mode,
@ -154,6 +170,8 @@ real_queue_resize (GtkWidget *widget)
{
GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_WIDTH_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_HEIGHT_REQUEST_NEEDED);
if (widget->parent)
_gtk_container_queue_resize (GTK_CONTAINER (widget->parent));
@ -284,6 +302,7 @@ initialize_size_group_quarks (void)
{
size_groups_quark = g_quark_from_static_string (size_groups_tag);
visited_quark = g_quark_from_static_string (visited_tag);
bumping_quark = g_quark_from_static_string (bumping_tag);
}
}
@ -607,42 +626,35 @@ get_base_dimension (GtkWidget *widget,
if (aux_info && aux_info->width > 0)
return aux_info->width;
else
return widget->requisition.width;
{
/* XXX Possibly we should be using natural values and not minimums here. */
gint width;
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (widget), &width, NULL);
return width;
}
}
else
{
if (aux_info && aux_info->height > 0)
return aux_info->height;
else
return widget->requisition.height;
}
}
static void
do_size_request (GtkWidget *widget)
{
if (GTK_WIDGET_REQUEST_NEEDED (widget))
{
gtk_widget_ensure_style (widget);
GTK_PRIVATE_UNSET_FLAG (widget, GTK_REQUEST_NEEDED);
g_signal_emit_by_name (widget,
"size-request",
&widget->requisition);
/* XXX Possibly we should be using natural values and not minimums here. */
gint height;
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (widget), &height, NULL);
return height;
}
}
static gint
compute_base_dimension (GtkWidget *widget,
GtkSizeGroupMode mode)
{
do_size_request (widget);
return get_base_dimension (widget, mode);
}
static gint
compute_dimension (GtkWidget *widget,
GtkSizeGroupMode mode)
GtkSizeGroupMode mode,
gint widget_requisition)
{
GSList *widgets = NULL;
GSList *groups = NULL;
@ -658,7 +670,7 @@ compute_dimension (GtkWidget *widget,
if (!groups)
{
result = compute_base_dimension (widget, mode);
result = widget_requisition;
}
else
{
@ -674,8 +686,12 @@ compute_dimension (GtkWidget *widget,
while (tmp_list)
{
GtkWidget *tmp_widget = tmp_list->data;
gint dimension;
gint dimension = compute_base_dimension (tmp_widget, mode);
if (tmp_widget == widget)
dimension = widget_requisition;
else
dimension = get_base_dimension (tmp_widget, mode);
if (gtk_widget_get_mapped (tmp_widget) || !group->ignore_hidden)
{
@ -715,122 +731,58 @@ compute_dimension (GtkWidget *widget,
return result;
}
static gint
get_dimension (GtkWidget *widget,
GtkSizeGroupMode mode)
/**
* _gtk_size_group_bump_requisition:
* @widget: a #GtkWidget
* @mode: either %GTK_SIZE_GROUP_HORIZONTAL or %GTK_SIZE_GROUP_VERTICAL, depending
* on the dimension in which to bump the size.
*
* Refreshes the sizegroup while returning the groups requested
* value in the dimension @mode.
*
* This function is used to update sizegroup minimum size information
* in multiple passes from the new #GtkExtendedLayout manager.
*/
gint
_gtk_size_group_bump_requisition (GtkWidget *widget,
GtkSizeGroupMode mode,
gint widget_requisition)
{
GSList *widgets = NULL;
GSList *groups = NULL;
gint result = 0;
gint result = widget_requisition;
add_widget_to_closure (widget, mode, &groups, &widgets);
g_slist_foreach (widgets, (GFunc)mark_unvisited, NULL);
g_slist_foreach (groups, (GFunc)mark_unvisited, NULL);
if (!groups)
if (!is_bumping (widget))
{
result = get_base_dimension (widget, mode);
GtkWidgetAuxInfo *aux_info =
_gtk_widget_get_aux_info (widget, FALSE);
/* Avoid recursion here */
mark_bumping (widget, TRUE);
if (get_size_groups (widget))
{
if (aux_info)
{
if (mode == GTK_SIZE_GROUP_HORIZONTAL)
result = compute_dimension (widget, mode, MAX (aux_info->width, widget_requisition));
else
result = compute_dimension (widget, mode, MAX (aux_info->height, widget_requisition));
}
else
{
GtkSizeGroup *group = groups->data;
if (mode == GTK_SIZE_GROUP_HORIZONTAL && group->have_width)
result = group->requisition.width;
else if (mode == GTK_SIZE_GROUP_VERTICAL && group->have_height)
result = group->requisition.height;
result = compute_dimension (widget, mode, widget_requisition);
}
else if (aux_info)
{
if (mode == GTK_SIZE_GROUP_HORIZONTAL)
result = MAX (aux_info->width, widget_requisition);
else
result = MAX (aux_info->height, widget_requisition);
}
mark_bumping (widget, FALSE);
}
g_slist_free (widgets);
g_slist_free (groups);
return result;
}
static void
get_fast_child_requisition (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
*requisition = widget->requisition;
if (aux_info)
{
if (aux_info->width > 0)
requisition->width = aux_info->width;
if (aux_info && aux_info->height > 0)
requisition->height = aux_info->height;
}
}
/**
* _gtk_size_group_get_child_requisition:
* @widget: a #GtkWidget
* @requisition: location to store computed requisition.
*
* Retrieve the "child requisition" of the widget, taking account grouping
* of the widget's requisition with other widgets.
**/
void
_gtk_size_group_get_child_requisition (GtkWidget *widget,
GtkRequisition *requisition)
{
initialize_size_group_quarks ();
if (requisition)
{
if (get_size_groups (widget))
{
requisition->width = get_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL);
requisition->height = get_dimension (widget, GTK_SIZE_GROUP_VERTICAL);
/* Only do the full computation if we actually have size groups */
}
else
get_fast_child_requisition (widget, requisition);
}
}
/**
* _gtk_size_group_compute_requisition:
* @widget: a #GtkWidget
* @requisition: location to store computed requisition.
*
* Compute the requisition of a widget taking into account grouping of
* the widget's requisition with other widgets.
**/
void
_gtk_size_group_compute_requisition (GtkWidget *widget,
GtkRequisition *requisition)
{
gint width;
gint height;
initialize_size_group_quarks ();
if (get_size_groups (widget))
{
/* Only do the full computation if we actually have size groups */
width = compute_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL);
height = compute_dimension (widget, GTK_SIZE_GROUP_VERTICAL);
if (requisition)
{
requisition->width = width;
requisition->height = height;
}
}
else
{
do_size_request (widget);
if (requisition)
get_fast_child_requisition (widget, requisition);
}
}
/**
* _gtk_size_group_queue_resize:

View File

@ -100,12 +100,13 @@ void gtk_size_group_remove_widget (GtkSizeGroup *size_group,
GSList * gtk_size_group_get_widgets (GtkSizeGroup *size_group);
void _gtk_size_group_get_child_requisition (GtkWidget *widget,
GtkRequisition *requisition);
void _gtk_size_group_compute_requisition (GtkWidget *widget,
GtkRequisition *requisition);
gint _gtk_size_group_bump_requisition (GtkWidget *widget,
GtkSizeGroupMode mode,
gint widget_requisition);
void _gtk_size_group_queue_resize (GtkWidget *widget);
G_END_DECLS
#endif /* __GTK_SIZE_GROUP_H__ */

View File

@ -26,6 +26,7 @@
#include "config.h"
#include "gtkviewport.h"
#include "gtkextendedlayout.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
@ -79,8 +80,6 @@ static gint gtk_viewport_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_viewport_add (GtkContainer *container,
GtkWidget *widget);
static void gtk_viewport_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_viewport_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
@ -88,7 +87,18 @@ static void gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
static void gtk_viewport_style_set (GtkWidget *widget,
GtkStyle *previous_style);
G_DEFINE_TYPE (GtkViewport, gtk_viewport, GTK_TYPE_BIN)
static void gtk_viewport_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_viewport_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_viewport_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
G_DEFINE_TYPE_WITH_CODE (GtkViewport, gtk_viewport, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_viewport_extended_layout_init))
static void
gtk_viewport_class_init (GtkViewportClass *class)
@ -111,7 +121,6 @@ gtk_viewport_class_init (GtkViewportClass *class)
widget_class->realize = gtk_viewport_realize;
widget_class->unrealize = gtk_viewport_unrealize;
widget_class->expose_event = gtk_viewport_expose;
widget_class->size_request = gtk_viewport_size_request;
widget_class->size_allocate = gtk_viewport_size_allocate;
widget_class->style_set = gtk_viewport_style_set;
@ -436,10 +445,13 @@ viewport_set_vadjustment_values (GtkViewport *viewport,
if (bin->child && gtk_widget_get_visible (bin->child))
{
GtkRequisition child_requisition;
gint natural_height;
gtk_widget_get_child_requisition (bin->child, &child_requisition);
vadjustment->upper = MAX (child_requisition.height, view_allocation.height);
gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (bin->child),
view_allocation.width,
NULL,
&natural_height);
vadjustment->upper = MAX (natural_height, view_allocation.height);
}
else
vadjustment->upper = view_allocation.height;
@ -740,31 +752,6 @@ gtk_viewport_add (GtkContainer *container,
GTK_CONTAINER_CLASS (gtk_viewport_parent_class)->add (container, child);
}
static void
gtk_viewport_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkBin *bin = GTK_BIN (widget);
GtkRequisition child_requisition;
requisition->width = GTK_CONTAINER (widget)->border_width;
requisition->height = GTK_CONTAINER (widget)->border_width;
if (GTK_VIEWPORT (widget)->shadow_type != GTK_SHADOW_NONE)
{
requisition->width += 2 * widget->style->xthickness;
requisition->height += 2 * widget->style->ythickness;
}
if (bin->child && gtk_widget_get_visible (bin->child))
{
gtk_widget_size_request (bin->child, &child_requisition);
requisition->width += child_requisition.width;
requisition->height += child_requisition.height;
}
}
static void
gtk_viewport_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -868,5 +855,74 @@ gtk_viewport_style_set (GtkWidget *widget,
}
}
static void
gtk_viewport_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_viewport_get_desired_width;
iface->get_desired_height = gtk_viewport_get_desired_height;
}
static void
gtk_viewport_get_desired_size (GtkExtendedLayout *layout,
GtkOrientation orientation,
gint *minimum_size,
gint *natural_size)
{
GtkWidget *child;
gint child_min, child_nat;
gint minimum, natural;
child = gtk_bin_get_child (GTK_BIN (layout));
/* XXX This should probably be (border_width * 2); but GTK+ has
* been doing this with a single border for a while now...
*/
minimum = GTK_CONTAINER (layout)->border_width;
if (GTK_VIEWPORT (layout)->shadow_type != GTK_SHADOW_NONE)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
minimum += 2 * GTK_WIDGET (layout)->style->xthickness;
else
minimum += 2 * GTK_WIDGET (layout)->style->ythickness;
}
natural = minimum;
if (child && gtk_widget_get_visible (child))
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (child), &child_min, &child_nat);
else
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (child), &child_min, &child_nat);
minimum += child_min;
natural += child_nat;
}
if (minimum_size)
*minimum_size = minimum;
if (natural_size)
*natural_size = natural;
}
static void
gtk_viewport_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_viewport_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
}
static void
gtk_viewport_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
gtk_viewport_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
}
#define __GTK_VIEWPORT_C__
#include "gtkaliasdef.c"

View File

@ -53,6 +53,7 @@
#include "gtkinvisible.h"
#include "gtkbuildable.h"
#include "gtkbuilderprivate.h"
#include "gtkextendedlayout.h"
#include "gtkalias.h"
/**
@ -344,6 +345,14 @@ static void gtk_widget_buildable_custom_finished (GtkBuildable
static void gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
GtkBuilder *builder);
static void gtk_widget_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_widget_real_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_widget_real_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_widget_queue_tooltip_query (GtkWidget *widget);
static void gtk_widget_set_usize_internal (GtkWidget *widget,
@ -419,6 +428,13 @@ gtk_widget_get_type (void)
NULL /* interface data */
};
const GInterfaceInfo layout_info =
{
(GInterfaceInitFunc) gtk_widget_extended_layout_init,
(GInterfaceFinalizeFunc) NULL,
NULL /* interface data */
};
widget_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkWidget",
&widget_info, G_TYPE_FLAG_ABSTRACT);
@ -426,7 +442,8 @@ gtk_widget_get_type (void)
&accessibility_info) ;
g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
&buildable_info) ;
g_type_add_interface_static (widget_type, GTK_TYPE_EXTENDED_LAYOUT,
&layout_info) ;
}
return widget_type;
@ -2836,6 +2853,8 @@ gtk_widget_init (GtkWidget *widget)
GTK_PRIVATE_SET_FLAG (widget, GTK_REDRAW_ON_ALLOC);
GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_WIDTH_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_HEIGHT_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
widget->style = gtk_widget_get_default_style ();
@ -3862,7 +3881,7 @@ gtk_widget_draw (GtkWidget *widget,
* Also remember that the size request is not necessarily the size
* a widget will actually be allocated.
*
* See also gtk_widget_get_child_requisition().
* Deprecated: 3.0: Use gtk_extended_layout_get_desired_size() instead.
**/
void
gtk_widget_size_request (GtkWidget *widget,
@ -3872,10 +3891,11 @@ gtk_widget_size_request (GtkWidget *widget,
#ifdef G_ENABLE_DEBUG
if (requisition == &widget->requisition)
g_warning ("gtk_widget_size_request() called on child widget with request equal\n to widget->requisition. gtk_widget_set_usize() may not work properly.");
g_warning ("gtk_widget_size_request() called on child widget with request equal\n"
"to widget->requisition. gtk_widget_set_usize() may not work properly.");
#endif /* G_ENABLE_DEBUG */
_gtk_size_group_compute_requisition (widget, requisition);
gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (widget), FALSE, requisition, NULL);
}
/**
@ -3901,12 +3921,15 @@ gtk_widget_size_request (GtkWidget *widget,
* since the last time a resize was queued. In general, only container
* implementations have this information; applications should use
* gtk_widget_size_request().
*
*
* Deprecated: 3.0: Use gtk_extended_layout_get_desired_size() instead.
**/
void
gtk_widget_get_child_requisition (GtkWidget *widget,
GtkRequisition *requisition)
{
_gtk_size_group_get_child_requisition (widget, requisition);
gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (widget), FALSE, requisition, NULL);
}
static gboolean
@ -9322,20 +9345,18 @@ _gtk_widget_get_aux_info (GtkWidget *widget,
aux_info = g_object_get_qdata (G_OBJECT (widget), quark_aux_info);
if (!aux_info && create)
{
aux_info = g_slice_new (GtkWidgetAuxInfo);
aux_info = g_slice_new0 (GtkWidgetAuxInfo);
aux_info->width = -1;
aux_info->height = -1;
aux_info->x = 0;
aux_info->y = 0;
aux_info->x_set = FALSE;
aux_info->y_set = FALSE;
g_object_set_qdata (G_OBJECT (widget), quark_aux_info, aux_info);
}
return aux_info;
}
/*****************************************
* gtk_widget_aux_info_destroy:
*
@ -10768,6 +10789,66 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
}
}
/*
* GtkExtendedLayout implementation
*/
static void
gtk_widget_real_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
/* Set the initial values so that unimplemented classes will fall back
* on the "size-request" collected values (see gtksizegroup.c:do_size_request()).
*/
if (minimum_size)
*minimum_size = GTK_WIDGET (layout)->requisition.width;
if (natural_size)
*natural_size = GTK_WIDGET (layout)->requisition.width;
}
static void
gtk_widget_real_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
/* Set the initial values so that unimplemented classes will fall back
* on the "size-request" collected values (see gtksizegroup.c:do_size_request()).
*/
if (minimum_size)
*minimum_size = GTK_WIDGET (layout)->requisition.height;
if (natural_size)
*natural_size = GTK_WIDGET (layout)->requisition.height;
}
static void
gtk_widget_real_get_height_for_width (GtkExtendedLayout *layout,
gint width,
gint *minimum_height,
gint *natural_height)
{
gtk_extended_layout_get_desired_height (layout, minimum_height, natural_height);
}
static void
gtk_widget_real_get_width_for_height (GtkExtendedLayout *layout,
gint height,
gint *minimum_width,
gint *natural_width)
{
gtk_extended_layout_get_desired_width (layout, minimum_width, natural_width);
}
static void
gtk_widget_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_widget_real_get_desired_width;
iface->get_desired_height = gtk_widget_real_get_desired_height;
iface->get_width_for_height = gtk_widget_real_get_width_for_height;
iface->get_height_for_width = gtk_widget_real_get_height_for_width;
}
/**
* gtk_widget_get_clipboard:

View File

@ -482,6 +482,7 @@ typedef struct _GtkClipboard GtkClipboard;
typedef struct _GtkTooltip GtkTooltip;
typedef struct _GtkWindow GtkWindow;
/**
* GtkAllocation:
* @x: the X position of the widget's area relative to its parents allocation.
@ -817,6 +818,7 @@ struct _GtkWidgetAuxInfo
gint y;
gint width;
gint height;
guint x_set : 1;
guint y_set : 1;
};

View File

@ -48,6 +48,7 @@
#include "gtkmarshalers.h"
#include "gtkplug.h"
#include "gtkbuildable.h"
#include "gtkextendedlayout.h"
#include "gtkalias.h"
#ifdef GDK_WINDOWING_X11
@ -207,8 +208,6 @@ static void gtk_window_map (GtkWidget *widget);
static void gtk_window_unmap (GtkWidget *widget);
static void gtk_window_realize (GtkWidget *widget);
static void gtk_window_unrealize (GtkWidget *widget);
static void gtk_window_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gint gtk_window_event (GtkWidget *widget,
@ -350,9 +349,19 @@ static void gtk_window_buildable_custom_finished (GtkBuildable *buildable,
gpointer user_data);
static void gtk_window_extended_layout_init (GtkExtendedLayoutIface *iface);
static void gtk_window_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
static void gtk_window_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size);
G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_window_buildable_interface_init))
gtk_window_buildable_interface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
gtk_window_extended_layout_init))
static void
add_tab_bindings (GtkBindingSet *binding_set,
@ -451,7 +460,6 @@ gtk_window_class_init (GtkWindowClass *klass)
widget_class->unmap = gtk_window_unmap;
widget_class->realize = gtk_window_realize;
widget_class->unrealize = gtk_window_unrealize;
widget_class->size_request = gtk_window_size_request;
widget_class->size_allocate = gtk_window_size_allocate;
widget_class->configure_event = gtk_window_configure_event;
widget_class->key_press_event = gtk_window_key_press_event;
@ -4933,30 +4941,6 @@ gtk_window_unrealize (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
}
static void
gtk_window_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkWindow *window;
GtkBin *bin;
window = GTK_WINDOW (widget);
bin = GTK_BIN (window);
requisition->width = GTK_CONTAINER (window)->border_width * 2;
requisition->height = GTK_CONTAINER (window)->border_width * 2;
if (bin->child && gtk_widget_get_visible (bin->child))
{
GtkRequisition child_requisition;
gtk_widget_size_request (bin->child, &child_requisition);
requisition->width += child_requisition.width;
requisition->height += child_requisition.height;
}
}
static void
gtk_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
@ -5546,6 +5530,64 @@ gtk_window_real_set_focus (GtkWindow *window,
}
}
static void
gtk_window_extended_layout_init (GtkExtendedLayoutIface *iface)
{
iface->get_desired_width = gtk_window_get_desired_width;
iface->get_desired_height = gtk_window_get_desired_height;
}
static void
gtk_window_get_desired_width (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
GtkWindow *window;
GtkWidget *child;
window = GTK_WINDOW (layout);
child = gtk_bin_get_child (GTK_BIN (window));
*minimum_size = GTK_CONTAINER (window)->border_width * 2;
*natural_size = GTK_CONTAINER (window)->border_width * 2;
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (child), &child_min, &child_nat);
*minimum_size += child_min;
*natural_size += child_nat;
}
}
static void
gtk_window_get_desired_height (GtkExtendedLayout *layout,
gint *minimum_size,
gint *natural_size)
{
GtkWindow *window;
GtkWidget *child;
window = GTK_WINDOW (layout);
child = gtk_bin_get_child (GTK_BIN (window));
*minimum_size = GTK_CONTAINER (window)->border_width * 2;
*natural_size = GTK_CONTAINER (window)->border_width * 2;
if (child && gtk_widget_get_visible (child))
{
gint child_min, child_nat;
gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (child), &child_min, &child_nat);
*minimum_size += child_min;
*natural_size += child_nat;
}
}
/**
* _gtk_window_unset_focus_and_default:
* @window: a #GtkWindow

View File

@ -29,6 +29,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
simple \
flicker \
print-editor \
extendedlayoutexample \
testaccel \
testassistant \
testbbox \
@ -112,6 +113,7 @@ endif
flicker_DEPENDENCIES = $(TEST_DEPS)
simple_DEPENDENCIES = $(TEST_DEPS)
print_editor_DEPENDENCIES = $(TEST_DEPS)
extendedlayoutexample_DEPENDENCIES = $(TEST_DEPS)
testicontheme_DEPENDENCIES = $(TEST_DEPS)
testiconview_DEPENDENCIES = $(TEST_DEPS)
testaccel_DEPENDENCIES = $(TEST_DEPS)
@ -176,6 +178,7 @@ testwindows_DEPENDENCIES = $(TEST_DEPS)
flicker_LDADD = $(LDADDS)
simple_LDADD = $(LDADDS)
print_editor_LDADD = $(LDADDS)
extendedlayoutexample_LDADD = $(LDADDS)
testaccel_LDADD = $(LDADDS)
testassistant_LDADD = $(LDADDS)
testbbox_LDADD = $(LDADDS)

View File

@ -0,0 +1,614 @@
/* extendedlayoutexample.c
* Copyright (C) 2010 Openismus GmbH
*
* Author:
* Tristan Van Berkom <tristan.van.berkom@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library 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.
*/
#include <gtk/gtk.h>
typedef struct {
const gchar *name;
const gchar *tooltip;
const gchar *interface;
GtkWidget *window;
} TestInterface;
/* These strings were generated with:
*
* IFS=""; while read line; do echo -n \"; echo -n $line | sed -e 's|\"|\\"|g'; echo \"; done < file.glade
*/
TestInterface interfaces[] = {
{
"Ellipsizing Labels",
"Demonstrates how labels will request a natural size in a horizontal space",
"<interface>"
" <requires lib=\"gtk+\" version=\"2.20\"/>"
" <!-- interface-naming-policy project-wide -->"
" <object class=\"GtkWindow\" id=\"window\">"
" <property name=\"default_width\">450</property>"
" <property name=\"default_height\">50</property>"
" <child>"
" <object class=\"GtkHBox\" id=\"hbox5\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label9\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">Some labels do ellipsize</property>"
" <property name=\"ellipsize\">end</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#09610feefe03\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label10\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">but some</property>"
" <property name=\"ellipsize\">end</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#0000af6b0993\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label11\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">do not at all</property>"
" <attributes>"
" <attribute name=\"style\" value=\"normal\"/>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#ffff00000000\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">2</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
" </object>"
"</interface>",
NULL
},
{
"Wrapping Label",
"Demonstrates how a wrapping label can require a height contextual to its allocated width",
"<interface>"
" <requires lib=\"gtk+\" version=\"2.18\"/>"
" <!-- interface-naming-policy project-wide -->"
" <object class=\"GtkWindow\" id=\"window\">"
" <property name=\"border_width\">12</property>"
" <property name=\"default_width\">300</property>"
" <child>"
" <object class=\"GtkHPaned\" id=\"hpaned1\">"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <child>"
" <object class=\"GtkVBox\" id=\"vbox2\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label3\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">A short static label.</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label1\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">This is a really long label for the purpose of testing line wrapping is working correctly in conjunction with height-for-width support in GTK+</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"max_width_chars\">30</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#18c52119f796\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkButton\" id=\"button2\">"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <property name=\"receives_default\">True</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label2\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">A really really long label inside a button to demonstrate height for width working inside buttons</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"max_width_chars\">25</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#1e3687ab0a52\"/>"
" </attributes>"
" </object>"
" </child>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"position\">2</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"resize\">False</property>"
" <property name=\"shrink\">False</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label4\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">This static label\n"
"can shrink.</property>"
" <property name=\"justify\">center</property>"
" <attributes>"
" <attribute name=\"style\" value=\"normal\"/>"
" <attribute name=\"foreground\" value=\"#ffff00000000\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"resize\">True</property>"
" <property name=\"shrink\">True</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
" </object>"
"</interface>",
NULL
},
{
"Horizontal Box",
"Demonstrates how a horizontal box can calculate the collective height for an allocated width",
"<interface>"
" <requires lib=\"gtk+\" version=\"2.20\"/>"
" <!-- interface-naming-policy project-wide -->"
" <object class=\"GtkWindow\" id=\"window\">"
" <property name=\"default_height\">200</property>"
" <property name=\"default_width\">600</property>"
" <child>"
" <object class=\"GtkHPaned\" id=\"hpaned1\">"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <child>"
" <object class=\"GtkVBox\" id=\"vbox1\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkHBox\" id=\"hbox1\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkButton\" id=\"button1\">"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <property name=\"receives_default\">True</property>"
" <property name=\"use_action_appearance\">False</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label2\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">A button that wraps.</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"width_chars\">10</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#0000041dffff\"/>"
" </attributes>"
" </object>"
" </child>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label1\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">Lets try setting up some long text to wrap up in this hbox and see if the height-for-width is gonna work !</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"width_chars\">30</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#07d0a9b20972\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkButton\" id=\"button2\">"
" <property name=\"label\" translatable=\"yes\">A button that expands in the vbox</property>"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <property name=\"receives_default\">True</property>"
" <property name=\"use_action_appearance\">False</property>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"resize\">False</property>"
" <property name=\"shrink\">False</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label4\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">This label is\n"
"set to shrink inside\n"
"the paned window.</property>"
" <property name=\"justify\">center</property>"
" <attributes>"
" <attribute name=\"style\" value=\"normal\"/>"
" <attribute name=\"foreground\" value=\"#ffff00000000\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"resize\">True</property>"
" <property name=\"shrink\">True</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
" </object>"
"</interface>",
NULL
},
{
"Vertical Labels",
"Demonstrates how a horizontal box will consider width-for-height when allocating children "
"even if the toplevel window is requested as height-for-width.",
"<interface>"
" <requires lib=\"gtk+\" version=\"2.20\"/>"
" <!-- interface-naming-policy project-wide -->"
" <object class=\"GtkWindow\" id=\"window\">"
" <property name=\"default_width\">400</property>"
" <property name=\"default_height\">300</property>"
" <child>"
" <object class=\"GtkVPaned\" id=\"vpaned1\">"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <child>"
" <object class=\"GtkHBox\" id=\"hbox1\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label1\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">Some long width-for-height text that wraps</property>"
" <property name=\"justify\">center</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"width_chars\">10</property>"
" <property name=\"angle\">90</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#03e307ddfb5f\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkFrame\" id=\"frame1\">"
" <property name=\"visible\">True</property>"
" <property name=\"label_xalign\">0</property>"
" <property name=\"shadow_type\">out</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label5\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">Neither of the panes are\n"
"set to shrink.</property>"
" <property name=\"justify\">center</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#ffff00000000\"/>"
" </attributes>"
" </object>"
" </child>"
" <child type=\"label_item\">"
" <placeholder/>"
" </child>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"resize\">False</property>"
" <property name=\"shrink\">False</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkHBox\" id=\"hbox2\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkFrame\" id=\"frame2\">"
" <property name=\"visible\">True</property>"
" <property name=\"label_xalign\">0</property>"
" <property name=\"shadow_type\">out</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label4\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">The interface is allocated as height\n"
"for width, but the horizontal boxes\n"
"allocate in width for height mode.</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#000097970808\"/>"
" </attributes>"
" </object>"
" </child>"
" <child type=\"label_item\">"
" <placeholder/>"
" </child>"
" </object>"
" <packing>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label3\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">Some long width-for-height text that wraps</property>"
" <property name=\"justify\">center</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"width_chars\">10</property>"
" <property name=\"angle\">270</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#03e307ddfb5f\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"resize\">False</property>"
" <property name=\"shrink\">False</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
" </object>"
"</interface>",
NULL
},
{
"Label Parameters",
"This test demonstrates how \"width-chars\" and \"max-width-chars\" can be used "
"to effect minimum and natural widths in wrapping labels.",
"<interface>"
" <requires lib=\"gtk+\" version=\"2.20\"/>"
" <!-- interface-naming-policy project-wide -->"
" <object class=\"GtkWindow\" id=\"window\">"
" <property name=\"default_width\">900</property>"
" <child>"
" <object class=\"GtkHPaned\" id=\"hpaned1\">"
" <property name=\"visible\">True</property>"
" <property name=\"can_focus\">True</property>"
" <child>"
" <object class=\"GtkVBox\" id=\"vbox1\">"
" <property name=\"visible\">True</property>"
" <child>"
" <object class=\"GtkHBox\" id=\"hbox1\">"
" <property name=\"visible\">True</property>"
" <property name=\"spacing\">6</property>"
" <child>"
" <object class=\"GtkLabel\" id=\"label1\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">The first 2 labels require 10 characters.</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"width_chars\">10</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#ffff00000000\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"expand\">False</property>"
" <property name=\"fill\">False</property>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label2\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">This label has a maximum natural width of 20 characters. The second two labels expand.</property>"
" <property name=\"wrap\">True</property>"
" <property name=\"width_chars\">10</property>"
" <property name=\"max_width_chars\">20</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#05c2a161134b\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"expand\">True</property>"
" <property name=\"fill\">True</property>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label3\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">This label requires a default minimum size.</property>"
" <property name=\"wrap\">True</property>"
" <attributes>"
" <attribute name=\"weight\" value=\"bold\"/>"
" <attribute name=\"foreground\" value=\"#03e30758fb5f\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">2</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"position\">0</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label4\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">This test demonstrates how the \"width-chars\" and \"max-width-chars\"\n"
"properties can be used to specify the minimum requested wrap width\n"
"and the maximum natural wrap width respectively.</property>"
" <property name=\"ellipsize\">end</property>"
" <property name=\"width_chars\">30</property>"
" <attributes>"
" <attribute name=\"style\" value=\"normal\"/>"
" <attribute name=\"foreground\" value=\"#05470000abaf\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"position\">1</property>"
" </packing>"
" </child>"
" </object>"
" <packing>"
" <property name=\"resize\">False</property>"
" <property name=\"shrink\">False</property>"
" </packing>"
" </child>"
" <child>"
" <object class=\"GtkLabel\" id=\"label5\">"
" <property name=\"visible\">True</property>"
" <property name=\"label\" translatable=\"yes\">Some static\n"
"text that shrinks.\n"
"\n"
"You will need to stretch\n"
"this window quite wide\n"
"to see the effects.</property>"
" <property name=\"justify\">center</property>"
" <attributes>"
" <attribute name=\"foreground\" value=\"#ffff00000000\"/>"
" </attributes>"
" </object>"
" <packing>"
" <property name=\"resize\">True</property>"
" <property name=\"shrink\">True</property>"
" </packing>"
" </child>"
" </object>"
" </child>"
" </object>"
"</interface>",
NULL
},
};
static void
test_clicked (GtkWidget *button,
TestInterface *interface)
{
if (!interface->window)
{
GtkBuilder *builder = gtk_builder_new ();
gtk_builder_add_from_string (builder, interface->interface, -1, NULL);
interface->window = (GtkWidget *)gtk_builder_get_object (builder, "window");
g_signal_connect (interface->window, "delete_event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
}
gtk_widget_show (interface->window);
}
static GtkWidget *
create_window (void)
{
GtkWidget *window, *vbox, *button;
gint i;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
vbox = gtk_vbox_new (FALSE, 6);
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
gtk_widget_show (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);
for (i = 0; i < G_N_ELEMENTS (interfaces); i++)
{
button = gtk_button_new_with_label (interfaces[i].name);
gtk_widget_set_tooltip_text (button, interfaces[i].tooltip);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (test_clicked), &interfaces[i]);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
}
return window;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = create_window ();
g_signal_connect (window, "delete-event",
G_CALLBACK (gtk_main_quit), window);
gtk_widget_show (window);
gtk_main ();
return 0;
}

View File

@ -25,6 +25,21 @@
#include <gtk/gtk.h>
static void
redraw_event_box (GtkWidget *widget)
{
while (widget)
{
if (GTK_IS_EVENT_BOX (widget))
{
gtk_widget_queue_draw (widget);
break;
}
widget = gtk_widget_get_parent (widget);
}
}
static void
combo_changed_cb (GtkWidget *combo,
gpointer data)
@ -33,33 +48,123 @@ combo_changed_cb (GtkWidget *combo,
gint active;
active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
gtk_label_set_ellipsize (GTK_LABEL (label), (PangoEllipsizeMode)active);
redraw_event_box (label);
}
static void
scale_changed_cb (GtkRange *range,
gpointer data)
{
double angle = gtk_range_get_value (range);
GtkWidget *label = GTK_WIDGET (data);
gtk_label_set_angle (GTK_LABEL (label), angle);
redraw_event_box (label);
}
static gboolean
ebox_expose_event_cb (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
PangoLayout *layout;
const double dashes[] = { 6, 18 };
GtkRequisition minimum_size, natural_size;
GtkWidget *label = data;
cairo_t *cr;
gint x, y;
cr = gdk_cairo_create (widget->window);
cairo_translate (cr, -0.5, -0.5);
cairo_set_line_width (cr, 1);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_rectangle (cr, 0, 0, widget->allocation.width, widget->allocation.height);
cairo_fill (cr);
gtk_widget_translate_coordinates (label, widget, 0, 0, &x, &y);
layout = gtk_widget_create_pango_layout (widget, "");
gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (label), FALSE,
&minimum_size, &natural_size);
pango_layout_set_markup (layout,
"<span color='#c33'>\342\227\217 requisition</span>\n"
"<span color='#3c3'>\342\227\217 natural size</span>\n"
"<span color='#33c'>\342\227\217 allocation</span>", -1);
pango_cairo_show_layout (cr, layout);
g_object_unref (layout);
cairo_rectangle (cr,
x + 0.5 * (label->allocation.width - minimum_size.width),
y + 0.5 * (label->allocation.height - minimum_size.height),
minimum_size.width, minimum_size.height);
cairo_set_source_rgb (cr, 0.8, 0.2, 0.2);
cairo_set_dash (cr, NULL, 0, 0);
cairo_stroke (cr);
cairo_rectangle (cr, x, y, label->allocation.width, label->allocation.height);
cairo_set_source_rgb (cr, 0.2, 0.2, 0.8);
cairo_set_dash (cr, dashes, 2, 0.5);
cairo_stroke (cr);
cairo_rectangle (cr,
x + 0.5 * (label->allocation.width - natural_size.width),
y + 0.5 * (label->allocation.height - natural_size.height),
natural_size.width, natural_size.height);
cairo_set_source_rgb (cr, 0.2, 0.8, 0.2);
cairo_set_dash (cr, dashes, 2, 12.5);
cairo_stroke (cr);
cairo_destroy (cr);
return FALSE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window, *vbox, *hbox, *label, *combo;
GtkWidget *window, *vbox, *label;
GtkWidget *combo, *scale, *align, *ebox;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
vbox = gtk_vbox_new (0, FALSE);
vbox = gtk_vbox_new (FALSE, 6);
gtk_container_add (GTK_CONTAINER (window), vbox);
hbox = gtk_hbox_new (0, FALSE);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
label = gtk_label_new ("This label may be ellipsized\nto make it fit.");
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
combo = gtk_combo_box_new_text ();
scale = gtk_hscale_new_with_range (0, 360, 1);
label = gtk_label_new ("This label may be ellipsized\nto make it fit.");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "NONE");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "START");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "MIDDLE");
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "END");
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (align), label);
ebox = gtk_event_box_new ();
gtk_widget_set_app_paintable (ebox, TRUE);
gtk_container_add (GTK_CONTAINER (ebox), align);
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), ebox, TRUE, TRUE, 0);
g_object_set_data (G_OBJECT (label), "combo", combo);
g_signal_connect (combo, "changed", G_CALLBACK (combo_changed_cb), label);
g_signal_connect (scale, "value-changed", G_CALLBACK (scale_changed_cb), label);
g_signal_connect (ebox, "expose-event", G_CALLBACK (ebox_expose_event_cb), label);
gtk_widget_show_all (window);