API: widget: Add gtk_widget_set_clip() API

And handle the fact that drawing bounds are now handled by this API and
the corresponding gtk_widget_get_clip().

Also add _gtk_widget_supports_clip() function to check if a widget has
been ported to the new world.
This commit is contained in:
Benjamin Otte 2014-05-18 16:02:04 +02:00
parent 1d897a9bf2
commit 4f89eb05cf
4 changed files with 134 additions and 18 deletions

View File

@ -5475,6 +5475,8 @@ gtk_widget_get_allocated_height
gtk_widget_get_allocation
gtk_widget_set_allocation
gtk_widget_get_allocated_baseline
gtk_widget_get_clip
gtk_widget_set_clip
gtk_widget_get_app_paintable
gtk_widget_get_can_default
gtk_widget_set_can_default

View File

@ -439,6 +439,7 @@ struct _GtkWidgetPrivate
guint multidevice : 1;
guint has_shape_mask : 1;
guint in_reparent : 1;
guint supports_clip : 1;
/* Queue-resize related flags */
guint alloc_needed : 1;
@ -485,6 +486,7 @@ struct _GtkWidgetPrivate
/* The widget's allocated size */
GtkAllocation allocation;
gint allocated_baseline;
GtkAllocation clip;
/* The widget's requested sizes */
SizeRequestCache requests;
@ -4539,10 +4541,10 @@ gtk_widget_queue_draw_child (GtkWidget *widget)
parent = priv->parent;
if (parent && gtk_widget_is_drawable (parent))
gtk_widget_queue_draw_area (parent,
priv->allocation.x,
priv->allocation.y,
priv->allocation.width,
priv->allocation.height);
priv->clip.x,
priv->clip.y,
priv->clip.width,
priv->clip.height);
}
/**
@ -4949,7 +4951,7 @@ gtk_widget_map (GtkWidget *widget)
g_signal_emit (widget, widget_signals[MAP], 0);
if (!gtk_widget_get_has_window (widget))
gdk_window_invalidate_rect (priv->window, &priv->allocation, FALSE);
gdk_window_invalidate_rect (priv->window, &priv->clip, FALSE);
if (widget->priv->context)
_gtk_style_context_update_animating (widget->priv->context);
@ -4979,7 +4981,7 @@ gtk_widget_unmap (GtkWidget *widget)
gtk_widget_push_verify_invariants (widget);
if (!gtk_widget_get_has_window (widget))
gdk_window_invalidate_rect (priv->window, &priv->allocation, FALSE);
gdk_window_invalidate_rect (priv->window, &priv->clip, FALSE);
_gtk_tooltip_hide (widget);
if (widget->priv->context)
@ -5588,7 +5590,7 @@ gtk_widget_queue_draw (GtkWidget *widget)
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_widget_get_allocation (widget, &rect);
gtk_widget_get_clip (widget, &rect);
if (!gtk_widget_get_has_window (widget))
gtk_widget_queue_draw_area (widget,
@ -5825,7 +5827,7 @@ gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
{
GtkWidgetPrivate *priv;
GdkRectangle real_allocation;
GdkRectangle old_allocation;
GdkRectangle old_allocation, old_clip;
GdkRectangle adjusted_allocation;
gboolean alloc_needed;
gboolean size_changed;
@ -5882,6 +5884,7 @@ gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
priv->alloc_needed = FALSE;
old_allocation = priv->allocation;
old_clip = priv->clip;
old_baseline = priv->allocated_baseline;
real_allocation = *allocation;
@ -5973,20 +5976,35 @@ gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
if (!alloc_needed && !size_changed && !position_changed && !baseline_changed)
goto out;
memset (&priv->clip, 0, sizeof (priv->clip));
priv->supports_clip = FALSE;
priv->allocated_baseline = baseline;
g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation);
/* Size allocation is god... after consulting god, no further requests or allocations are needed */
priv->alloc_needed = FALSE;
if (priv->supports_clip)
{
size_changed |= (old_clip.width != priv->clip.width ||
old_clip.height != priv->clip.height);
position_changed |= (old_clip.x != priv->clip.x ||
old_clip.y != priv->clip.y);
}
else
{
priv->clip = priv->allocation;
}
if (gtk_widget_get_mapped (widget) && priv->redraw_on_alloc)
{
if (!gtk_widget_get_has_window (widget) && position_changed)
{
/* Invalidate union(old_allaction,priv->allocation) in priv->window
/* Invalidate union(old_clip,priv->clip) in priv->window
*/
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->allocation);
cairo_region_union_rectangle (invalidate, &old_allocation);
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->clip);
cairo_region_union_rectangle (invalidate, &old_clip);
gdk_window_invalidate_region (priv->window, invalidate, FALSE);
cairo_region_destroy (invalidate);
@ -5994,10 +6012,10 @@ gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
if (size_changed || baseline_changed)
{
/* Invalidate union(old_allaction,priv->allocation) in priv->window and descendents owned by widget
/* Invalidate union(old_clip,priv->clip) in priv->window and descendents owned by widget
*/
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->allocation);
cairo_region_union_rectangle (invalidate, &old_allocation);
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->clip);
cairo_region_union_rectangle (invalidate, &old_clip);
gtk_widget_invalidate_widget_windows (widget, invalidate);
cairo_region_destroy (invalidate);
@ -6007,7 +6025,7 @@ gtk_widget_size_allocate_with_baseline (GtkWidget *widget,
if ((size_changed || position_changed || baseline_changed) && priv->parent &&
gtk_widget_get_realized (priv->parent) && _gtk_container_get_reallocate_redraws (GTK_CONTAINER (priv->parent)))
{
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->parent->priv->allocation);
cairo_region_t *invalidate = cairo_region_create_rectangle (&priv->parent->priv->clip);
gtk_widget_invalidate_widget_windows (priv->parent, invalidate);
cairo_region_destroy (invalidate);
}
@ -6843,9 +6861,10 @@ _gtk_widget_draw_internal (GtkWidget *widget,
if (clip_to_size)
{
cairo_rectangle (cr,
0, 0,
widget->priv->allocation.width,
widget->priv->allocation.height);
widget->priv->clip.x - widget->priv->allocation.x,
widget->priv->clip.y - widget->priv->allocation.y,
widget->priv->clip.width,
widget->priv->clip.height);
cairo_clip (cr);
}
@ -8873,6 +8892,7 @@ _gtk_widget_set_visible_flag (GtkWidget *widget,
priv->allocation.y = -1;
priv->allocation.width = 1;
priv->allocation.height = 1;
memset (&priv->clip, 0, sizeof (priv->clip));
}
}
@ -15307,6 +15327,93 @@ gtk_widget_get_has_tooltip (GtkWidget *widget)
return has_tooltip;
}
/**
* gtk_widget_get_clip:
* @widget: a #GtkWidget
* @clip: (out): a pointer to a #GtkAllocation to copy to
*
* Retrieves the widgets clip area.
*
* The clip area is the area in which all of @widget's drawing will
* happen. Other toolkits call it the bounding box.
*
* Historically, in GTK the clip area has been equal to the allocation
* retrieved via gtk_widget_get_allocation().
*
* Since: 3.14
*/
void
gtk_widget_get_clip (GtkWidget *widget,
GtkAllocation *clip)
{
GtkWidgetPrivate *priv;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (clip != NULL);
priv = widget->priv;
*clip = priv->clip;
}
/**
* gtk_widget_set_clip:
* @widget: a #GtkWidget
* @clip: a pointer to a #GtkAllocation to copy from
*
* Sets the widgets clip. This must not be used
* directly, but from within a widgets size_allocate method.
*
* The clip set should be the area that @widget draws on. If @widget is a
* #GtkContainer, the area must contain all children's clips.
*
* If this function is not called by @widget during a size_allocate handler,
* it is assumed to be equal to the allocation. However, if the function is
* not called, certain features that might extend a widget's allocation will
* not be available:
*
* * The GtkWidget::draw signal will be clipped to the widget's allocation
* to avoid overdraw.
* * Calling gtk_render_background() will not draw outset shadows.
*
* It is therefor suggested that you always call gtk_widget_set_clip() during
* a size_allocate handler.
*
* Since: 3.14
*/
void
gtk_widget_set_clip (GtkWidget *widget,
const GtkAllocation *clip)
{
GtkWidgetPrivate *priv;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (gtk_widget_get_visible (widget) || gtk_widget_is_toplevel (widget));
g_return_if_fail (clip != NULL);
priv = widget->priv;
priv->clip = *clip;
priv->supports_clip = TRUE;
}
/**
* _gtk_widget_supports_clip:
* @widget: The #GtkWidget to check
*
* Returns %TRUE if the widget called gtk_widget_set_clip() during
* size allocation. See that function for details.
*
* Returns: %TRUE if the widget handles a clip separate from its allocation.
**/
gboolean
_gtk_widget_supports_clip (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
return widget->priv->supports_clip;
}
/**
* gtk_widget_get_allocation:
* @widget: a #GtkWidget

View File

@ -945,6 +945,12 @@ void gtk_widget_get_allocation (GtkWidget *widget,
GDK_AVAILABLE_IN_ALL
void gtk_widget_set_allocation (GtkWidget *widget,
const GtkAllocation *allocation);
GDK_AVAILABLE_IN_3_14
void gtk_widget_set_clip (GtkWidget *widget,
const GtkAllocation *allocation);
GDK_AVAILABLE_IN_3_14
void gtk_widget_get_clip (GtkWidget *widget,
GtkAllocation *allocation);
GDK_DEPRECATED_IN_3_0_FOR(gtk_widget_get_preferred_width & gtk_widget_get_preferred_height)

View File

@ -133,6 +133,7 @@ void _gtk_widget_buildable_finish_accelerator (GtkWidget *widget,
GtkStyle * _gtk_widget_get_style (GtkWidget *widget);
void _gtk_widget_set_style (GtkWidget *widget,
GtkStyle *style);
gboolean _gtk_widget_supports_clip (GtkWidget *widget);
typedef gboolean (*GtkCapturedEventHandler) (GtkWidget *widget, GdkEvent *event);