From 4f89eb05cf8a09a1ce1de4870fdc4395645a0bdf Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 18 May 2014 16:02:04 +0200 Subject: [PATCH] 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. --- docs/reference/gtk/gtk3-sections.txt | 2 + gtk/gtkwidget.c | 143 +++++++++++++++++++++++---- gtk/gtkwidget.h | 6 ++ gtk/gtkwidgetprivate.h | 1 + 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index 53b94611b6..13cd553dbc 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -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 diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 4326bf6c9c..acb7316517 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -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 widget’s 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 widget’s clip. This must not be used + * directly, but from within a widget’s 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 diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 089420a873..152f6dde05 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -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) diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index dad9b6fd3c..8f2a9d5ecc 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -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);