Compare commits

...

12 Commits

Author SHA1 Message Date
Havoc Pennington
68fa31e268 Add padding and alignment tests to testadjustsize.c 2010-09-12 13:12:17 -04:00
Havoc Pennington
f0d841beed Add margin and alignment properties to GtkWidget
h-align = START,END,CENTER,FILL
v-align = START,END,CENTER,FILL
margin-left,right,top,bottom
margin

These should obsolete all such similar properties on
layout containers, GtkMisc, GtkAlignment, GtkContainer::border-width

Margin is outside the size request.
If margin were not outside the set_size_request() it would not work the
same way as container-supplied (child property) padding.

Conceptually set_size_request() forces the value from the subclass
(the original unadjusted request) and then we go on to adjust
the request further by adding the margin.
2010-09-12 13:12:17 -04:00
Havoc Pennington
59b45073fe GtkButton: let GtkContainer handle border width 2010-09-12 13:12:17 -04:00
Havoc Pennington
248267badb add gtk_container_class_handle_border_width() so subclasses can ignore border_width
A subclass calls gtk_container_class_handle_border_width()
in its class_init

This marks the subclass as expecting GtkContainer to deal with
border width automatically, which GtkContainer then does.
2010-09-12 13:12:16 -04:00
Havoc Pennington
35a666c534 Add testadjustsize test, to test new adjust size methods and related features
This will test size adjust, and interactions with other padding and border
2010-09-12 13:12:16 -04:00
Havoc Pennington
a171c499c3 GtkWidget: add adjust_size_request adjust_size_allocation virtual funcs
Use these new methods to handle set_size_request (aka aux_info)
inside gtkwidget.c, instead of having external code mess with it.

The virtual functions can be used for other purposes in the
future. For example, GtkContainer::border_width could be
automatically implemented for all container subclasses.
2010-09-12 13:12:16 -04:00
Havoc Pennington
d2243056e5 Use _gtk_widget_get_aux_info_or_defaults() when possible in gtkwidget.c
Did not update uses in other files because the plan is to
get rid of those other uses anyhow. So don't want to make
this function available in the header.
2010-09-12 13:12:16 -04:00
Havoc Pennington
6c780fa93b add _gtk_widget_get_aux_info_or_defaults()
This is better than peeking aux info then testing != NULL
in several ways:
- it returns const aux info so if we don't create we can't write
- it ensures that the default we assume if aux_info is NULL is
  the same as the default we set if we've created the aux info
- it avoids typing in != NULL checks
2010-09-12 13:12:16 -04:00
Havoc Pennington
3cd07cb78c Fix more SizeRequest implementations to avoid recursive calls to wrapper API
GtkFrame, GtkComboBox, GtkExpander, GtkMenu, GtkWrapBox

These are all the examples I could find so far.

https://bugzilla.gnome.org/show_bug.cgi?id=628829
2010-09-12 13:12:16 -04:00
Havoc Pennington
a0a0495145 Warn about recursively calling size req wrappers on the same object and orientation
We are not re-entrant and there is no reason for widgets to
do this, most likely they'll just get unexpected bugs because
the wrappers may modify the request.

Computing the request should logically rely only on the
widget itself, not on any adjustments caused by set_size_request,
size groups, and so forth.

https://bugzilla.gnome.org/show_bug.cgi?id=628829
2010-09-12 13:12:16 -04:00
Havoc Pennington
ed06fbd674 default impls of width_for_height,hfw should chain directly not use wrapper API
In GtkBin and GtkWidget we tried to provide handy defaults that
call get_width if there's no get_width_for_height and
get_height for get_height_for_width.

However, they used the wrapper API on GtkSizeRequest instead of
chaining directly to the other method implementation.

This could result in all kinds of surprising behavior, for example,
get_width_for_height() would now already include the effects of set_size_request().

If nothing else it's inefficient. But it's just conceptually wrong,
because to chain to another implementation, we should call the other
implementation, not call a wrapper around the other implementation
(when we're already inside a previous invocation of the wrapper,
i.e. compute_size_for_orientation() ends up reinvoking itself
in the same orientation on the same object which it pretty
likely isn't intending to do)

https://bugzilla.gnome.org/show_bug.cgi?id=628829
2010-09-12 13:12:16 -04:00
Havoc Pennington
4b409c3c28 Use gint16 for GtkBorder
32K of border ought to be enough for any pixel dimensions. At least
until screens are so huge we start using doubles.

This saves a nice 64 bits of space when we have a GtkBorder
stored somewhere.

Signed integers are used to avoid surprising unsigned math
issues. Just search GTK's whole git log from inception
for "unsigned" if you want to find any number of commits
fixing signed/unsigned bugs.

https://bugzilla.gnome.org/show_bug.cgi?id=629387
2010-09-12 13:12:16 -04:00
18 changed files with 1353 additions and 114 deletions

View File

@@ -214,10 +214,15 @@ get_child_padding_delta (GtkBin *bin,
gint *delta_v)
{
GtkBinPrivate *priv = bin->priv;
gint hmin, vmin, child_hmin, child_vmin;
gint hmin, vmin, hnat, vnat, child_hmin, child_vmin;
gtk_size_request_get_width (GTK_SIZE_REQUEST (bin), &hmin, NULL);
gtk_size_request_get_height (GTK_SIZE_REQUEST (bin), &vmin, NULL);
/* we can't use gtk_size_request_get_width() wrapper because we want
* our "original" request, not any external adjustments from
* set_size_request() or whatever. we have to ask for natural also
* because NULL isn't allowed for the direct vfuncs
*/
GTK_SIZE_REQUEST_GET_IFACE (bin)->get_width(GTK_SIZE_REQUEST (bin), &hmin, &hnat);
GTK_SIZE_REQUEST_GET_IFACE (bin)->get_height (GTK_SIZE_REQUEST (bin), &vmin, &vnat);
gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->child), &child_hmin, NULL);
gtk_size_request_get_height (GTK_SIZE_REQUEST (priv->child), &child_vmin, NULL);

View File

@@ -227,6 +227,7 @@ gtk_button_class_init (GtkButtonClass *klass)
container_class->child_type = gtk_button_child_type;
container_class->add = gtk_button_add;
gtk_container_class_handle_border_width (container_class);
klass->pressed = gtk_real_button_pressed;
klass->released = gtk_real_button_released;
@@ -1284,19 +1285,16 @@ gtk_button_realize (GtkWidget *widget)
GdkWindow *window;
GdkWindowAttr attributes;
gint attributes_mask;
gint border_width;
gtk_widget_get_allocation (widget, &allocation);
gtk_widget_set_realized (widget, TRUE);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
attributes.window_type = GDK_WINDOW_CHILD;
attributes.x = allocation.x + border_width;
attributes.y = allocation.y + border_width;
attributes.width = allocation.width - border_width * 2;
attributes.height = allocation.height - border_width * 2;
attributes.x = allocation.x;
attributes.y = allocation.y;
attributes.width = allocation.width;
attributes.height = allocation.height;
attributes.wclass = GDK_INPUT_ONLY;
attributes.event_mask = gtk_widget_get_events (widget);
attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
@@ -1455,7 +1453,6 @@ gtk_button_size_allocate (GtkWidget *widget,
GtkStyle *style;
GtkWidget *child;
guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gint xthickness, ythickness;
GtkBorder default_border;
GtkBorder inner_border;
@@ -1476,30 +1473,28 @@ gtk_button_size_allocate (GtkWidget *widget,
if (gtk_widget_get_realized (widget))
gdk_window_move_resize (button->event_window,
allocation->x + border_width,
allocation->y + border_width,
allocation->width - border_width * 2,
allocation->height - border_width * 2);
allocation->x,
allocation->y,
allocation->width,
allocation->height);
child = gtk_bin_get_child (GTK_BIN (button));
if (child && gtk_widget_get_visible (child))
{
child_allocation.x = allocation->x + border_width + inner_border.left + xthickness;
child_allocation.y = allocation->y + border_width + inner_border.top + ythickness;
child_allocation.x = allocation->x + inner_border.left + xthickness;
child_allocation.y = allocation->y + inner_border.top + ythickness;
child_allocation.width =
allocation->width -
xthickness * 2 -
inner_border.left -
inner_border.right -
border_width * 2;
inner_border.right;
child_allocation.height =
allocation->height -
ythickness * 2 -
inner_border.top -
inner_border.bottom -
border_width * 2;
inner_border.bottom;
if (gtk_widget_get_can_default (GTK_WIDGET (button)))
{
@@ -1548,7 +1543,6 @@ _gtk_button_paint (GtkButton *button,
GtkWidget *widget;
gint width, height;
gint x, y;
gint border_width;
GtkBorder default_border;
GtkBorder default_outside_border;
gboolean interior_focus;
@@ -1563,8 +1557,6 @@ _gtk_button_paint (GtkButton *button,
GdkWindow *window;
GtkStyle *style;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
gtk_button_get_props (button, &default_border, &default_outside_border, NULL, &interior_focus);
gtk_widget_style_get (widget,
"focus-line-width", &focus_width,
@@ -1575,10 +1567,10 @@ _gtk_button_paint (GtkButton *button,
style = gtk_widget_get_style (widget);
window = gtk_widget_get_window (widget);
x = allocation.x + border_width;
y = allocation.y + border_width;
width = allocation.width - border_width * 2;
height = allocation.height - border_width * 2;
x = allocation.x;
y = allocation.y;
width = allocation.width;
height = allocation.height;
if (gtk_widget_has_default (widget) &&
GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
@@ -1925,7 +1917,6 @@ gtk_button_get_size (GtkSizeRequest *widget,
gint focus_width;
gint focus_pad;
gint minimum, natural;
guint border_width;
gtk_button_get_props (button, &default_border, NULL, &inner_border, NULL);
gtk_widget_style_get (GTK_WIDGET (widget),
@@ -1933,12 +1924,11 @@ gtk_button_get_size (GtkSizeRequest *widget,
"focus-padding", &focus_pad,
NULL);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
style = gtk_widget_get_style (GTK_WIDGET (widget));
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
minimum = ((border_width + style->xthickness) * 2 +
minimum = (style->xthickness * 2 +
inner_border.left + inner_border.right);
if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
@@ -1946,7 +1936,7 @@ gtk_button_get_size (GtkSizeRequest *widget,
}
else
{
minimum = ((border_width + style->ythickness) * 2 +
minimum = (style->ythickness * 2 +
inner_border.top + inner_border.bottom);
if (gtk_widget_get_can_default (GTK_WIDGET (widget)))

View File

@@ -6172,8 +6172,8 @@ gtk_combo_box_get_height (GtkSizeRequest *widget,
/* Combo box is height-for-width only
* (so we always just reserve enough height for the minimum width) */
gtk_size_request_get_width (widget, &min_width, NULL);
gtk_size_request_get_height_for_width (widget, min_width, minimum_size, natural_size);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, &min_width, NULL);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_height_for_width (widget, min_width, minimum_size, natural_size);
}
static void
@@ -6184,7 +6184,7 @@ gtk_combo_box_get_width_for_height (GtkSizeRequest *widget,
{
/* Combo box is height-for-width only
* (so we assume we always reserved enough height for the minimum width) */
gtk_size_request_get_width (widget, minimum_size, natural_size);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, minimum_size, natural_size);
}

View File

@@ -107,6 +107,13 @@ static gint gtk_container_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_container_map (GtkWidget *widget);
static void gtk_container_unmap (GtkWidget *widget);
static void gtk_container_adjust_size_request (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
gint *natural_size);
static void gtk_container_adjust_size_allocation (GtkWidget *widget,
GtkAllocation *allocation);
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
GtkWidget *child);
@@ -233,7 +240,10 @@ gtk_container_class_init (GtkContainerClass *class)
widget_class->map = gtk_container_map;
widget_class->unmap = gtk_container_unmap;
widget_class->focus = gtk_container_focus;
widget_class->adjust_size_request = gtk_container_adjust_size_request;
widget_class->adjust_size_allocation = gtk_container_adjust_size_allocation;
class->add = gtk_container_add_unimplemented;
class->remove = gtk_container_remove_unimplemented;
class->check_resize = gtk_container_real_check_resize;
@@ -1520,6 +1530,103 @@ gtk_container_resize_children (GtkContainer *container)
gtk_widget_set_allocation (widget, &allocation);
}
static void
gtk_container_adjust_size_request (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
gint *natural_size)
{
GtkContainer *container;
container = GTK_CONTAINER (widget);
if (GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
{
int border_width;
border_width = container->priv->border_width;
*minimum_size += border_width * 2;
*natural_size += border_width * 2;
}
/* chain up last so gtk_widget_set_size_request() values
* will have a chance to overwrite our border width.
*/
parent_class->adjust_size_request (widget, orientation, for_size,
minimum_size, natural_size);
}
static void
gtk_container_adjust_size_allocation (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkContainer *container;
int border_width;
container = GTK_CONTAINER (widget);
parent_class->adjust_size_allocation (widget, allocation);
if (!GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
return;
border_width = container->priv->border_width;
allocation->width -= border_width * 2;
allocation->height -= border_width * 2;
/* If we get a pathological too-small allocation to hold
* even the border width, leave all allocation to the actual
* widget, and leave x,y unchanged. (GtkWidget's min size is
* 1x1 if you're wondering why <1 and not <0)
*
* As long as we have space, set x,y properly.
*/
if (allocation->width < 1)
{
allocation->width += border_width * 2;
}
else
{
allocation->x += border_width;
}
if (allocation->height < 1)
{
allocation->height += border_width * 2;
}
else
{
allocation->y += border_width;
}
}
/**
* gtk_container_class_handle_border_width:
* @klass: the class struct of a #GtkContainer subclass
*
* Modifies a subclass of #GtkContainerClass to automatically add and
* remove the border-width setting on GtkContainer. This allows the
* subclass to ignore the border width in its size request and
* allocate methods. The intent is for a subclass to invoke this
* in its class_init function.
*
* gtk_container_class_handle_border_width() is necessary because it
* would break API too badly to make this behavior the default. So
* subclasses must "opt in" to the parent class handling border_width
* for them.
*/
void
gtk_container_class_handle_border_width (GtkContainerClass *klass)
{
g_return_if_fail (GTK_IS_CONTAINER_CLASS (klass));
klass->handle_border_width = TRUE;
}
/**
* gtk_container_forall:
* @container: a #GtkContainer

View File

@@ -62,6 +62,8 @@ struct _GtkContainerClass
{
GtkWidgetClass parent_class;
unsigned int handle_border_width : 1;
void (*add) (GtkContainer *container,
GtkWidget *widget);
void (*remove) (GtkContainer *container,
@@ -194,6 +196,8 @@ void gtk_container_forall (GtkContainer *container,
GtkCallback callback,
gpointer callback_data);
void gtk_container_class_handle_border_width (GtkContainerClass *klass);
/* Non-public methods */
void _gtk_container_queue_resize (GtkContainer *container);
void _gtk_container_clear_resize_widgets (GtkContainer *container);

View File

@@ -35,6 +35,36 @@
G_BEGIN_DECLS
/**
* GtkAlign:
*
* @GTK_ALIGN_FILL: stretch to fill all space if possible, center if
* no meaningful way to stretch
* @GTK_ALIGN_START: snap to left or top side, leaving space on right
* or bottom
* @GTK_ALIGN_END: snap to right or bottom side, leaving space on left
* or top
* @GTK_ALIGN_CENTER: center natural width of widget inside the
* allocation
*
* Controls how a widget deals with extra space in a single (x or y)
* dimension.
*
* Alignment only matters if the widget receives a "too large"
* allocation, for example if you packed the widget with the "expand"
* flag inside a #GtkBox, then the widget might get extra space. If
* you have for example a 16x16 icon inside a 32x32 space, the icon
* could be scaled and stretched, it could be centered, or it could be
* positioned to one side of the space.
*/
typedef enum
{
GTK_ALIGN_FILL,
GTK_ALIGN_START,
GTK_ALIGN_END,
GTK_ALIGN_CENTER
} GtkAlign;
/* Arrow placement */
typedef enum
{

View File

@@ -1495,8 +1495,7 @@ gtk_expander_get_width_for_height (GtkSizeRequest *widget,
gint *minimum_width,
gint *natural_width)
{
gtk_size_request_get_width (widget, minimum_width, natural_width);
//GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, minimum_width, natural_width);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, minimum_width, natural_width);
}

View File

@@ -925,7 +925,7 @@ gtk_frame_get_width_for_height (GtkSizeRequest *widget,
gint *minimum_width,
gint *natural_width)
{
gtk_size_request_get_width (widget, minimum_width, natural_width);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, minimum_width, natural_width);
}
static void

View File

@@ -3150,8 +3150,8 @@ gtk_menu_get_height (GtkSizeRequest *widget,
gint min_width;
/* Menus are height-for-width only, just return the height for the minimum width */
gtk_size_request_get_width (widget, &min_width, NULL);
gtk_size_request_get_height_for_width (widget, min_width, minimum_size, natural_size);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, &min_width, NULL);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_height_for_width (widget, min_width, minimum_size, natural_size);
}
static void

View File

@@ -1941,6 +1941,7 @@ gtk_rc_property_parse_border (const GParamSpec *pspec,
GtkBorder border;
GScanner *scanner;
gboolean success = FALSE;
int left, right, top, bottom;
g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
@@ -1948,11 +1949,15 @@ gtk_rc_property_parse_border (const GParamSpec *pspec,
scanner = gtk_rc_scanner_new ();
g_scanner_input_text (scanner, gstring->str, gstring->len);
if (get_braced_int (scanner, TRUE, FALSE, &border.left) &&
get_braced_int (scanner, FALSE, FALSE, &border.right) &&
get_braced_int (scanner, FALSE, FALSE, &border.top) &&
get_braced_int (scanner, FALSE, TRUE, &border.bottom))
if (get_braced_int (scanner, TRUE, FALSE, &left) &&
get_braced_int (scanner, FALSE, FALSE, &right) &&
get_braced_int (scanner, FALSE, FALSE, &top) &&
get_braced_int (scanner, FALSE, TRUE, &bottom))
{
border.left = left;
border.right = right;
border.top = top;
border.bottom = bottom;
g_value_set_boxed (property_value, &border);
success = TRUE;
}

View File

@@ -666,35 +666,23 @@ static gint
get_base_dimension (GtkWidget *widget,
GtkSizeGroupMode mode)
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (mode == GTK_SIZE_GROUP_HORIZONTAL)
{
if (aux_info && aux_info->width > 0)
return aux_info->width;
else
{
/* XXX Possibly we should be using natural values and not minimums here. */
gint width;
/* XXX Possibly we should be using natural values and not minimums here. */
gint width;
gtk_size_request_get_width (GTK_SIZE_REQUEST (widget), &width, NULL);
gtk_size_request_get_width (GTK_SIZE_REQUEST (widget), &width, NULL);
return width;
}
return width;
}
else
{
if (aux_info && aux_info->height > 0)
return aux_info->height;
else
{
/* XXX Possibly we should be using natural values and not minimums here. */
gint height;
/* XXX Possibly we should be using natural values and not minimums here. */
gint height;
gtk_size_request_get_height (GTK_SIZE_REQUEST (widget), &height, NULL);
gtk_size_request_get_height (GTK_SIZE_REQUEST (widget), &height, NULL);
return height;
}
return height;
}
}
@@ -801,31 +789,14 @@ _gtk_size_group_bump_requisition (GtkWidget *widget,
if (!is_bumping (widget))
{
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
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);
result = compute_dimension (widget, mode, widget_requisition);
}
mark_bumping (widget, FALSE);
}
return result;

View File

@@ -155,6 +155,57 @@ do_size_request (GtkWidget *widget,
g_signal_emit_by_name (widget, "size-request", requisition);
}
#ifndef G_DISABLE_CHECKS
static GQuark recursion_check_quark = 0;
#endif /* G_DISABLE_CHECKS */
static void
push_recursion_check (GtkSizeRequest *request,
GtkSizeGroupMode orientation,
gint for_size)
{
#ifndef G_DISABLE_CHECKS
const char *previous_method;
const char *method;
if (recursion_check_quark == 0)
recursion_check_quark = g_quark_from_static_string ("gtk-size-request-in-progress");
previous_method = g_object_get_qdata (G_OBJECT (request), recursion_check_quark);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
method = for_size < 0 ? "get_width" : "get_width_for_height";
}
else
{
method = for_size < 0 ? "get_height" : "get_height_for_width";
}
if (previous_method != NULL)
{
g_warning ("%s %p: widget tried to gtk_size_request_%s inside "
" GtkSizeRequest::%s implementation. "
"Should just invoke GTK_SIZE_REQUEST_GET_IFACE(widget)->%s "
"directly rather than using gtk_size_request_%s",
G_OBJECT_TYPE_NAME (request), request,
method, previous_method,
method, method);
}
g_object_set_qdata (G_OBJECT (request), recursion_check_quark, (char*) method);
#endif /* G_DISABLE_CHECKS */
}
static void
pop_recursion_check (GtkSizeRequest *request,
GtkSizeGroupMode orientation)
{
#ifndef G_DISABLE_CHECKS
g_object_set_qdata (G_OBJECT (request), recursion_check_quark, NULL);
#endif
}
static void
compute_size_for_orientation (GtkSizeRequest *request,
GtkSizeGroupMode orientation,
@@ -166,6 +217,7 @@ compute_size_for_orientation (GtkSizeRequest *request,
SizeRequest *cached_size;
GtkWidget *widget;
gboolean found_in_cache = FALSE;
int adjusted_min, adjusted_natural;
g_return_if_fail (GTK_IS_SIZE_REQUEST (request));
g_return_if_fail (minimum_size != NULL || natural_size != NULL);
@@ -207,6 +259,7 @@ compute_size_for_orientation (GtkSizeRequest *request,
/* Unconditional size request runs but is often unhandled. */
do_size_request (widget, &requisition);
push_recursion_check (request, orientation, for_size);
if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
{
requisition_size = requisition.width;
@@ -227,6 +280,7 @@ compute_size_for_orientation (GtkSizeRequest *request,
GTK_SIZE_REQUEST_GET_IFACE (request)->get_height_for_width (request, for_size,
&min_size, &nat_size);
}
pop_recursion_check (request, orientation);
if (min_size > nat_size)
{
@@ -259,12 +313,45 @@ compute_size_for_orientation (GtkSizeRequest *request,
GTK_PRIVATE_UNSET_FLAG (request, GTK_HEIGHT_REQUEST_NEEDED);
}
adjusted_min = cached_size->minimum_size;
adjusted_natural = cached_size->natural_size;
GTK_WIDGET_GET_CLASS (request)->adjust_size_request (GTK_WIDGET (request),
orientation == GTK_SIZE_GROUP_HORIZONTAL ?
GTK_ORIENTATION_HORIZONTAL :
GTK_ORIENTATION_VERTICAL,
cached_size->for_size,
&adjusted_min,
&adjusted_natural);
if (adjusted_min < cached_size->minimum_size ||
adjusted_natural < cached_size->natural_size)
{
g_warning ("%s %p adjusted size %s min %d natural %d must not decrease below min %d natural %d",
G_OBJECT_TYPE_NAME (request), request,
orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal",
adjusted_min, adjusted_natural,
cached_size->minimum_size, cached_size->natural_size);
/* don't use the adjustment */
}
else if (adjusted_min > adjusted_natural)
{
g_warning ("%s %p adjusted size %s min %d natural %d original min %d natural %d has min greater than natural",
G_OBJECT_TYPE_NAME (request), request,
orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal",
adjusted_min, adjusted_natural,
cached_size->minimum_size, cached_size->natural_size);
/* don't use the adjustment */
}
else
{
/* adjustment looks good */
cached_size->minimum_size = adjusted_min;
cached_size->natural_size = adjusted_natural;
}
/* 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 (request),

View File

@@ -416,10 +416,10 @@ struct _GtkStyleClass
*/
struct _GtkBorder
{
gint left;
gint right;
gint top;
gint bottom;
gint16 left;
gint16 right;
gint16 top;
gint16 bottom;
};
GType gtk_style_get_type (void) G_GNUC_CONST;

View File

@@ -278,7 +278,14 @@ enum {
PROP_TOOLTIP_MARKUP,
PROP_TOOLTIP_TEXT,
PROP_WINDOW,
PROP_DOUBLE_BUFFERED
PROP_DOUBLE_BUFFERED,
PROP_H_ALIGN,
PROP_V_ALIGN,
PROP_MARGIN_LEFT,
PROP_MARGIN_RIGHT,
PROP_MARGIN_TOP,
PROP_MARGIN_BOTTOM,
PROP_MARGIN
};
typedef struct _GtkStateData GtkStateData;
@@ -315,7 +322,7 @@ static void gtk_widget_real_unrealize (GtkWidget *widget);
static void gtk_widget_real_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_widget_real_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
GtkAllocation *allocation);
static void gtk_widget_real_style_set (GtkWidget *widget,
GtkStyle *previous_style);
static void gtk_widget_real_direction_changed(GtkWidget *widget,
@@ -359,6 +366,7 @@ static gint gtk_widget_event_internal (GtkWidget *widget,
GdkEvent *event);
static gboolean gtk_widget_real_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
static const GtkWidgetAuxInfo* _gtk_widget_get_aux_info_or_defaults (GtkWidget *widget);
static void gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info);
static AtkObject* gtk_widget_real_get_accessible (GtkWidget *widget);
static void gtk_widget_accessible_interface_init (AtkImplementorIface *iface);
@@ -407,7 +415,16 @@ static void gtk_widget_real_get_height (GtkSizeRequest
gint *natural_size);
static void gtk_widget_queue_tooltip_query (GtkWidget *widget);
static void gtk_widget_real_adjust_size_request (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
gint *natural_size);
static void gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_widget_set_usize_internal (GtkWidget *widget,
gint width,
gint height);
@@ -621,6 +638,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->no_expose_event = NULL;
klass->adjust_size_request = gtk_widget_real_adjust_size_request;
klass->adjust_size_allocation = gtk_widget_real_adjust_size_allocation;
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name",
@@ -850,6 +870,140 @@ gtk_widget_class_init (GtkWidgetClass *klass)
TRUE,
GTK_PARAM_READWRITE));
/**
* GtkWidget:h-align
*
* How to distribute horizontal space if widget gets extra space, see #GtkAlign
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_H_ALIGN,
g_param_spec_enum ("h-align",
P_("Horizontal Alignment"),
P_("How to position in extra horizontal space"),
GTK_TYPE_ALIGN,
GTK_ALIGN_FILL,
GTK_PARAM_READWRITE));
/**
* GtkWidget:v-align
*
* How to distribute vertical space if widget gets extra space, see #GtkAlign
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_V_ALIGN,
g_param_spec_enum ("v-align",
P_("Vertical Alignment"),
P_("How to position in extra vertical space"),
GTK_TYPE_ALIGN,
GTK_ALIGN_FILL,
GTK_PARAM_READWRITE));
/**
* GtkWidget:margin-left
*
* Margin on left side of widget.
*
* This property adds margin outside of the widget's normal size
* request, the margin will be added in addition to the size from
* gtk_widget_set_size_request() for example.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_MARGIN_LEFT,
g_param_spec_int ("margin-left",
P_("Margin on Left"),
P_("Pixels of extra space on the left side"),
0,
G_MAXINT16,
0,
GTK_PARAM_READWRITE));
/**
* GtkWidget:margin-right
*
* Margin on right side of widget.
*
* This property adds margin outside of the widget's normal size
* request, the margin will be added in addition to the size from
* gtk_widget_set_size_request() for example.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_MARGIN_RIGHT,
g_param_spec_int ("margin-right",
P_("Margin on Right"),
P_("Pixels of extra space on the right side"),
0,
G_MAXINT16,
0,
GTK_PARAM_READWRITE));
/**
* GtkWidget:margin-top
*
* Margin on top side of widget.
*
* This property adds margin outside of the widget's normal size
* request, the margin will be added in addition to the size from
* gtk_widget_set_size_request() for example.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_MARGIN_TOP,
g_param_spec_int ("margin-top",
P_("Margin on Top"),
P_("Pixels of extra space on the top side"),
0,
G_MAXINT16,
0,
GTK_PARAM_READWRITE));
/**
* GtkWidget:margin-bottom
*
* Margin on bottom side of widget.
*
* This property adds margin outside of the widget's normal size
* request, the margin will be added in addition to the size from
* gtk_widget_set_size_request() for example.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_MARGIN_BOTTOM,
g_param_spec_int ("margin-bottom",
P_("Margin on Bottom"),
P_("Pixels of extra space on the bottom side"),
0,
G_MAXINT16,
0,
GTK_PARAM_READWRITE));
/**
* GtkWidget:margin
*
* Sets all four sides' margin at once. If read, returns max
* margin on any side.
*
* Since: 3.0
*/
g_object_class_install_property (gobject_class,
PROP_MARGIN,
g_param_spec_int ("margin",
P_("All Margins"),
P_("Pixels of extra space on all four sides"),
0,
G_MAXINT16,
0,
GTK_PARAM_READWRITE));
/**
* GtkWidget::show:
* @widget: the object which received the signal.
@@ -2787,6 +2941,32 @@ gtk_widget_set_property (GObject *object,
case PROP_DOUBLE_BUFFERED:
gtk_widget_set_double_buffered (widget, g_value_get_boolean (value));
break;
case PROP_H_ALIGN:
gtk_widget_set_h_align (widget, g_value_get_enum (value));
break;
case PROP_V_ALIGN:
gtk_widget_set_v_align (widget, g_value_get_enum (value));
break;
case PROP_MARGIN_LEFT:
gtk_widget_set_margin_left (widget, g_value_get_int (value));
break;
case PROP_MARGIN_RIGHT:
gtk_widget_set_margin_right (widget, g_value_get_int (value));
break;
case PROP_MARGIN_TOP:
gtk_widget_set_margin_top (widget, g_value_get_int (value));
break;
case PROP_MARGIN_BOTTOM:
gtk_widget_set_margin_bottom (widget, g_value_get_int (value));
break;
case PROP_MARGIN:
g_object_freeze_notify (G_OBJECT (widget));
gtk_widget_set_margin_left (widget, g_value_get_int (value));
gtk_widget_set_margin_right (widget, g_value_get_int (value));
gtk_widget_set_margin_top (widget, g_value_get_int (value));
gtk_widget_set_margin_bottom (widget, g_value_get_int (value));
g_object_thaw_notify (G_OBJECT (widget));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2897,6 +3077,40 @@ gtk_widget_get_property (GObject *object,
case PROP_DOUBLE_BUFFERED:
g_value_set_boolean (value, gtk_widget_get_double_buffered (widget));
break;
case PROP_H_ALIGN:
g_value_set_enum (value, gtk_widget_get_h_align (widget));
break;
case PROP_V_ALIGN:
g_value_set_enum (value, gtk_widget_get_v_align (widget));
break;
case PROP_MARGIN_LEFT:
g_value_set_int (value, gtk_widget_get_margin_left (widget));
break;
case PROP_MARGIN_RIGHT:
g_value_set_int (value, gtk_widget_get_margin_right (widget));
break;
case PROP_MARGIN_TOP:
g_value_set_int (value, gtk_widget_get_margin_top (widget));
break;
case PROP_MARGIN_BOTTOM:
g_value_set_int (value, gtk_widget_get_margin_bottom (widget));
break;
case PROP_MARGIN:
{
GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (aux_info == NULL)
{
g_value_set_int (value, 0);
}
else
{
g_value_set_int (value, MAX (MAX (aux_info->margin.left,
aux_info->margin.right),
MAX (aux_info->margin.top,
aux_info->margin.bottom)));
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3968,7 +4182,11 @@ gtk_widget_queue_shallow_draw (GtkWidget *widget)
* @allocation: (inout): position and size to be allocated to @widget
*
* This function is only used by #GtkContainer subclasses, to assign a size
* and position to their child widgets.
* and position to their child widgets.
*
* In this function, the allocation may be adjusted. It will be forced
* to a 1x1 minimum size, and the adjust_size_allocation virtual method
* on the child will be used to adjust the allocation.
**/
void
gtk_widget_size_allocate (GtkWidget *widget,
@@ -3977,6 +4195,7 @@ gtk_widget_size_allocate (GtkWidget *widget,
GtkWidgetPrivate *priv;
GdkRectangle real_allocation;
GdkRectangle old_allocation;
GdkRectangle adjusted_allocation;
gboolean alloc_needed;
gboolean size_changed;
gboolean position_changed;
@@ -4015,6 +4234,27 @@ gtk_widget_size_allocate (GtkWidget *widget,
old_allocation = priv->allocation;
real_allocation = *allocation;
adjusted_allocation = real_allocation;
GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget, &adjusted_allocation);
if (adjusted_allocation.x < real_allocation.x ||
adjusted_allocation.y < real_allocation.y ||
(adjusted_allocation.x + adjusted_allocation.width) >
(real_allocation.x + real_allocation.width) ||
(adjusted_allocation.y + adjusted_allocation.height >
real_allocation.y + real_allocation.height))
{
g_warning ("%s %p attempted to adjust its size allocation from %d,%d %dx%d to %d,%d %dx%d. adjust_size_allocation must keep allocation inside original bounds",
G_OBJECT_TYPE_NAME (widget), widget,
real_allocation.x, real_allocation.y, real_allocation.width, real_allocation.height,
adjusted_allocation.x, adjusted_allocation.y, adjusted_allocation.width, adjusted_allocation.height);
adjusted_allocation = real_allocation; /* veto it */
}
else
{
real_allocation = adjusted_allocation;
}
if (real_allocation.width < 0 || real_allocation.height < 0)
{
g_warning ("gtk_widget_size_allocate(): attempt to allocate widget with width %d and height %d",
@@ -4269,6 +4509,122 @@ gtk_widget_real_size_allocate (GtkWidget *widget,
}
}
static void
get_span_inside_border (GtkWidget *widget,
GtkAlign align,
int start_pad,
int end_pad,
int allocated_outside_size,
int natural_inside_size,
int *coord_inside_p,
int *size_inside_p)
{
int inside_allocated;
int content_size;
int coord, size;
inside_allocated = allocated_outside_size - start_pad - end_pad;
content_size = natural_inside_size;
if (content_size > inside_allocated)
{
/* didn't get full natural size */
content_size = inside_allocated;
}
coord = size = 0; /* silence compiler */
switch (align)
{
case GTK_ALIGN_FILL:
coord = start_pad;
size = inside_allocated;
break;
case GTK_ALIGN_START:
coord = start_pad;
size = content_size;
break;
case GTK_ALIGN_END:
coord = allocated_outside_size - end_pad - content_size;
size = content_size;
break;
case GTK_ALIGN_CENTER:
coord = start_pad + (inside_allocated - content_size) / 2;
size = content_size;
break;
}
if (coord_inside_p)
*coord_inside_p = coord;
if (size_inside_p)
*size_inside_p = size;
}
static void
get_span_inside_border_horizontal (GtkWidget *widget,
const GtkWidgetAuxInfo *aux_info,
int allocated_outside_width,
int natural_inside_width,
int *x_inside_p,
int *width_inside_p)
{
get_span_inside_border (widget,
aux_info->h_align,
aux_info->margin.left,
aux_info->margin.right,
allocated_outside_width,
natural_inside_width,
x_inside_p,
width_inside_p);
}
static void
get_span_inside_border_vertical (GtkWidget *widget,
const GtkWidgetAuxInfo *aux_info,
int allocated_outside_height,
int natural_inside_height,
int *y_inside_p,
int *height_inside_p)
{
get_span_inside_border (widget,
aux_info->v_align,
aux_info->margin.top,
aux_info->margin.bottom,
allocated_outside_height,
natural_inside_height,
y_inside_p,
height_inside_p);
}
static void
gtk_widget_real_adjust_size_allocation (GtkWidget *widget,
GtkAllocation *allocation)
{
const GtkWidgetAuxInfo *aux_info;
GtkRequisition min, natural;
int x, y, w, h;
aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
gtk_size_request_get_size (GTK_SIZE_REQUEST (widget), &min, &natural);
get_span_inside_border_horizontal (widget,
aux_info,
allocation->width,
natural.width,
&x, &w);
get_span_inside_border_vertical (widget,
aux_info,
allocation->height,
natural.height,
&y, &h);
allocation->x += x;
allocation->y += y;
allocation->width = w;
allocation->height = h;
}
static gboolean
gtk_widget_real_can_activate_accel (GtkWidget *widget,
guint signal_id)
@@ -7979,6 +8335,11 @@ gtk_widget_set_usize_internal (GtkWidget *widget,
*
* Widgets can't actually be allocated a size less than 1 by 1, but
* you can pass 0,0 to this function to mean "as small as possible."
*
* The size request set here does not include any margin from the
* #GtkWidget properties margin-left, margin-right, margin-top, and
* margin-bottom, but it does include pretty much all other padding
* or border properties set by any subclass of #GtkWidget.
**/
void
gtk_widget_set_size_request (GtkWidget *widget,
@@ -8017,17 +8378,17 @@ gtk_widget_get_size_request (GtkWidget *widget,
gint *width,
gint *height)
{
GtkWidgetAuxInfo *aux_info;
const GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
aux_info = _gtk_widget_get_aux_info_or_defaults (widget);
if (width)
*width = aux_info ? aux_info->width : -1;
*width = aux_info->width;
if (height)
*height = aux_info ? aux_info->height : -1;
*height = aux_info->height;
}
/**
@@ -9053,6 +9414,46 @@ gtk_widget_real_size_request (GtkWidget *widget,
requisition->height = 0;
}
static void
gtk_widget_real_adjust_size_request (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
gint *natural_size)
{
const GtkWidgetAuxInfo *aux_info;
aux_info =_gtk_widget_get_aux_info_or_defaults (widget);
if (orientation == GTK_ORIENTATION_HORIZONTAL &&
aux_info->width > 0)
{
*minimum_size = MAX (*minimum_size, aux_info->width);
}
else if (orientation == GTK_ORIENTATION_VERTICAL &&
aux_info->height > 0)
{
*minimum_size = MAX (*minimum_size, aux_info->height);
}
/* Fix it if set_size_request made natural size smaller than min size.
* This would also silently fix broken widgets, but we warn about them
* in gtksizerequest.c when calling their size request vfuncs.
*/
*natural_size = MAX (*natural_size, *minimum_size);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
*minimum_size += (aux_info->margin.left + aux_info->margin.right);
*natural_size += (aux_info->margin.left + aux_info->margin.right);
}
else
{
*minimum_size += (aux_info->margin.top + aux_info->margin.bottom);
*natural_size += (aux_info->margin.top + aux_info->margin.bottom);
}
}
/**
* _gtk_widget_peek_colormap:
*
@@ -9555,6 +9956,13 @@ gtk_widget_propagate_state (GtkWidget *widget,
}
}
static const GtkWidgetAuxInfo default_aux_info = {
-1, -1,
GTK_ALIGN_FILL,
GTK_ALIGN_FILL,
{ 0, 0, 0, 0 }
};
/*
* _gtk_widget_get_aux_info:
* @widget: a #GtkWidget
@@ -9576,8 +9984,7 @@ _gtk_widget_get_aux_info (GtkWidget *widget,
{
aux_info = g_slice_new0 (GtkWidgetAuxInfo);
aux_info->width = -1;
aux_info->height = -1;
*aux_info = default_aux_info;
g_object_set_qdata (G_OBJECT (widget), quark_aux_info, aux_info);
}
@@ -9585,6 +9992,21 @@ _gtk_widget_get_aux_info (GtkWidget *widget,
return aux_info;
}
static const GtkWidgetAuxInfo*
_gtk_widget_get_aux_info_or_defaults (GtkWidget *widget)
{
GtkWidgetAuxInfo *aux_info;
aux_info = _gtk_widget_get_aux_info (widget, FALSE);
if (aux_info == NULL)
{
return &default_aux_info;
}
else
{
return aux_info;
}
}
/*****************************************
* gtk_widget_aux_info_destroy:
@@ -11040,7 +11462,7 @@ gtk_widget_real_get_height_for_width (GtkSizeRequest *layout,
gint *minimum_height,
gint *natural_height)
{
gtk_size_request_get_height (layout, minimum_height, natural_height);
GTK_SIZE_REQUEST_GET_IFACE (layout)->get_height(layout, minimum_height, natural_height);
}
static void
@@ -11048,8 +11470,8 @@ gtk_widget_real_get_width_for_height (GtkSizeRequest *layout,
gint height,
gint *minimum_width,
gint *natural_width)
{
gtk_size_request_get_width (layout, minimum_width, natural_width);
{
GTK_SIZE_REQUEST_GET_IFACE (layout)->get_width(layout, minimum_width, natural_width);
}
static void
@@ -11060,8 +11482,165 @@ gtk_widget_size_request_init (GtkSizeRequestIface *iface)
iface->get_width_for_height = gtk_widget_real_get_width_for_height;
iface->get_height_for_width = gtk_widget_real_get_height_for_width;
}
GtkAlign
gtk_widget_get_h_align (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
return _gtk_widget_get_aux_info_or_defaults (widget)->h_align;
}
void
gtk_widget_set_h_align (GtkWidget *widget,
GtkAlign align)
{
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
aux_info = _gtk_widget_get_aux_info (widget, TRUE);
if (aux_info->h_align == align)
return;
aux_info->h_align = align;
gtk_widget_queue_resize (widget);
g_object_notify (G_OBJECT (widget), "h-align");
}
GtkAlign
gtk_widget_get_v_align (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_ALIGN_FILL);
return _gtk_widget_get_aux_info_or_defaults (widget)->v_align;
}
void
gtk_widget_set_v_align (GtkWidget *widget,
GtkAlign align)
{
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
aux_info = _gtk_widget_get_aux_info (widget, TRUE);
if (aux_info->v_align == align)
return;
aux_info->v_align = align;
gtk_widget_queue_resize (widget);
g_object_notify (G_OBJECT (widget), "v-align");
}
int
gtk_widget_get_margin_left (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
return _gtk_widget_get_aux_info_or_defaults (widget)->margin.left;
}
void
gtk_widget_set_margin_left (GtkWidget *widget,
int margin)
{
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (margin <= G_MAXINT16);
aux_info = _gtk_widget_get_aux_info (widget, TRUE);
if (aux_info->margin.left == margin)
return;
aux_info->margin.left = margin;
gtk_widget_queue_resize (widget);
g_object_notify (G_OBJECT (widget), "margin-left");
}
int
gtk_widget_get_margin_right (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
return _gtk_widget_get_aux_info_or_defaults (widget)->margin.right;
}
void
gtk_widget_set_margin_right (GtkWidget *widget,
int margin)
{
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (margin <= G_MAXINT16);
aux_info = _gtk_widget_get_aux_info (widget, TRUE);
if (aux_info->margin.right == margin)
return;
aux_info->margin.right = margin;
gtk_widget_queue_resize (widget);
g_object_notify (G_OBJECT (widget), "margin-right");
}
int
gtk_widget_get_margin_top (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
return _gtk_widget_get_aux_info_or_defaults (widget)->margin.top;
}
void
gtk_widget_set_margin_top (GtkWidget *widget,
int margin)
{
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (margin <= G_MAXINT16);
aux_info = _gtk_widget_get_aux_info (widget, TRUE);
if (aux_info->margin.top == margin)
return;
aux_info->margin.top = margin;
gtk_widget_queue_resize (widget);
g_object_notify (G_OBJECT (widget), "margin-top");
}
int
gtk_widget_get_margin_bottom (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
return _gtk_widget_get_aux_info_or_defaults (widget)->margin.bottom;
}
void
gtk_widget_set_margin_bottom (GtkWidget *widget,
int margin)
{
GtkWidgetAuxInfo *aux_info;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (margin <= G_MAXINT16);
aux_info = _gtk_widget_get_aux_info (widget, TRUE);
if (aux_info->margin.bottom == margin)
return;
aux_info->margin.bottom = margin;
gtk_widget_queue_resize (widget);
g_object_notify (G_OBJECT (widget), "margin-bottom");
}
/**
* gtk_widget_get_clipboard:
* @widget: a #GtkWidget

View File

@@ -473,6 +473,15 @@ struct _GtkWidgetClass
gint y,
gboolean keyboard_tooltip,
GtkTooltip *tooltip);
void (* adjust_size_request) (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum_size,
gint *natural_size);
void (* adjust_size_allocation) (GtkWidget *widget,
GtkAllocation *allocation);
/* Signals without a C default handler class slot:
* gboolean (*damage_event) (GtkWidget *widget,
* GdkEventExpose *event);
@@ -493,6 +502,11 @@ struct _GtkWidgetAuxInfo
{
gint width;
gint height;
guint h_align : 4;
guint v_align : 4;
GtkBorder margin;
};
struct _GtkWidgetShapeInfo
@@ -721,6 +735,28 @@ void gtk_widget_set_support_multidevice (GtkWidget *widget,
/* Accessibility support */
AtkObject* gtk_widget_get_accessible (GtkWidget *widget);
/* Margin and alignment */
GtkAlign gtk_widget_get_h_align (GtkWidget *widget);
void gtk_widget_set_h_align (GtkWidget *widget,
GtkAlign align);
GtkAlign gtk_widget_get_v_align (GtkWidget *widget);
void gtk_widget_set_v_align (GtkWidget *widget,
GtkAlign align);
int gtk_widget_get_margin_left (GtkWidget *widget);
void gtk_widget_set_margin_left (GtkWidget *widget,
int margin);
int gtk_widget_get_margin_right (GtkWidget *widget);
void gtk_widget_set_margin_right (GtkWidget *widget,
int margin);
int gtk_widget_get_margin_top (GtkWidget *widget);
void gtk_widget_set_margin_top (GtkWidget *widget,
int margin);
int gtk_widget_get_margin_bottom (GtkWidget *widget);
void gtk_widget_set_margin_bottom (GtkWidget *widget,
int margin);
/* The following functions must not be called on an already
* realized widget. Because it is possible that somebody
* can call get_colormap() or get_visual() and save the

View File

@@ -1527,8 +1527,8 @@ gtk_wrap_box_get_width (GtkSizeRequest *widget,
/* Return the width for the minimum height */
gint min_height;
gtk_size_request_get_height (widget, &min_height, NULL);
gtk_size_request_get_width_for_height (widget, min_height, &min_width, &nat_width);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_height (widget, &min_height, NULL);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width_for_height (widget, min_height, &min_width, &nat_width);
}
@@ -1559,8 +1559,8 @@ gtk_wrap_box_get_height (GtkSizeRequest *widget,
/* Return the height for the minimum width */
gint min_width;
gtk_size_request_get_width (widget, &min_width, NULL);
gtk_size_request_get_height_for_width (widget, min_width, &min_height, &nat_height);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, &min_width, NULL);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_height_for_width (widget, min_width, &min_height, &nat_height);
}
else /* GTK_ORIENTATION_VERTICAL */
{
@@ -1637,7 +1637,7 @@ gtk_wrap_box_get_height_for_width (GtkSizeRequest *widget,
gint min_width;
/* Make sure its no smaller than the minimum */
gtk_size_request_get_width (widget, &min_width, NULL);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, &min_width, NULL);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
@@ -1771,7 +1771,7 @@ gtk_wrap_box_get_height_for_width (GtkSizeRequest *widget,
else /* GTK_ORIENTATION_VERTICAL */
{
/* Return the minimum height */
gtk_size_request_get_height (widget, &min_height, &nat_height);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_height (widget, &min_height, &nat_height);
}
if (minimum_height)
@@ -1803,14 +1803,14 @@ gtk_wrap_box_get_width_for_height (GtkSizeRequest *widget,
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
/* Return the minimum width */
gtk_size_request_get_width (widget, &min_width, &nat_width);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_width (widget, &min_width, &nat_width);
}
else /* GTK_ORIENTATION_VERTICAL */
{
gint min_height;
/* Make sure its no smaller than the minimum */
gtk_size_request_get_height (widget, &min_height, NULL);
GTK_SIZE_REQUEST_GET_IFACE (widget)->get_height (widget, &min_height, NULL);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));

View File

@@ -30,6 +30,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
flicker \
print-editor \
testaccel \
testadjustsize \
testassistant \
testbbox \
testbuttons \
@@ -117,6 +118,7 @@ testicontheme_DEPENDENCIES = $(TEST_DEPS)
testiconview_DEPENDENCIES = $(TEST_DEPS)
testaccel_DEPENDENCIES = $(TEST_DEPS)
testapplication_DEPENDENCIES = $(TEST_DEPS)
testadjustsize_DEPENDENCIES = $(TEST_DEPS)
testassistant_DEPENDENCIES = $(TEST_DEPS)
testbbox_DEPENDENCIES = $(TEST_DEPS)
testbuttons_DEPENDENCIES = $(TEST_DEPS)
@@ -179,6 +181,7 @@ flicker_LDADD = $(LDADDS)
simple_LDADD = $(LDADDS)
print_editor_LDADD = $(LDADDS)
testaccel_LDADD = $(LDADDS)
testadjustsize_LDADD = $(LDADDS)
testapplication_LDADD = $(LDADDS)
testassistant_LDADD = $(LDADDS)
testbbox_LDADD = $(LDADDS)

423
tests/testadjustsize.c Normal file
View File

@@ -0,0 +1,423 @@
/* testadjustsize.c
* Copyright (C) 2010 Havoc Pennington
*
* Author:
* Havoc Pennington <hp@pobox.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>
static GtkWidget *test_window;
enum {
TEST_WIDGET_LABEL,
TEST_WIDGET_VERTICAL_LABEL,
TEST_WIDGET_WRAP_LABEL,
TEST_WIDGET_ALIGNMENT,
TEST_WIDGET_IMAGE,
TEST_WIDGET_BUTTON,
TEST_WIDGET_LAST
};
static GtkWidget *test_widgets[TEST_WIDGET_LAST];
static GtkWidget*
create_image (void)
{
return gtk_image_new_from_stock (GTK_STOCK_OPEN,
GTK_ICON_SIZE_BUTTON);
}
static GtkWidget*
create_label (gboolean vertical,
gboolean wrap)
{
GtkWidget *widget;
widget = gtk_label_new ("This is a label, label label label");
if (vertical)
gtk_label_set_angle (GTK_LABEL (widget), 90);
if (wrap)
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
return widget;
}
static GtkWidget*
create_button (void)
{
return gtk_button_new_with_label ("BUTTON!");
}
static gboolean
on_expose_alignment (GtkWidget *widget,
GdkEventExpose *event,
void *data)
{
cairo_t *cr;
GtkAllocation allocation;
cr = gdk_cairo_create (event->window);
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
gtk_widget_get_allocation (widget, &allocation);
cairo_rectangle (cr,
allocation.x,
allocation.y,
allocation.width,
allocation.height);
cairo_fill (cr);
cairo_destroy (cr);
return FALSE;
}
static GtkWidget*
create_alignment (void)
{
GtkWidget *alignment;
alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
/* make the alignment visible */
gtk_widget_set_redraw_on_allocate (alignment, TRUE);
g_signal_connect (G_OBJECT (alignment),
"expose-event",
G_CALLBACK (on_expose_alignment),
NULL);
return alignment;
}
static void
open_test_window (void)
{
GtkWidget *table;
int i;
test_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (test_window), "Tests");
g_signal_connect (test_window, "delete-event",
G_CALLBACK (gtk_main_quit), test_window);
gtk_window_set_resizable (GTK_WINDOW (test_window), FALSE);
test_widgets[TEST_WIDGET_IMAGE] = create_image ();
test_widgets[TEST_WIDGET_LABEL] = create_label (FALSE, FALSE);
test_widgets[TEST_WIDGET_VERTICAL_LABEL] = create_label (TRUE, FALSE);
test_widgets[TEST_WIDGET_WRAP_LABEL] = create_label (FALSE, TRUE);
test_widgets[TEST_WIDGET_BUTTON] = create_button ();
test_widgets[TEST_WIDGET_ALIGNMENT] = create_alignment ();
table = gtk_table_new (2, 3, FALSE);
gtk_container_add (GTK_CONTAINER (test_window), table);
for (i = 0; i < TEST_WIDGET_LAST; ++i)
{
gtk_table_attach (GTK_TABLE (table),
test_widgets[i],
i % 3,
i % 3 + 1,
i / 3,
i / 3 + 1,
0, 0, 0, 0);
}
gtk_widget_show_all (test_window);
}
static void
on_toggle_border_widths (GtkToggleButton *button,
void *data)
{
gboolean has_border;
int i;
has_border = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
for (i = 0; i < TEST_WIDGET_LAST; ++i)
{
if (GTK_IS_CONTAINER (test_widgets[i]))
{
gtk_container_set_border_width (GTK_CONTAINER (test_widgets[i]),
has_border ? 50 : 0);
}
}
}
static void
on_set_small_size_requests (GtkToggleButton *button,
void *data)
{
gboolean has_small_size_requests;
int i;
has_small_size_requests = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
for (i = 0; i < TEST_WIDGET_LAST; ++i)
{
gtk_widget_set_size_request (test_widgets[i],
has_small_size_requests ? 5 : -1,
has_small_size_requests ? 5 : -1);
}
}
static void
on_set_large_size_requests (GtkToggleButton *button,
void *data)
{
gboolean has_large_size_requests;
int i;
has_large_size_requests = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
for (i = 0; i < TEST_WIDGET_LAST; ++i)
{
gtk_widget_set_size_request (test_widgets[i],
has_large_size_requests ? 200 : -1,
has_large_size_requests ? 200 : -1);
}
}
static void
open_control_window (void)
{
GtkWidget *window;
GtkWidget *box;
GtkWidget *toggle;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Controls");
g_signal_connect (window, "delete-event",
G_CALLBACK (gtk_main_quit), window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box);
toggle =
gtk_toggle_button_new_with_label ("Containers have borders");
g_signal_connect (G_OBJECT (toggle),
"toggled", G_CALLBACK (on_toggle_border_widths),
NULL);
gtk_container_add (GTK_CONTAINER (box), toggle);
toggle =
gtk_toggle_button_new_with_label ("Set small size requests");
g_signal_connect (G_OBJECT (toggle),
"toggled", G_CALLBACK (on_set_small_size_requests),
NULL);
gtk_container_add (GTK_CONTAINER (box), toggle);
toggle =
gtk_toggle_button_new_with_label ("Set large size requests");
g_signal_connect (G_OBJECT (toggle),
"toggled", G_CALLBACK (on_set_large_size_requests),
NULL);
gtk_container_add (GTK_CONTAINER (box), toggle);
gtk_widget_show_all (window);
}
#define TEST_WIDGET(outer) (gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN(outer)))))
static GtkWidget*
create_widget_visible_border (const char *text)
{
GtkWidget *outer_box;
GtkWidget *inner_box;
GtkWidget *test_widget;
GtkWidget *label;
GdkColor color;
outer_box = gtk_event_box_new ();
gdk_color_parse ("black", &color);
gtk_widget_modify_bg (outer_box, GTK_STATE_NORMAL, &color);
inner_box = gtk_event_box_new ();
gtk_container_set_border_width (GTK_CONTAINER (inner_box), 5);
gdk_color_parse ("blue", &color);
gtk_widget_modify_bg (inner_box, GTK_STATE_NORMAL, &color);
gtk_container_add (GTK_CONTAINER (outer_box), inner_box);
test_widget = gtk_event_box_new ();
gdk_color_parse ("red", &color);
gtk_widget_modify_bg (test_widget, GTK_STATE_NORMAL, &color);
gtk_container_add (GTK_CONTAINER (inner_box), test_widget);
label = gtk_label_new (text);
gtk_container_add (GTK_CONTAINER (test_widget), label);
g_assert (TEST_WIDGET (outer_box) == test_widget);
gtk_widget_show_all (outer_box);
return outer_box;
}
static const char*
enum_to_string (GType enum_type,
int value)
{
GEnumValue *v;
v = g_enum_get_value (g_type_class_peek (enum_type), value);
return v->value_nick;
}
static GtkWidget*
create_aligned (GtkAlign h_align,
GtkAlign v_align)
{
GtkWidget *widget;
char *label;
label = g_strdup_printf ("h=%s v=%s",
enum_to_string (GTK_TYPE_ALIGN, h_align),
enum_to_string (GTK_TYPE_ALIGN, v_align));
widget = create_widget_visible_border (label);
g_object_set (G_OBJECT (TEST_WIDGET (widget)),
"h-align", h_align,
"v-align", v_align,
NULL);
return widget;
}
static void
open_alignment_window (void)
{
GtkWidget *table;
int i;
GEnumClass *align_class;
test_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (test_window), "Alignment");
g_signal_connect (test_window, "delete-event",
G_CALLBACK (gtk_main_quit), test_window);
gtk_window_set_resizable (GTK_WINDOW (test_window), TRUE);
gtk_window_set_default_size (GTK_WINDOW (test_window), 500, 500);
align_class = g_type_class_peek (GTK_TYPE_ALIGN);
table = gtk_table_new (align_class->n_values, align_class->n_values, TRUE);
gtk_container_add (GTK_CONTAINER (test_window), table);
for (i = 0; i < align_class->n_values; ++i)
{
int j;
for (j = 0; j < align_class->n_values; ++j)
{
GtkWidget *child =
create_aligned(align_class->values[i].value,
align_class->values[j].value);
gtk_table_attach (GTK_TABLE (table),
child,
i, i + 1,
j, j + 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
}
}
gtk_widget_show_all (test_window);
}
static GtkWidget*
create_margined (const char *propname)
{
GtkWidget *widget;
widget = create_widget_visible_border (propname);
g_object_set (G_OBJECT (TEST_WIDGET (widget)),
propname, 15,
NULL);
return widget;
}
static void
open_margin_window (void)
{
GtkWidget *table;
int i;
const char * margins[] = {
"margin-left",
"margin-right",
"margin-top",
"margin-bottom",
"margin"
};
test_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (test_window), "Margin");
g_signal_connect (test_window, "delete-event",
G_CALLBACK (gtk_main_quit), test_window);
gtk_window_set_resizable (GTK_WINDOW (test_window), TRUE);
table = gtk_table_new (G_N_ELEMENTS (margins), 1, FALSE);
gtk_container_add (GTK_CONTAINER (test_window), table);
for (i = 0; i < (int) G_N_ELEMENTS (margins); ++i)
{
GtkWidget *child =
create_margined(margins[i]);
gtk_table_attach (GTK_TABLE (table),
child,
0, 1,
i, i + 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
}
gtk_widget_show_all (test_window);
}
int
main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
open_test_window ();
open_control_window ();
open_alignment_window ();
open_margin_window ();
gtk_main ();
return 0;
}