diff options
author | Matthias Clasen <mclasen@redhat.com> | 2019-02-15 16:12:26 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2019-02-15 16:12:26 +0000 |
commit | bea1a02edd161658f96f63c12694a8b3acce9c93 (patch) | |
tree | 91b9008dea6090023a370e8ef88ad7acc344e74a | |
parent | 74d6d81db920d4c03a609a0eb2fbc35395e18e28 (diff) | |
parent | c44c44ee2510415c3b796e973ac3f525e5d512b9 (diff) | |
download | gtk+-bea1a02edd161658f96f63c12694a8b3acce9c93.tar.gz |
Merge branch 'wip/otte/boxes' into 'master'
GtkCssBoxes
See merge request GNOME/gtk!584
32 files changed, 1255 insertions, 583 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index fd48280bed..b6fc344d36 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -751,7 +751,6 @@ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID gtk_container_add gtk_container_remove gtk_container_add_with_properties -gtk_container_check_resize gtk_container_foreach gtk_container_get_children gtk_container_get_path_for_child diff --git a/gtk/a11y/gtkentryaccessible.c b/gtk/a11y/gtkentryaccessible.c index f8aaabad87..3b8bcf3b23 100644 --- a/gtk/a11y/gtkentryaccessible.c +++ b/gtk/a11y/gtkentryaccessible.c @@ -961,7 +961,7 @@ gtk_entry_accessible_get_character_extents (AtkText *text, pango_layout_index_to_pos (gtk_entry_get_layout (entry), index, &char_rect); pango_extents_to_pixels (&char_rect, NULL); - _gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (widget, &allocation); surface = gtk_widget_get_surface (widget); gdk_surface_get_origin (surface, &x_surface, &y_surface); @@ -176,6 +176,7 @@ #include <gtk/gtkrecentmanager.h> #include <gtk/gtkrender.h> #include <gtk/gtkrevealer.h> +#include <gtk/gtkroot.h> #include <gtk/gtkscale.h> #include <gtk/gtkscalebutton.h> #include <gtk/gtkscrollable.h> diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 58085d3135..f1ef23e8e4 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -34,12 +34,11 @@ #include "gtkpopovermenu.h" #include "gtkprivate.h" #include "gtkmarshalers.h" -#include "gtkshortcutssection.h" -#include "gtkshortcutswindow.h" #include "gtksizerequest.h" #include "gtkstylecontextprivate.h" #include "gtktypebuiltins.h" #include "gtkwidgetprivate.h" +#include "gtkwindowprivate.h" #include "a11y/gtkcontaineraccessibleprivate.h" @@ -129,7 +128,6 @@ struct _GtkContainerPrivate enum { ADD, REMOVE, - CHECK_RESIZE, SET_FOCUS_CHILD, LAST_SIGNAL }; @@ -148,7 +146,6 @@ static void gtk_container_add_unimplemented (GtkContainer *container GtkWidget *widget); static void gtk_container_remove_unimplemented (GtkContainer *container, GtkWidget *widget); -static void gtk_container_real_check_resize (GtkContainer *container); static void gtk_container_compute_expand (GtkWidget *widget, gboolean *hexpand_p, gboolean *vexpand_p); @@ -284,7 +281,6 @@ gtk_container_class_init (GtkContainerClass *class) class->add = gtk_container_add_unimplemented; class->remove = gtk_container_remove_unimplemented; - class->check_resize = gtk_container_real_check_resize; class->forall = NULL; class->set_focus_child = gtk_container_real_set_focus_child; class->child_type = NULL; @@ -308,14 +304,6 @@ gtk_container_class_init (GtkContainerClass *class) NULL, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); - container_signals[CHECK_RESIZE] = - g_signal_new (I_("check-resize"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkContainerClass, check_resize), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); container_signals[SET_FOCUS_CHILD] = g_signal_new (I_("set-focus-child"), G_OBJECT_CLASS_TYPE (gobject_class), @@ -1397,7 +1385,10 @@ gtk_container_idle_sizer (GdkFrameClock *clock, */ if (gtk_widget_needs_allocate (GTK_WIDGET (container))) { - gtk_container_check_resize (container); + if (GTK_IS_WINDOW (container)) + gtk_window_check_resize (GTK_WINDOW (container)); + else + g_warning ("gtk_container_idle_sizer() called on a non-window"); } if (!gtk_container_needs_idle_sizer (container)) @@ -1460,44 +1451,6 @@ _gtk_container_queue_restyle (GtkContainer *container) gtk_container_start_idle_sizer (container); } -void -gtk_container_check_resize (GtkContainer *container) -{ - g_return_if_fail (GTK_IS_CONTAINER (container)); - - g_signal_emit (container, container_signals[CHECK_RESIZE], 0); -} - -static void -gtk_container_real_check_resize (GtkContainer *container) -{ - GtkWidget *widget = GTK_WIDGET (container); - GtkAllocation allocation; - GtkRequisition requisition; - int baseline; - - if (_gtk_widget_get_alloc_needed (widget)) - { - if (!_gtk_widget_is_toplevel (widget)) - { - gtk_widget_get_preferred_size (widget, &requisition, NULL); - gtk_widget_get_allocated_size (widget, &allocation, &baseline); - - if (allocation.width < requisition.width) - allocation.width = requisition.width; - if (allocation.height < requisition.height) - allocation.height = requisition.height; - gtk_widget_size_allocate (widget, &allocation, baseline); - } - else - gtk_widget_queue_resize (widget); - } - else - { - gtk_widget_ensure_allocate (widget); - } -} - static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget *widget) { diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h index 8f07f97408..4e2aa50aec 100644 --- a/gtk/gtkcontainer.h +++ b/gtk/gtkcontainer.h @@ -56,7 +56,6 @@ struct _GtkContainer * @parent_class: The parent class. * @add: Signal emitted when a widget is added to container. * @remove: Signal emitted when a widget is removed from container. - * @check_resize: Signal emitted when a size recalculation is needed. * @forall: Invokes callback on each child of container. The callback handler * may remove the child. * @set_focus_child: Sets the focused child of container. @@ -78,7 +77,6 @@ struct _GtkContainerClass GtkWidget *widget); void (*remove) (GtkContainer *container, GtkWidget *widget); - void (*check_resize) (GtkContainer *container); void (*forall) (GtkContainer *container, GtkCallback callback, gpointer callback_data); @@ -126,9 +124,6 @@ void gtk_container_remove (GtkContainer *container, GtkWidget *widget); GDK_AVAILABLE_IN_ALL -void gtk_container_check_resize (GtkContainer *container); - -GDK_AVAILABLE_IN_ALL void gtk_container_foreach (GtkContainer *container, GtkCallback callback, gpointer callback_data); diff --git a/gtk/gtkcssboxesimplprivate.h b/gtk/gtkcssboxesimplprivate.h new file mode 100644 index 0000000000..98c1b71e0d --- /dev/null +++ b/gtk/gtkcssboxesimplprivate.h @@ -0,0 +1,495 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2019 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GTK_CSS_BOXES_IMPL_PRIVATE_H__ +#define __GTK_CSS_BOXES_IMPL_PRIVATE_H__ + +#include "gtkcssboxesprivate.h" + +#include "gtkcsscornervalueprivate.h" +#include "gtkcssnodeprivate.h" +#include "gtkcssnumbervalueprivate.h" +#include "gtkwidgetprivate.h" + +/* This file is included from gtkcssboxesprivate.h */ + +static inline void +gtk_css_boxes_init (GtkCssBoxes *boxes, + GtkWidget *widget) +{ + GtkWidgetPrivate *priv = widget->priv; + + gtk_css_boxes_init_content_box (boxes, + gtk_css_node_get_style (priv->cssnode), + 0, 0, + priv->width, + priv->height); +} + +static inline void +gtk_css_boxes_init_content_box (GtkCssBoxes *boxes, + GtkCssStyle *style, + double x, + double y, + double width, + double height) +{ + memset (boxes, 0, sizeof (GtkCssBoxes)); + + boxes->style = style; + boxes->box[GTK_CSS_AREA_CONTENT_BOX].bounds = GRAPHENE_RECT_INIT (x, y, width, height); + boxes->has_rect[GTK_CSS_AREA_CONTENT_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_init_border_box (GtkCssBoxes *boxes, + GtkCssStyle *style, + double x, + double y, + double width, + double height) +{ + memset (boxes, 0, sizeof (GtkCssBoxes)); + + boxes->style = style; + boxes->box[GTK_CSS_AREA_BORDER_BOX].bounds = GRAPHENE_RECT_INIT (x, y, width, height); + boxes->has_rect[GTK_CSS_AREA_BORDER_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_rect_grow (GskRoundedRect *dest, + GskRoundedRect *src, + GtkCssStyle *style, + int top_property, + int right_property, + int bottom_property, + int left_property) +{ + double top = _gtk_css_number_value_get (gtk_css_style_get_value (style, top_property), 100); + double right = _gtk_css_number_value_get (gtk_css_style_get_value (style, right_property), 100); + double bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, bottom_property), 100); + double left = _gtk_css_number_value_get (gtk_css_style_get_value (style, left_property), 100); + + dest->bounds.origin.x = src->bounds.origin.x - left; + dest->bounds.origin.y = src->bounds.origin.y - top; + dest->bounds.size.width = src->bounds.size.width + left + right; + dest->bounds.size.height = src->bounds.size.height + top + bottom; +} + +static inline void +gtk_css_boxes_rect_shrink (GskRoundedRect *dest, + GskRoundedRect *src, + GtkCssStyle *style, + int top_property, + int right_property, + int bottom_property, + int left_property) +{ + double top = _gtk_css_number_value_get (gtk_css_style_get_value (style, top_property), 100); + double right = _gtk_css_number_value_get (gtk_css_style_get_value (style, right_property), 100); + double bottom = _gtk_css_number_value_get (gtk_css_style_get_value (style, bottom_property), 100); + double left = _gtk_css_number_value_get (gtk_css_style_get_value (style, left_property), 100); + + /* FIXME: Do we need underflow checks here? */ + dest->bounds.origin.x = src->bounds.origin.x + left; + dest->bounds.origin.y = src->bounds.origin.y + top; + dest->bounds.size.width = src->bounds.size.width - left - right; + dest->bounds.size.height = src->bounds.size.height - top - bottom; +} + +static inline void gtk_css_boxes_compute_padding_rect (GtkCssBoxes *boxes); + +static inline const graphene_rect_t * +gtk_css_boxes_get_rect (GtkCssBoxes *boxes, + GtkCssArea area) +{ + switch (area) + { + case GTK_CSS_AREA_BORDER_BOX: + return gtk_css_boxes_get_border_rect (boxes); + case GTK_CSS_AREA_PADDING_BOX: + return gtk_css_boxes_get_padding_rect (boxes); + case GTK_CSS_AREA_CONTENT_BOX: + return gtk_css_boxes_get_content_rect (boxes); + default: + g_assert_not_reached (); + return NULL; + } +} + +static inline void +gtk_css_boxes_compute_border_rect (GtkCssBoxes *boxes) +{ + if (boxes->has_rect[GTK_CSS_AREA_BORDER_BOX]) + return; + + gtk_css_boxes_compute_padding_rect (boxes); + + gtk_css_boxes_rect_grow (&boxes->box[GTK_CSS_AREA_BORDER_BOX], + &boxes->box[GTK_CSS_AREA_PADDING_BOX], + boxes->style, + GTK_CSS_PROPERTY_BORDER_TOP_WIDTH, + GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH, + GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH, + GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH); + + boxes->has_rect[GTK_CSS_AREA_BORDER_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_padding_rect (GtkCssBoxes *boxes) +{ + if (boxes->has_rect[GTK_CSS_AREA_PADDING_BOX]) + return; + + if (boxes->has_rect[GTK_CSS_AREA_BORDER_BOX]) + { + gtk_css_boxes_rect_shrink (&boxes->box[GTK_CSS_AREA_PADDING_BOX], + &boxes->box[GTK_CSS_AREA_BORDER_BOX], + boxes->style, + GTK_CSS_PROPERTY_BORDER_TOP_WIDTH, + GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH, + GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH, + GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH); + } + else + { + gtk_css_boxes_rect_grow (&boxes->box[GTK_CSS_AREA_PADDING_BOX], + &boxes->box[GTK_CSS_AREA_CONTENT_BOX], + boxes->style, + GTK_CSS_PROPERTY_PADDING_TOP, + GTK_CSS_PROPERTY_PADDING_RIGHT, + GTK_CSS_PROPERTY_PADDING_BOTTOM, + GTK_CSS_PROPERTY_PADDING_LEFT); + } + + boxes->has_rect[GTK_CSS_AREA_PADDING_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_content_rect (GtkCssBoxes *boxes) +{ + if (boxes->has_rect[GTK_CSS_AREA_CONTENT_BOX]) + return; + + gtk_css_boxes_compute_padding_rect (boxes); + + gtk_css_boxes_rect_shrink (&boxes->box[GTK_CSS_AREA_CONTENT_BOX], + &boxes->box[GTK_CSS_AREA_PADDING_BOX], + boxes->style, + GTK_CSS_PROPERTY_PADDING_TOP, + GTK_CSS_PROPERTY_PADDING_RIGHT, + GTK_CSS_PROPERTY_PADDING_BOTTOM, + GTK_CSS_PROPERTY_PADDING_LEFT); + + boxes->has_rect[GTK_CSS_AREA_CONTENT_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_margin_rect (GtkCssBoxes *boxes) +{ + if (boxes->has_rect[GTK_CSS_AREA_MARGIN_BOX]) + return; + + gtk_css_boxes_compute_border_rect (boxes); + + gtk_css_boxes_rect_grow (&boxes->box[GTK_CSS_AREA_MARGIN_BOX], + &boxes->box[GTK_CSS_AREA_BORDER_BOX], + boxes->style, + GTK_CSS_PROPERTY_MARGIN_TOP, + GTK_CSS_PROPERTY_MARGIN_RIGHT, + GTK_CSS_PROPERTY_MARGIN_BOTTOM, + GTK_CSS_PROPERTY_MARGIN_LEFT); + + boxes->has_rect[GTK_CSS_AREA_MARGIN_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_outline_rect (GtkCssBoxes *boxes) +{ + graphene_rect_t *dest, *src; + double d; + + if (boxes->has_rect[GTK_CSS_AREA_OUTLINE_BOX]) + return; + + gtk_css_boxes_compute_border_rect (boxes); + + dest = &boxes->box[GTK_CSS_AREA_OUTLINE_BOX].bounds; + src = &boxes->box[GTK_CSS_AREA_BORDER_BOX].bounds; + + d = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 100) + + _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); + + dest->origin.x = src->origin.x - d; + dest->origin.y = src->origin.y - d; + dest->size.width = src->size.width + d + d; + dest->size.height = src->size.height + d + d; + + boxes->has_rect[GTK_CSS_AREA_OUTLINE_BOX] = TRUE; +} + +static inline const graphene_rect_t * +gtk_css_boxes_get_margin_rect (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_margin_rect (boxes); + + return &boxes->box[GTK_CSS_AREA_MARGIN_BOX].bounds; +} + +static inline const graphene_rect_t * +gtk_css_boxes_get_border_rect (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_border_rect (boxes); + + return &boxes->box[GTK_CSS_AREA_BORDER_BOX].bounds; +} + +static inline const graphene_rect_t * +gtk_css_boxes_get_padding_rect (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_padding_rect (boxes); + + return &boxes->box[GTK_CSS_AREA_PADDING_BOX].bounds; +} + +static inline const graphene_rect_t * +gtk_css_boxes_get_content_rect (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_content_rect (boxes); + + return &boxes->box[GTK_CSS_AREA_CONTENT_BOX].bounds; +} + +static inline const graphene_rect_t * +gtk_css_boxes_get_outline_rect (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_outline_rect (boxes); + + return &boxes->box[GTK_CSS_AREA_OUTLINE_BOX].bounds; +} + +/* clamp border radius, following CSS specs */ +static inline void +gtk_css_boxes_clamp_border_radius (GskRoundedRect *box) +{ + gdouble factor = 1.0; + gdouble corners; + + corners = box->corner[GSK_CORNER_TOP_LEFT].width + box->corner[GSK_CORNER_TOP_RIGHT].width; + if (corners != 0) + factor = MIN (factor, box->bounds.size.width / corners); + + corners = box->corner[GSK_CORNER_TOP_RIGHT].height + box->corner[GSK_CORNER_BOTTOM_RIGHT].height; + if (corners != 0) + factor = MIN (factor, box->bounds.size.height / corners); + + corners = box->corner[GSK_CORNER_BOTTOM_RIGHT].width + box->corner[GSK_CORNER_BOTTOM_LEFT].width; + if (corners != 0) + factor = MIN (factor, box->bounds.size.width / corners); + + corners = box->corner[GSK_CORNER_TOP_LEFT].height + box->corner[GSK_CORNER_BOTTOM_LEFT].height; + if (corners != 0) + factor = MIN (factor, box->bounds.size.height / corners); + + box->corner[GSK_CORNER_TOP_LEFT].width *= factor; + box->corner[GSK_CORNER_TOP_LEFT].height *= factor; + box->corner[GSK_CORNER_TOP_RIGHT].width *= factor; + box->corner[GSK_CORNER_TOP_RIGHT].height *= factor; + box->corner[GSK_CORNER_BOTTOM_RIGHT].width *= factor; + box->corner[GSK_CORNER_BOTTOM_RIGHT].height *= factor; + box->corner[GSK_CORNER_BOTTOM_LEFT].width *= factor; + box->corner[GSK_CORNER_BOTTOM_LEFT].height *= factor; +} + +static inline void +gtk_css_boxes_apply_border_radius (GskRoundedRect *box, + const GtkCssValue *top_left, + const GtkCssValue *top_right, + const GtkCssValue *bottom_right, + const GtkCssValue *bottom_left) +{ + box->corner[GSK_CORNER_TOP_LEFT].width = _gtk_css_corner_value_get_x (top_left, box->bounds.size.width); + box->corner[GSK_CORNER_TOP_LEFT].height = _gtk_css_corner_value_get_y (top_left, box->bounds.size.height); + + box->corner[GSK_CORNER_TOP_RIGHT].width = _gtk_css_corner_value_get_x (top_right, box->bounds.size.width); + box->corner[GSK_CORNER_TOP_RIGHT].height = _gtk_css_corner_value_get_y (top_right, box->bounds.size.height); + + box->corner[GSK_CORNER_BOTTOM_RIGHT].width = _gtk_css_corner_value_get_x (bottom_right, box->bounds.size.width); + box->corner[GSK_CORNER_BOTTOM_RIGHT].height = _gtk_css_corner_value_get_y (bottom_right, box->bounds.size.height); + + box->corner[GSK_CORNER_BOTTOM_LEFT].width = _gtk_css_corner_value_get_x (bottom_left, box->bounds.size.width); + box->corner[GSK_CORNER_BOTTOM_LEFT].height = _gtk_css_corner_value_get_y (bottom_left, box->bounds.size.height); + + gtk_css_boxes_clamp_border_radius (box); +} + +/* NB: width and height must be >= 0 */ +static inline void +gtk_css_boxes_shrink_border_radius (graphene_size_t *dest, + const graphene_size_t *src, + double width, + double height) +{ + dest->width = src->width - width; + dest->height = src->height - height; + + if (dest->width <= 0 || dest->height <= 0) + { + dest->width = 0; + dest->height = 0; + } +} + +static inline void +gtk_css_boxes_shrink_corners (GskRoundedRect *dest, + const GskRoundedRect *src) +{ + double top = dest->bounds.origin.y - src->bounds.origin.y; + double right = src->bounds.origin.x + src->bounds.size.width - dest->bounds.origin.x - dest->bounds.size.width; + double bottom = src->bounds.origin.y + src->bounds.size.height - dest->bounds.origin.y - dest->bounds.size.height; + double left = dest->bounds.origin.x - src->bounds.origin.x; + + gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_TOP_LEFT], + &src->corner[GSK_CORNER_TOP_LEFT], + top, left); + gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_TOP_RIGHT], + &src->corner[GSK_CORNER_TOP_RIGHT], + top, right); + gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_BOTTOM_RIGHT], + &src->corner[GSK_CORNER_BOTTOM_RIGHT], + bottom, right); + gtk_css_boxes_shrink_border_radius (&dest->corner[GSK_CORNER_BOTTOM_LEFT], + &src->corner[GSK_CORNER_BOTTOM_LEFT], + bottom, left); +} + +static inline void +gtk_css_boxes_compute_border_box (GtkCssBoxes *boxes) +{ + if (boxes->has_box[GTK_CSS_AREA_BORDER_BOX]) + return; + + gtk_css_boxes_compute_border_rect (boxes); + + gtk_css_boxes_apply_border_radius (&boxes->box[GTK_CSS_AREA_BORDER_BOX], + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS), + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS), + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS), + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS)); + + boxes->has_box[GTK_CSS_AREA_BORDER_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_padding_box (GtkCssBoxes *boxes) +{ + if (boxes->has_box[GTK_CSS_AREA_PADDING_BOX]) + return; + + gtk_css_boxes_compute_border_box (boxes); + gtk_css_boxes_compute_padding_rect (boxes); + + gtk_css_boxes_shrink_corners (&boxes->box[GTK_CSS_AREA_PADDING_BOX], + &boxes->box[GTK_CSS_AREA_BORDER_BOX]); + + boxes->has_box[GTK_CSS_AREA_PADDING_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_content_box (GtkCssBoxes *boxes) +{ + if (boxes->has_box[GTK_CSS_AREA_CONTENT_BOX]) + return; + + gtk_css_boxes_compute_padding_box (boxes); + gtk_css_boxes_compute_content_rect (boxes); + + gtk_css_boxes_shrink_corners (&boxes->box[GTK_CSS_AREA_CONTENT_BOX], + &boxes->box[GTK_CSS_AREA_PADDING_BOX]); + + boxes->has_box[GTK_CSS_AREA_CONTENT_BOX] = TRUE; +} + +static inline void +gtk_css_boxes_compute_outline_box (GtkCssBoxes *boxes) +{ + if (boxes->has_box[GTK_CSS_AREA_OUTLINE_BOX]) + return; + + gtk_css_boxes_compute_outline_rect (boxes); + + gtk_css_boxes_apply_border_radius (&boxes->box[GTK_CSS_AREA_OUTLINE_BOX], + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_TOP_LEFT_RADIUS), + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_TOP_RIGHT_RADIUS), + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_BOTTOM_RIGHT_RADIUS), + gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_BOTTOM_LEFT_RADIUS)); + + boxes->has_box[GTK_CSS_AREA_OUTLINE_BOX] = TRUE; +} + +static inline const GskRoundedRect * +gtk_css_boxes_get_box (GtkCssBoxes *boxes, + GtkCssArea area) +{ + switch (area) + { + case GTK_CSS_AREA_BORDER_BOX: + return gtk_css_boxes_get_border_box (boxes); + case GTK_CSS_AREA_PADDING_BOX: + return gtk_css_boxes_get_padding_box (boxes); + case GTK_CSS_AREA_CONTENT_BOX: + return gtk_css_boxes_get_content_box (boxes); + default: + g_assert_not_reached (); + return NULL; + } +} + +static inline const GskRoundedRect * +gtk_css_boxes_get_border_box (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_border_box (boxes); + + return &boxes->box[GTK_CSS_AREA_BORDER_BOX]; +} + +static inline const GskRoundedRect * +gtk_css_boxes_get_padding_box (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_padding_box (boxes); + + return &boxes->box[GTK_CSS_AREA_PADDING_BOX]; +} + +static inline const GskRoundedRect * +gtk_css_boxes_get_content_box (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_content_box (boxes); + + return &boxes->box[GTK_CSS_AREA_CONTENT_BOX]; +} + +static inline const GskRoundedRect * +gtk_css_boxes_get_outline_box (GtkCssBoxes *boxes) +{ + gtk_css_boxes_compute_outline_box (boxes); + + return &boxes->box[GTK_CSS_AREA_OUTLINE_BOX]; +} + +#endif /* __GTK_CSS_BOXES_IMPL_PRIVATE_H__ */ diff --git a/gtk/gtkcssboxesprivate.h b/gtk/gtkcssboxesprivate.h new file mode 100644 index 0000000000..d90ba1e598 --- /dev/null +++ b/gtk/gtkcssboxesprivate.h @@ -0,0 +1,91 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2019 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GTK_CSS_BOXES_PRIVATE_H__ +#define __GTK_CSS_BOXES_PRIVATE_H__ + +#include "gtkcsstypesprivate.h" + +G_BEGIN_DECLS + +/* + * The idea behind this file is that it provides an on-stack representation + * for all the CSS boxes one can have to deal with in the CSS box model so that + * higher level code can use convenient and readable function calls instead of + * doing complicated math. + * + * However, because computing all those rectangles is prohibitively expensive, + * this struct does it lazily. + * And then we inline all the code, so that whenever we use this struct, the + * compiler can optimize out the parts we don't need in that particular use + * case. + */ + +typedef struct _GtkCssBoxes GtkCssBoxes; + +/* ahem... + * Let's extend GtkCssArea a bit here. */ +#define GTK_CSS_AREA_MARGIN_BOX (3) +#define GTK_CSS_AREA_OUTLINE_BOX (4) +#define GTK_CSS_AREA_N_BOXES (5) + + +struct _GtkCssBoxes +{ + GtkCssStyle *style; + GskRoundedRect box[GTK_CSS_AREA_N_BOXES]; + gboolean has_rect[GTK_CSS_AREA_N_BOXES]; /* TRUE if we have initialized just the bounds rect */ + gboolean has_box[GTK_CSS_AREA_N_BOXES]; /* TRUE if we have initialized the whole box */ +}; + +static inline void gtk_css_boxes_init (GtkCssBoxes *boxes, + GtkWidget *widget); +static inline void gtk_css_boxes_init_content_box (GtkCssBoxes *boxes, + GtkCssStyle *style, + double x, + double y, + double width, + double height); +static inline void gtk_css_boxes_init_border_box (GtkCssBoxes *boxes, + GtkCssStyle *style, + double x, + double y, + double width, + double height); + +static inline const graphene_rect_t * gtk_css_boxes_get_rect (GtkCssBoxes *boxes, + GtkCssArea area); +static inline const graphene_rect_t * gtk_css_boxes_get_margin_rect (GtkCssBoxes *boxes); +static inline const graphene_rect_t * gtk_css_boxes_get_border_rect (GtkCssBoxes *boxes); +static inline const graphene_rect_t * gtk_css_boxes_get_padding_rect (GtkCssBoxes *boxes); +static inline const graphene_rect_t * gtk_css_boxes_get_content_rect (GtkCssBoxes *boxes); +static inline const graphene_rect_t * gtk_css_boxes_get_outline_rect (GtkCssBoxes *boxes); + +static inline const GskRoundedRect * gtk_css_boxes_get_box (GtkCssBoxes *boxes, + GtkCssArea area); +static inline const GskRoundedRect * gtk_css_boxes_get_border_box (GtkCssBoxes *boxes); +static inline const GskRoundedRect * gtk_css_boxes_get_padding_box (GtkCssBoxes *boxes); +static inline const GskRoundedRect * gtk_css_boxes_get_content_box (GtkCssBoxes *boxes); +static inline const GskRoundedRect * gtk_css_boxes_get_outline_box (GtkCssBoxes *boxes); + +G_END_DECLS + +#endif /* __GTK_CSS_BOXES_PRIVATE_H__ */ + +/* and finally include the actual code for the functions */ +#include "gtkcssboxesimplprivate.h" + diff --git a/gtk/gtkcssnodeprivate.h b/gtk/gtkcssnodeprivate.h index 8c71733192..7335fb30da 100644 --- a/gtk/gtkcssnodeprivate.h +++ b/gtk/gtkcssnodeprivate.h @@ -106,28 +106,28 @@ void gtk_css_node_insert_before (GtkCssNode * GtkCssNode *cssnode, GtkCssNode *next_sibling); -GtkCssNode * gtk_css_node_get_parent (GtkCssNode *cssnode); -GtkCssNode * gtk_css_node_get_first_child (GtkCssNode *cssnode); -GtkCssNode * gtk_css_node_get_last_child (GtkCssNode *cssnode); -GtkCssNode * gtk_css_node_get_previous_sibling(GtkCssNode *cssnode); -GtkCssNode * gtk_css_node_get_next_sibling (GtkCssNode *cssnode); +GtkCssNode * gtk_css_node_get_parent (GtkCssNode *cssnode) G_GNUC_PURE; +GtkCssNode * gtk_css_node_get_first_child (GtkCssNode *cssnode) G_GNUC_PURE; +GtkCssNode * gtk_css_node_get_last_child (GtkCssNode *cssnode) G_GNUC_PURE; +GtkCssNode * gtk_css_node_get_previous_sibling(GtkCssNode *cssnode) G_GNUC_PURE; +GtkCssNode * gtk_css_node_get_next_sibling (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_set_visible (GtkCssNode *cssnode, gboolean visible); -gboolean gtk_css_node_get_visible (GtkCssNode *cssnode); +gboolean gtk_css_node_get_visible (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_set_name (GtkCssNode *cssnode, /*interned*/const char*name); -/*interned*/const char *gtk_css_node_get_name (GtkCssNode *cssnode); +/*interned*/const char *gtk_css_node_get_name (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_set_widget_type (GtkCssNode *cssnode, GType widget_type); -GType gtk_css_node_get_widget_type (GtkCssNode *cssnode); +GType gtk_css_node_get_widget_type (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_set_id (GtkCssNode *cssnode, /*interned*/const char*id); -/*interned*/const char *gtk_css_node_get_id (GtkCssNode *cssnode); +/*interned*/const char *gtk_css_node_get_id (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_set_state (GtkCssNode *cssnode, GtkStateFlags state_flags); -GtkStateFlags gtk_css_node_get_state (GtkCssNode *cssnode); +GtkStateFlags gtk_css_node_get_state (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_set_classes (GtkCssNode *cssnode, const char **classes); char ** gtk_css_node_get_classes (GtkCssNode *cssnode); @@ -136,13 +136,13 @@ void gtk_css_node_add_class (GtkCssNode * void gtk_css_node_remove_class (GtkCssNode *cssnode, GQuark style_class); gboolean gtk_css_node_has_class (GtkCssNode *cssnode, - GQuark style_class); + GQuark style_class) G_GNUC_PURE; const GQuark * gtk_css_node_list_classes (GtkCssNode *cssnode, guint *n_classes); const GtkCssNodeDeclaration * - gtk_css_node_get_declaration (GtkCssNode *cssnode); -GtkCssStyle * gtk_css_node_get_style (GtkCssNode *cssnode); + gtk_css_node_get_declaration (GtkCssNode *cssnode) G_GNUC_PURE; +GtkCssStyle * gtk_css_node_get_style (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_invalidate_style_provider @@ -157,8 +157,8 @@ void gtk_css_node_validate (GtkCssNode * gboolean gtk_css_node_init_matcher (GtkCssNode *cssnode, GtkCssMatcher *matcher); GtkWidgetPath * gtk_css_node_create_widget_path (GtkCssNode *cssnode); -const GtkWidgetPath * gtk_css_node_get_widget_path (GtkCssNode *cssnode); -GtkStyleProvider * gtk_css_node_get_style_provider (GtkCssNode *cssnode); +const GtkWidgetPath * gtk_css_node_get_widget_path (GtkCssNode *cssnode) G_GNUC_PURE; +GtkStyleProvider * gtk_css_node_get_style_provider (GtkCssNode *cssnode) G_GNUC_PURE; void gtk_css_node_print (GtkCssNode *cssnode, GtkStyleContextPrintFlags flags, diff --git a/gtk/gtkcssnumbervalueprivate.h b/gtk/gtkcssnumbervalueprivate.h index 3ea9af6b7b..faf7dad5c9 100644 --- a/gtk/gtkcssnumbervalueprivate.h +++ b/gtk/gtkcssnumbervalueprivate.h @@ -61,8 +61,8 @@ gboolean gtk_css_number_value_can_parse (GtkCssParser *par GtkCssValue * _gtk_css_number_value_parse (GtkCssParser *parser, GtkCssNumberParseFlags flags); -GtkCssDimension gtk_css_number_value_get_dimension (const GtkCssValue *value); -gboolean gtk_css_number_value_has_percent (const GtkCssValue *value); +GtkCssDimension gtk_css_number_value_get_dimension (const GtkCssValue *value) G_GNUC_PURE; +gboolean gtk_css_number_value_has_percent (const GtkCssValue *value) G_GNUC_PURE; GtkCssValue * gtk_css_number_value_multiply (const GtkCssValue *value, double factor); GtkCssValue * gtk_css_number_value_add (GtkCssValue *value1, @@ -72,7 +72,7 @@ GtkCssValue * gtk_css_number_value_try_add (const GtkCssValue *val gint gtk_css_number_value_get_calc_term_order (const GtkCssValue *value); double _gtk_css_number_value_get (const GtkCssValue *number, - double one_hundred_percent); + double one_hundred_percent) G_GNUC_PURE; G_END_DECLS diff --git a/gtk/gtkcssrgbavalueprivate.h b/gtk/gtkcssrgbavalueprivate.h index 4a2909dde4..60a0cffd6f 100644 --- a/gtk/gtkcssrgbavalueprivate.h +++ b/gtk/gtkcssrgbavalueprivate.h @@ -28,7 +28,7 @@ G_BEGIN_DECLS GtkCssValue * _gtk_css_rgba_value_new_from_rgba (const GdkRGBA *rgba); -const GdkRGBA * _gtk_css_rgba_value_get_rgba (const GtkCssValue *rgba); +const GdkRGBA * _gtk_css_rgba_value_get_rgba (const GtkCssValue *rgba) G_GNUC_PURE; G_END_DECLS diff --git a/gtk/gtkcssstyleprivate.h b/gtk/gtkcssstyleprivate.h index 536b4b8a23..a17dc4203f 100644 --- a/gtk/gtkcssstyleprivate.h +++ b/gtk/gtkcssstyleprivate.h @@ -61,13 +61,13 @@ struct _GtkCssStyleClass GType gtk_css_style_get_type (void) G_GNUC_CONST; GtkCssValue * gtk_css_style_get_value (GtkCssStyle *style, - guint id); + guint id) G_GNUC_PURE; GtkCssSection * gtk_css_style_get_section (GtkCssStyle *style, - guint id); + guint id) G_GNUC_PURE; GtkBitmask * gtk_css_style_add_difference (GtkBitmask *accumulated, GtkCssStyle *style, GtkCssStyle *other); -gboolean gtk_css_style_is_static (GtkCssStyle *style); +gboolean gtk_css_style_is_static (GtkCssStyle *style) G_GNUC_PURE; char * gtk_css_style_to_string (GtkCssStyle *style); gboolean gtk_css_style_print (GtkCssStyle *style, diff --git a/gtk/gtkinvisible.c b/gtk/gtkinvisible.c index 37821039a6..9b66f3a9c8 100644 --- a/gtk/gtkinvisible.c +++ b/gtk/gtkinvisible.c @@ -23,11 +23,13 @@ */ #include "config.h" -#include <gdk/gdk.h> + #include "gtkinvisibleprivate.h" -#include "gtkwidgetprivate.h" -#include "gtkprivate.h" + #include "gtkintl.h" +#include "gtkprivate.h" +#include "gtkroot.h" +#include "gtkwidgetprivate.h" /** @@ -69,7 +71,24 @@ static void gtk_invisible_get_property (GObject *object, GParamSpec *pspec); static void gtk_invisible_constructed (GObject *object); -G_DEFINE_TYPE_WITH_PRIVATE (GtkInvisible, gtk_invisible, GTK_TYPE_WIDGET) +static GdkDisplay * +gtk_invisible_root_get_display (GtkRoot *root) +{ + GtkInvisible *invisible = GTK_INVISIBLE (root); + + return invisible->priv->display; +} + +static void +gtk_invisible_root_interface_init (GtkRootInterface *iface) +{ + iface->get_display = gtk_invisible_root_get_display; +} + +G_DEFINE_TYPE_WITH_CODE (GtkInvisible, gtk_invisible, GTK_TYPE_WIDGET, + G_ADD_PRIVATE (GtkInvisible) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ROOT, + gtk_invisible_root_interface_init)) static void gtk_invisible_class_init (GtkInvisibleClass *class) @@ -107,7 +126,6 @@ gtk_invisible_init (GtkInvisible *invisible) priv = invisible->priv; gtk_widget_set_has_surface (GTK_WIDGET (invisible), TRUE); - _gtk_widget_set_is_toplevel (GTK_WIDGET (invisible), TRUE); g_object_ref_sink (invisible); @@ -201,22 +219,6 @@ gtk_invisible_set_display (GtkInvisible *invisible, gtk_widget_realize (widget); } -/** - * gtk_invisible_get_display: - * @invisible: a #GtkInvisible. - * - * Returns the #GdkDisplay object associated with @invisible - * - * Returns: (transfer none): the associated #GdkDisplay. - **/ -GdkDisplay * -gtk_invisible_get_display (GtkInvisible *invisible) -{ - g_return_val_if_fail (GTK_IS_INVISIBLE (invisible), NULL); - - return invisible->priv->display; -} - static void gtk_invisible_realize (GtkWidget *widget) { diff --git a/gtk/gtkinvisibleprivate.h b/gtk/gtkinvisibleprivate.h index f625a35684..c65053bca0 100644 --- a/gtk/gtkinvisibleprivate.h +++ b/gtk/gtkinvisibleprivate.h @@ -74,8 +74,6 @@ GtkWidget* gtk_invisible_new_for_display(GdkDisplay *display); GDK_AVAILABLE_IN_ALL void gtk_invisible_set_display (GtkInvisible *invisible, GdkDisplay *display); -GDK_AVAILABLE_IN_ALL -GdkDisplay*gtk_invisible_get_display (GtkInvisible *invisible); G_END_DECLS diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c index ac18261c71..4f21c1f17f 100644 --- a/gtk/gtkprintoperation-win32.c +++ b/gtk/gtkprintoperation-win32.c @@ -1382,8 +1382,6 @@ pageDlgProc (HWND wnd, UINT message, WPARAM wparam, LPARAM lparam) SetWindowLongPtrW (wnd, GWLP_USERDATA, (LONG_PTR)op); - _gtk_widget_set_is_toplevel (plug, TRUE); - gtk_window_set_modal (GTK_WINDOW (plug), TRUE); op_win32->embed_widget = plug; gtk_container_add (GTK_CONTAINER (plug), op->priv->custom_widget); diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c index 0be739f679..32e0305cab 100644 --- a/gtk/gtkrenderbackground.c +++ b/gtk/gtkrenderbackground.c @@ -25,6 +25,7 @@ #include "gtkcssarrayvalueprivate.h" #include "gtkcssbgsizevalueprivate.h" +#include "gtkcssboxesprivate.h" #include "gtkcsscornervalueprivate.h" #include "gtkcssenumvalueprivate.h" #include "gtkcssimagevalueprivate.h" @@ -47,49 +48,43 @@ */ #include "fallback-c89.c" -typedef struct _GtkThemingBackground GtkThemingBackground; - -#define N_BOXES (3) - -struct _GtkThemingBackground { - GtkCssStyle *style; - - GskRoundedRect boxes[N_BOXES]; -}; - static void -gtk_theming_background_snapshot_color (const GtkThemingBackground *bg, - GtkSnapshot *snapshot, - const GdkRGBA *bg_color, - const GtkCssValue *background_image) +gtk_theming_background_snapshot_color (GtkCssBoxes *boxes, + GtkSnapshot *snapshot, + const GdkRGBA *bg_color, + const GtkCssValue *background_image) { - gint n_values = _gtk_css_array_value_get_n_values (background_image); - GtkCssArea clip = _gtk_css_area_value_get + const GskRoundedRect *box; + gint n_values; + GtkCssArea clip; + + n_values = _gtk_css_array_value_get_n_values (background_image); + clip = _gtk_css_area_value_get (_gtk_css_array_value_get_nth - (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), + (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), n_values - 1)); + box = gtk_css_boxes_get_box (boxes, clip); - if (gsk_rounded_rect_is_rectilinear (&bg->boxes[clip])) + if (gsk_rounded_rect_is_rectilinear (box)) { gtk_snapshot_append_color (snapshot, bg_color, - &bg->boxes[clip].bounds); + &box->bounds); } else { - gtk_snapshot_push_rounded_clip (snapshot, - &bg->boxes[clip]); + gtk_snapshot_push_rounded_clip (snapshot, box); gtk_snapshot_append_color (snapshot, bg_color, - &bg->boxes[clip].bounds); + &box->bounds); gtk_snapshot_pop (snapshot); } } static void -gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg, - guint idx, - GtkSnapshot *snapshot) +gtk_theming_background_snapshot_layer (GtkCssBoxes *bg, + guint idx, + GtkSnapshot *snapshot) { GtkCssRepeatStyle hrepeat, vrepeat; const GtkCssValue *pos, *repeat; @@ -112,11 +107,11 @@ gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg, vrepeat = _gtk_css_background_repeat_value_get_y (repeat); - origin = &bg->boxes[ - _gtk_css_area_value_get ( - _gtk_css_array_value_get_nth ( - gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_ORIGIN), - idx))]; + origin = gtk_css_boxes_get_box (bg, + _gtk_css_area_value_get ( + _gtk_css_array_value_get_nth ( + gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_ORIGIN), + idx))); width = origin->bounds.size.width; height = origin->bounds.size.height; @@ -124,11 +119,11 @@ gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg, if (width <= 0 || height <= 0) return; - clip = &bg->boxes[ - _gtk_css_area_value_get ( - _gtk_css_array_value_get_nth ( - gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), - idx))]; + clip = gtk_css_boxes_get_box (bg, + _gtk_css_area_value_get ( + _gtk_css_array_value_get_nth ( + gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_CLIP), + idx))); _gtk_css_bg_size_value_compute_size (_gtk_css_array_value_get_nth (gtk_css_style_get_value (bg->style, GTK_CSS_PROPERTY_BACKGROUND_SIZE), idx), image, @@ -274,28 +269,10 @@ gtk_theming_background_snapshot_layer (const GtkThemingBackground *bg, gtk_snapshot_pop (snapshot); } -static void -gtk_theming_background_init (GtkThemingBackground *bg, - GtkCssStyle *style, - double width, - double height) -{ - bg->style = style; - - gtk_rounded_boxes_init_for_style (&bg->boxes[GTK_CSS_AREA_BORDER_BOX], - &bg->boxes[GTK_CSS_AREA_PADDING_BOX], - &bg->boxes[GTK_CSS_AREA_CONTENT_BOX], - style, - 0, 0, width, height); -} - void -gtk_css_style_snapshot_background (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height) +gtk_css_style_snapshot_background (GtkCssBoxes *boxes, + GtkSnapshot *snapshot) { - GtkThemingBackground bg; gint idx; GtkCssValue *background_image; GtkCssValue *box_shadow; @@ -304,9 +281,9 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, gint number_of_layers; GskBlendMode *blend_mode_values; - background_image = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE); - bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); - box_shadow = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BOX_SHADOW); + background_image = gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BACKGROUND_IMAGE); + bg_color = _gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); + box_shadow = gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BOX_SHADOW); /* This is the common default case of no background */ if (gdk_rgba_is_clear (bg_color) && @@ -315,15 +292,13 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, _gtk_css_shadows_value_is_none (box_shadow)) return; - gtk_theming_background_init (&bg, style, width, height); - gtk_snapshot_push_debug (snapshot, "CSS background"); gtk_css_shadows_value_snapshot_outset (box_shadow, snapshot, - &bg.boxes[GTK_CSS_AREA_BORDER_BOX]); + gtk_css_boxes_get_border_box (boxes)); - blend_modes = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE); + blend_modes = gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE); number_of_layers = _gtk_css_array_value_get_n_values (background_image); blend_mode_values = g_alloca (sizeof (GskBlendMode) * number_of_layers); @@ -336,25 +311,25 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, } if (!gdk_rgba_is_clear (bg_color)) - gtk_theming_background_snapshot_color (&bg, snapshot, bg_color, background_image); + gtk_theming_background_snapshot_color (boxes, snapshot, bg_color, background_image); for (idx = number_of_layers - 1; idx >= 0; idx--) { if (blend_mode_values[idx] == GSK_BLEND_MODE_DEFAULT) { - gtk_theming_background_snapshot_layer (&bg, idx, snapshot); + gtk_theming_background_snapshot_layer (boxes, idx, snapshot); } else { gtk_snapshot_pop (snapshot); - gtk_theming_background_snapshot_layer (&bg, idx, snapshot); + gtk_theming_background_snapshot_layer (boxes, idx, snapshot); gtk_snapshot_pop (snapshot); } } gtk_css_shadows_value_snapshot_inset (box_shadow, snapshot, - &bg.boxes[GTK_CSS_AREA_PADDING_BOX]); + gtk_css_boxes_get_padding_box (boxes)); gtk_snapshot_pop (snapshot); } diff --git a/gtk/gtkrenderbackgroundprivate.h b/gtk/gtkrenderbackgroundprivate.h index a812b3ef7a..43aaf17580 100644 --- a/gtk/gtkrenderbackgroundprivate.h +++ b/gtk/gtkrenderbackgroundprivate.h @@ -24,14 +24,13 @@ #include <cairo.h> #include "gtkcsstypesprivate.h" +#include "gtkcssboxesprivate.h" #include "gtktypes.h" G_BEGIN_DECLS -void gtk_css_style_snapshot_background (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height); +void gtk_css_style_snapshot_background (GtkCssBoxes *boxes, + GtkSnapshot *snapshot); diff --git a/gtk/gtkrenderborder.c b/gtk/gtkrenderborder.c index 1c568532ce..08a05f692f 100644 --- a/gtk/gtkrenderborder.c +++ b/gtk/gtkrenderborder.c @@ -251,13 +251,10 @@ gtk_border_image_compute_slice_size (GtkBorderImageSliceSize sizes[3], } static void -gtk_border_image_render (GtkBorderImage *image, - const double border_width[4], - cairo_t *cr, - gdouble x, - gdouble y, - gdouble width, - gdouble height) +gtk_border_image_render (GtkBorderImage *image, + const float border_width[4], + cairo_t *cr, + const graphene_rect_t *rect) { cairo_surface_t *surface, *slice; GtkBorderImageSliceSize vertical_slice[3], horizontal_slice[3]; @@ -267,7 +264,7 @@ gtk_border_image_render (GtkBorderImage *image, _gtk_css_image_get_concrete_size (image->source, 0, 0, - width, height, + rect->size.width, rect->size.height, &source_width, &source_height); /* XXX: Optimize for (source_width == width && source_height == height) */ @@ -285,15 +282,15 @@ gtk_border_image_render (GtkBorderImage *image, _gtk_css_number_value_get (_gtk_css_border_value_get_top (image->slice), source_height), _gtk_css_number_value_get (_gtk_css_border_value_get_bottom (image->slice), source_height)); gtk_border_image_compute_border_size (horizontal_border, - x, - width, + rect->origin.x, + rect->size.width, border_width[GTK_CSS_LEFT], border_width[GTK_CSS_RIGHT], _gtk_css_border_value_get_left (image->width), _gtk_css_border_value_get_right (image->width)); gtk_border_image_compute_border_size (vertical_border, - y, - height, + rect->origin.y, + rect->size.height, border_width[GTK_CSS_TOP], border_width[GTK_CSS_BOTTOM], _gtk_css_border_value_get_top (image->width), @@ -423,12 +420,12 @@ set_stroke_style (cairo_t *cr, } static void -render_frame_stroke (cairo_t *cr, - GskRoundedRect *border_box, - const double border_width[4], - GdkRGBA colors[4], - guint hidden_side, - GtkBorderStyle stroke_style) +render_frame_stroke (cairo_t *cr, + const GskRoundedRect *border_box, + const double border_width[4], + GdkRGBA colors[4], + guint hidden_side, + GtkBorderStyle stroke_style) { gboolean different_colors, different_borders; GskRoundedRect stroke_box; @@ -510,12 +507,12 @@ render_frame_stroke (cairo_t *cr, } static void -snapshot_frame_stroke (GtkSnapshot *snapshot, - GskRoundedRect *outline, - const float border_width[4], - GdkRGBA colors[4], - guint hidden_side, - GtkBorderStyle stroke_style) +snapshot_frame_stroke (GtkSnapshot *snapshot, + const GskRoundedRect *outline, + const float border_width[4], + GdkRGBA colors[4], + guint hidden_side, + GtkBorderStyle stroke_style) { double double_width[4] = { border_width[0], border_width[1], border_width[2], border_width[3] }; cairo_t *cr; @@ -539,11 +536,11 @@ color_shade (const GdkRGBA *color, } static void -snapshot_border (GtkSnapshot *snapshot, - GskRoundedRect *border_box, - const float border_width[4], - GdkRGBA colors[4], - GtkBorderStyle border_style[4]) +snapshot_border (GtkSnapshot *snapshot, + const GskRoundedRect *border_box, + const float border_width[4], + GdkRGBA colors[4], + GtkBorderStyle border_style[4]) { guint hidden_side = 0; guint i, j; @@ -661,136 +658,86 @@ snapshot_border (GtkSnapshot *snapshot, } void -gtk_css_style_snapshot_border (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height) +gtk_css_style_snapshot_border (GtkCssBoxes *boxes, + GtkSnapshot *snapshot) { GtkBorderImage border_image; float border_width[4]; - border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); - border_width[1] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); - border_width[2] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); - border_width[3] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); + border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100); + border_width[1] = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100); + border_width[2] = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100); + border_width[3] = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100); - if (gtk_border_image_init (&border_image, style)) + if (gtk_border_image_init (&border_image, boxes->style)) { cairo_t *cr; - graphene_rect_t bounds; - double double_width[4] = { border_width[0], border_width[1], border_width[2], border_width[3] }; + const graphene_rect_t *bounds; - graphene_rect_init (&bounds, 0, 0, width, height); + bounds = gtk_css_boxes_get_border_rect (boxes); gtk_snapshot_push_debug (snapshot, "CSS border image"); - cr = gtk_snapshot_append_cairo (snapshot, - &bounds); - gtk_border_image_render (&border_image, double_width, cr, 0, 0, width, height); + cr = gtk_snapshot_append_cairo (snapshot, bounds); + gtk_border_image_render (&border_image, border_width, cr, bounds); cairo_destroy (cr); gtk_snapshot_pop (snapshot); } else { GtkBorderStyle border_style[4]; - GskRoundedRect border_box; GdkRGBA colors[4]; graphene_simd4f_t alpha_test_vector; /* Optimize the most common case of "This widget has no border" */ - if (border_width[0] == 0 && - border_width[1] == 0 && - border_width[2] == 0 && - border_width[3] == 0) + if (graphene_rect_equal (gtk_css_boxes_get_border_rect (boxes), + gtk_css_boxes_get_padding_rect (boxes))) return; - colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_COLOR)); - colors[1] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR)); - colors[2] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR)); - colors[3] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_COLOR)); + colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_TOP_COLOR)); + colors[1] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR)); + colors[2] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR)); + colors[3] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_LEFT_COLOR)); alpha_test_vector = graphene_simd4f_init (colors[0].alpha, colors[1].alpha, colors[2].alpha, colors[3].alpha); if (graphene_simd4f_is_zero4 (alpha_test_vector)) return; - border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_TOP_STYLE)); - border_style[1] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE)); - border_style[2] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE)); - border_style[3] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_BORDER_LEFT_STYLE)); - - gtk_rounded_boxes_init_for_style (&border_box, NULL, NULL, style, 0, 0, width, height); + border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_TOP_STYLE)); + border_style[1] = _gtk_css_border_style_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE)); + border_style[2] = _gtk_css_border_style_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE)); + border_style[3] = _gtk_css_border_style_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_BORDER_LEFT_STYLE)); gtk_snapshot_push_debug (snapshot, "CSS border"); - snapshot_border (snapshot, &border_box, border_width, colors, border_style); + snapshot_border (snapshot, + gtk_css_boxes_get_border_box (boxes), + border_width, + colors, + border_style); gtk_snapshot_pop (snapshot); } } -static void -compute_outline_rect (GtkCssStyle *style, - gdouble x, - gdouble y, - gdouble width, - gdouble height, - cairo_rectangle_t *out_rect) -{ - double offset, owidth; - - owidth = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); - offset = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 100); - - if (width <= -2 * offset) - { - x += width / 2; - out_rect->x = x - owidth; - out_rect->width = 2 * owidth; - } - else - { - out_rect->x = x - offset - owidth; - out_rect->width = width + 2 * (offset + owidth); - } - - if (height <= -2 * offset) - { - y += height / 2; - out_rect->y = y - owidth; - out_rect->height = 2 * owidth; - } - else - { - out_rect->y = y - offset - owidth; - out_rect->height = height + 2 * (offset + owidth); - } - -} - void -gtk_css_style_snapshot_outline (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height) +gtk_css_style_snapshot_outline (GtkCssBoxes *boxes, + GtkSnapshot *snapshot) { GtkBorderStyle border_style[4]; - GskRoundedRect border_box; float border_width[4]; GdkRGBA colors[4]; - border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_STYLE)); + border_style[0] = _gtk_css_border_style_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_STYLE)); if (border_style[0] != GTK_BORDER_STYLE_NONE) { - cairo_rectangle_t rect; - - compute_outline_rect (style, 0, 0, width, height, &rect); - border_style[1] = border_style[2] = border_style[3] = border_style[0]; - border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); + border_width[0] = _gtk_css_number_value_get (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100); border_width[3] = border_width[2] = border_width[1] = border_width[0]; - colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_OUTLINE_COLOR)); + colors[0] = *_gtk_css_rgba_value_get_rgba (gtk_css_style_get_value (boxes->style, GTK_CSS_PROPERTY_OUTLINE_COLOR)); colors[3] = colors[2] = colors[1] = colors[0]; - _gtk_rounded_box_init_rect (&border_box, rect.x, rect.y, rect.width, rect.height); - _gtk_rounded_box_apply_outline_radius_for_style (&border_box, style); - - snapshot_border (snapshot, &border_box, border_width, colors, border_style); + snapshot_border (snapshot, + gtk_css_boxes_get_outline_box (boxes), + border_width, + colors, + border_style); } } diff --git a/gtk/gtkrenderborderprivate.h b/gtk/gtkrenderborderprivate.h index 60cb7a016e..ded54fbd71 100644 --- a/gtk/gtkrenderborderprivate.h +++ b/gtk/gtkrenderborderprivate.h @@ -23,21 +23,16 @@ #define __GTK_RENDER_BORDER_H__ #include "gtkborder.h" -#include "gtkcssimageprivate.h" -#include "gtkcssvalueprivate.h" +#include "gtkcssboxesprivate.h" #include "gtktypes.h" G_BEGIN_DECLS -void gtk_css_style_snapshot_border (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height); +void gtk_css_style_snapshot_border (GtkCssBoxes *boxes, + GtkSnapshot *snapshot); -void gtk_css_style_snapshot_outline (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height); +void gtk_css_style_snapshot_outline (GtkCssBoxes *boxes, + GtkSnapshot *snapshot); G_END_DECLS diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c new file mode 100644 index 0000000000..1907786e95 --- /dev/null +++ b/gtk/gtkroot.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#include "config.h" + +#include "gtkrootprivate.h" + +/** + * SECTION:root + * @Title: GtkRoot + * @Short_description: Root widgets + * @See_also: #GtkWindow + * + * #GtkRoot is the interface implemented by all widgets that can act as a toplevel + * widget to a hierarchy of widgets. The root widget takes care of providing the + * connection to the windowing system and manages layout, drawing and event delivery + * for its widget hierarchy. + * + * The obvious example of a #GtkRoot is #GtkWindow. + */ + +G_DEFINE_INTERFACE (GtkRoot, gtk_root, GTK_TYPE_WIDGET) + +static GdkDisplay * +gtk_root_default_get_display (GtkRoot *self) +{ + return gdk_display_get_default (); +} + +static GskRenderer * +gtk_root_default_get_renderer (GtkRoot *self) +{ + return NULL; +} + +static void +gtk_root_default_get_surface_transform (GtkRoot *self, + int *x, + int *y) +{ + *x = 0; + *y = 0; +} + +static void +gtk_root_default_init (GtkRootInterface *iface) +{ + iface->get_display = gtk_root_default_get_display; + iface->get_renderer = gtk_root_default_get_renderer; + iface->get_surface_transform = gtk_root_default_get_surface_transform; +} + +GdkDisplay * +gtk_root_get_display (GtkRoot *self) +{ + GtkRootInterface *iface; + + g_return_val_if_fail (GTK_IS_ROOT (self), NULL); + + iface = GTK_ROOT_GET_IFACE (self); + return iface->get_display (self); +} + +GskRenderer * +gtk_root_get_renderer (GtkRoot *self) +{ + GtkRootInterface *iface; + + g_return_val_if_fail (GTK_IS_ROOT (self), NULL); + + iface = GTK_ROOT_GET_IFACE (self); + return iface->get_renderer (self); +} + +void +gtk_root_get_surface_transform (GtkRoot *self, + int *x, + int *y) +{ + GtkRootInterface *iface; + + g_return_if_fail (GTK_IS_ROOT (self)); + g_return_if_fail (x != 0); + g_return_if_fail (y != 0); + + iface = GTK_ROOT_GET_IFACE (self); + return iface->get_surface_transform (self, x, y); +} diff --git a/gtk/gtkroot.h b/gtk/gtkroot.h new file mode 100644 index 0000000000..e3494fcc7a --- /dev/null +++ b/gtk/gtkroot.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2018 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#ifndef __GTK_ROOT_H__ +#define __GTK_ROOT_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gdk/gdk.h> +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_ROOT (gtk_root_get_type ()) + +GDK_AVAILABLE_IN_ALL +G_DECLARE_INTERFACE (GtkRoot, gtk_root, GTK, ROOT, GtkWidget) + +/** + * GtkRootIface: + * + * The list of functions that must be implemented for the #GtkRoot interface. + */ +struct _GtkRootInterface +{ + /*< private >*/ + GTypeInterface g_iface; + + /*< public >*/ + GdkDisplay * (* get_display) (GtkRoot *self); + GskRenderer * (* get_renderer) (GtkRoot *self); + + void (* get_surface_transform) (GtkRoot *root, + int *x, + int *y); +}; + + +G_END_DECLS + +#endif /* __GTK_ROOT_H__ */ diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h new file mode 100644 index 0000000000..07ddc380e5 --- /dev/null +++ b/gtk/gtkrootprivate.h @@ -0,0 +1,16 @@ +#ifndef __GTK_ROOT_PRIVATE_H__ +#define __GTK_ROOT_PRIVATE_H__ + +#include "gtkroot.h" + +G_BEGIN_DECLS + +GdkDisplay * gtk_root_get_display (GtkRoot *root); +GskRenderer * gtk_root_get_renderer (GtkRoot *self); + +void gtk_root_get_surface_transform (GtkRoot *self, + int *x, + int *y); +G_END_DECLS + +#endif /* __GTK_ROOT_PRIVATE_H__ */ diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 7eb12dd33e..3f7f100608 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -1263,14 +1263,15 @@ gtk_snapshot_render_background (GtkSnapshot *snapshot, gdouble width, gdouble height) { + GtkCssBoxes boxes; + g_return_if_fail (snapshot != NULL); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - gtk_snapshot_offset (snapshot, x, y); - gtk_css_style_snapshot_background (gtk_style_context_lookup_style (context), - snapshot, - width, height); - gtk_snapshot_offset (snapshot, -x, -y); + gtk_css_boxes_init_border_box (&boxes, + gtk_style_context_lookup_style (context), + x, y, width, height); + gtk_css_style_snapshot_background (&boxes, snapshot); } /** @@ -1294,14 +1295,15 @@ gtk_snapshot_render_frame (GtkSnapshot *snapshot, gdouble width, gdouble height) { + GtkCssBoxes boxes; + g_return_if_fail (snapshot != NULL); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - gtk_snapshot_offset (snapshot, x, y); - gtk_css_style_snapshot_border (gtk_style_context_lookup_style (context), - snapshot, - width, height); - gtk_snapshot_offset (snapshot, -x, -y); + gtk_css_boxes_init_border_box (&boxes, + gtk_style_context_lookup_style (context), + x, y, width, height); + gtk_css_style_snapshot_border (&boxes, snapshot); } /** @@ -1325,14 +1327,15 @@ gtk_snapshot_render_focus (GtkSnapshot *snapshot, gdouble width, gdouble height) { + GtkCssBoxes boxes; + g_return_if_fail (snapshot != NULL); g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - gtk_snapshot_offset (snapshot, x, y); - gtk_css_style_snapshot_outline (gtk_style_context_lookup_style (context), - snapshot, - width, height); - gtk_snapshot_offset (snapshot, -x, -y); + gtk_css_boxes_init_border_box (&boxes, + gtk_style_context_lookup_style (context), + x, y, width, height); + gtk_css_style_snapshot_outline (&boxes, snapshot); } /** diff --git a/gtk/gtktypes.h b/gtk/gtktypes.h index fc58058821..5d1218f189 100644 --- a/gtk/gtktypes.h +++ b/gtk/gtktypes.h @@ -39,6 +39,7 @@ typedef struct _GtkClipboard GtkClipboard; typedef struct _GtkEventController GtkEventController; typedef struct _GtkGesture GtkGesture; typedef struct _GtkRequisition GtkRequisition; +typedef struct _GtkRoot GtkRoot; typedef struct _GtkSelectionData GtkSelectionData; typedef struct _GtkSettings GtkSettings; typedef GdkSnapshot GtkSnapshot; diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 9207a46b1d..6f871e9ab0 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -34,6 +34,7 @@ #include "gtkbuildable.h" #include "gtkbuilderprivate.h" #include "gtkcontainerprivate.h" +#include "gtkcssboxesprivate.h" #include "gtkcssfiltervalueprivate.h" #include "gtkcssfontvariationsvalueprivate.h" #include "gtkcssnumbervalueprivate.h" @@ -507,6 +508,7 @@ enum { PROP_0, PROP_NAME, PROP_PARENT, + PROP_ROOT, PROP_WIDTH_REQUEST, PROP_HEIGHT_REQUEST, PROP_VISIBLE, @@ -602,6 +604,8 @@ static void gtk_widget_real_move_focus (GtkWidget GtkDirectionType direction); static gboolean gtk_widget_real_keynav_failed (GtkWidget *widget, GtkDirectionType direction); +static void gtk_widget_root (GtkWidget *widget); +static void gtk_widget_unroot (GtkWidget *widget); #ifdef G_ENABLE_CONSISTENCY_CHECKS static void gtk_widget_verify_invariants (GtkWidget *widget); static void gtk_widget_push_verify_invariants (GtkWidget *widget); @@ -854,6 +858,18 @@ gtk_widget_real_grab_notify (GtkWidget *widget, } static void +gtk_widget_real_root (GtkWidget *widget) +{ + gtk_widget_forall (widget, (GtkCallback) gtk_widget_root, NULL); +} + +static void +gtk_widget_real_unroot (GtkWidget *widget) +{ + gtk_widget_forall (widget, (GtkCallback) gtk_widget_unroot, NULL); +} + +static void gtk_widget_class_init (GtkWidgetClass *klass) { static GObjectNotifyContext cpn_context = { 0, NULL, NULL }; @@ -899,6 +915,8 @@ gtk_widget_class_init (GtkWidgetClass *klass) klass->unmap = gtk_widget_real_unmap; klass->realize = gtk_widget_real_realize; klass->unrealize = gtk_widget_real_unrealize; + klass->root = gtk_widget_real_root; + klass->unroot = gtk_widget_real_unroot; klass->size_allocate = gtk_widget_real_size_allocate; klass->get_request_mode = gtk_widget_real_get_request_mode; klass->measure = gtk_widget_real_measure; @@ -948,6 +966,19 @@ gtk_widget_class_init (GtkWidgetClass *klass) GTK_TYPE_WIDGET, GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY); + /** + * GtkWidget:root: + * + * The #GtkRoot widget of the widget tree containing this widget or %NULL if + * the widget is not contained in a root widget. + */ + widget_props[PROP_ROOT] = + g_param_spec_object ("root", + P_("Root widget"), + P_("The root widget in the widget tree."), + GTK_TYPE_ROOT, + GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY); + widget_props[PROP_WIDTH_REQUEST] = g_param_spec_int ("width-request", P_("Width request"), @@ -2368,6 +2399,9 @@ gtk_widget_get_property (GObject *object, case PROP_PARENT: g_value_set_object (value, priv->parent); break; + case PROP_ROOT: + g_value_set_object (value, priv->root); + break; case PROP_WIDTH_REQUEST: { int w; @@ -2810,10 +2844,6 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class) priv->visible = gtk_widget_class_get_visible_by_default (g_class); priv->child_visible = TRUE; priv->name = NULL; - priv->allocation.x = -1; - priv->allocation.y = -1; - priv->allocation.width = 0; - priv->allocation.height = 0; priv->user_alpha = 255; priv->alpha = 255; priv->surface = NULL; @@ -2822,7 +2852,7 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class) priv->last_child = NULL; priv->prev_sibling = NULL; priv->next_sibling = NULL; - priv->allocated_baseline = -1; + priv->baseline = -1; priv->allocated_size_baseline = -1; priv->sensitive = TRUE; @@ -2872,6 +2902,9 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class) gtk_css_node_set_visible (priv->cssnode, priv->visible); /* need to set correct type here, and only class has the correct type here */ gtk_css_node_set_widget_type (priv->cssnode, G_TYPE_FROM_CLASS (g_class)); + + if (g_type_is_a (G_TYPE_FROM_CLASS (g_class), GTK_TYPE_ROOT)) + priv->root = (GtkRoot *) widget; } @@ -2999,6 +3032,46 @@ gtk_widget_new (GType type, return widget; } +static void +gtk_widget_root (GtkWidget *widget) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + /* roots are rooted by default */ + if (GTK_IS_ROOT (widget)) + return; + + g_assert (priv->root == NULL); + g_assert (!priv->realized); + g_assert (priv->parent); + g_assert (priv->parent->priv->root); + + priv->root = priv->parent->priv->root; + + GTK_WIDGET_GET_CLASS (widget)->root (widget); + + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_ROOT]); +} + +static void +gtk_widget_unroot (GtkWidget *widget) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + /* roots are rooted by default and cannot be unrooted */ + if (GTK_IS_ROOT (widget)) + return; + + g_assert (priv->root); + g_assert (!priv->realized); + + GTK_WIDGET_GET_CLASS (widget)->unroot (widget); + + priv->root = NULL; + + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_ROOT]); +} + /** * gtk_widget_unparent: * @widget: a #GtkWidget @@ -3044,12 +3117,15 @@ gtk_widget_unparent (GtkWidget *widget) /* Reset the width and height here, to force reallocation if we * get added back to a new parent. */ - priv->allocation.width = 0; - priv->allocation.height = 0; + priv->width = 0; + priv->height = 0; if (_gtk_widget_get_realized (widget)) gtk_widget_unrealize (widget); + if (priv->root) + gtk_widget_unroot (widget); + /* If we are unanchoring the child, we save around the toplevel * to emit hierarchy changed */ @@ -3107,10 +3183,9 @@ gtk_widget_unparent (GtkWidget *widget) gtk_list_list_model_item_removed (old_parent->priv->children_observer, old_prev_sibling); if (toplevel) - { - _gtk_widget_propagate_hierarchy_changed (widget, toplevel); - g_object_unref (toplevel); - } + _gtk_widget_propagate_hierarchy_changed (widget, toplevel); + + g_clear_object (&toplevel); /* Now that the parent pointer is nullified and the hierarchy-changed * already passed, go ahead and unset the parent window, if we are unparenting @@ -4145,6 +4220,12 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation = *allocation; + baseline_changed = priv->allocated_size_baseline != baseline; + size_changed = (priv->allocated_size.width != real_allocation.width || + priv->allocated_size.height != real_allocation.height); + position_changed = (priv->allocated_size.x != real_allocation.x || + priv->allocated_size.y != real_allocation.y); + priv->allocated_size = *allocation; priv->allocated_size_baseline = baseline; @@ -4233,16 +4314,6 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation.height = MAX (1, real_allocation.height); } - baseline_changed = priv->allocated_baseline != baseline; - size_changed = (priv->allocation.width != real_allocation.width || - priv->allocation.height != real_allocation.height); - position_changed = (priv->allocation.x != real_allocation.x || - priv->allocation.y != real_allocation.y); - - /* Set the widget allocation to real_allocation now, pass the smaller allocation to the vfunc */ - priv->allocation = real_allocation; - priv->allocated_baseline = baseline; - if (!alloc_needed && !size_changed && !baseline_changed) { /* Still have to move the window... */ @@ -4265,6 +4336,9 @@ gtk_widget_size_allocate (GtkWidget *widget, get_box_border (style, &border); get_box_padding (style, &padding); + priv->transform.x = real_allocation.x + margin.left + border.left + padding.left; + priv->transform.y = real_allocation.y + margin.top + border.top + padding.top; + /* Since gtk_widget_measure does it for us, we can be sure here that * the given alloaction is large enough for the css margin/bordder/padding */ real_allocation.x = 0; @@ -4277,6 +4351,10 @@ gtk_widget_size_allocate (GtkWidget *widget, if (baseline >= 0) baseline -= margin.top + border.top + padding.top; + priv->width = real_allocation.width; + priv->height = real_allocation.height; + priv->baseline = baseline; + if (g_signal_has_handler_pending (widget, widget_signals[SIZE_ALLOCATE], 0, FALSE)) g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, real_allocation.width, @@ -4380,23 +4458,8 @@ gtk_widget_get_origin_relative_to_parent (GtkWidget *widget, int *origin_x, int *origin_y) { - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - GtkBorder margin, border, padding; - GtkCssStyle *style; - - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - - /* allocation is relative to the parent's origin */ - *origin_x = priv->allocation.x; - *origin_y = priv->allocation.y; - - /* ... but points to the upper left, excluding widget margins - * but including all the css properties */ - *origin_x += margin.left + border.left + padding.left; - *origin_y += margin.top + border.top + padding.top; + *origin_x = widget->priv->transform.x; + *origin_y = widget->priv->transform.y; } /** @@ -5008,18 +5071,6 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget, return TRUE; } -static GskRenderer * -gtk_widget_get_renderer (GtkWidget *widget) -{ - GtkWidget *toplevel; - - toplevel = _gtk_widget_get_toplevel (widget); - if (_gtk_widget_is_toplevel (toplevel)) - return gtk_window_get_renderer (GTK_WINDOW (toplevel)); - - return NULL; -} - #define WIDGET_REALIZED_FOR_EVENT(widget, event) \ (event->any.type == GDK_FOCUS_CHANGE || _gtk_widget_get_realized(widget)) @@ -6185,10 +6236,10 @@ _gtk_widget_set_visible_flag (GtkWidget *widget, if (!visible) { - priv->allocation.x = -1; - priv->allocation.y = -1; - priv->allocation.width = 0; - priv->allocation.height = 0; + priv->transform.x = 0; + priv->transform.y = 0; + priv->width = 0; + priv->height = 0; memset (&priv->allocated_size, 0, sizeof (priv->allocated_size)); priv->allocated_size_baseline = 0; gtk_widget_update_paintables (widget); @@ -6278,8 +6329,8 @@ gtk_widget_set_has_surface (GtkWidget *widget, priv->no_surface_set = TRUE; /* GdkSurface has a min size of 1×1 */ - priv->allocation.width = 1; - priv->allocation.height = 1; + priv->width = 1; + priv->height = 1; } /** @@ -6315,20 +6366,9 @@ gtk_widget_get_has_surface (GtkWidget *widget) gboolean gtk_widget_is_toplevel (GtkWidget *widget) { - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); - return priv->toplevel; -} - -void -_gtk_widget_set_is_toplevel (GtkWidget *widget, - gboolean is_toplevel) -{ - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - - priv->toplevel = is_toplevel; + return GTK_IS_ROOT (widget); } /** @@ -6603,7 +6643,11 @@ gtk_widget_reposition_after (GtkWidget *widget, } if (priv->parent->priv->anchored && prev_parent == NULL) - _gtk_widget_propagate_hierarchy_changed (widget, NULL); + { + _gtk_widget_propagate_hierarchy_changed (widget, NULL); + } + if (parent->priv->root && priv->root == NULL) + gtk_widget_root (widget); if (prev_parent == NULL) g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_PARENT]); @@ -6687,6 +6731,25 @@ gtk_widget_get_parent (GtkWidget *widget) return priv->parent; } +/** + * gtk_widget_get_root: + * @widget: a #GtkWidget + * + * Returns the #GtkRoot widget of @widget or %NULL if the widget is not contained + * inside a widget tree with a root widget. + * + * #GtkRoot widgets will return themselves here. + * + * Returns: (transfer none) (nullable): the root widget of @widget, or %NULL + **/ +GtkRoot * +gtk_widget_get_root (GtkWidget *widget) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + return _gtk_widget_get_root (widget); +} + static void gtk_widget_real_direction_changed (GtkWidget *widget, GtkTextDirection previous_direction) @@ -6899,7 +6962,7 @@ gtk_widget_verify_invariants (GtkWidget *widget) g_warning ("%s %p is mapped but not visible", G_OBJECT_TYPE_NAME (widget), widget); - if (!priv->toplevel) + if (!GTK_IS_ROOT (widget)) { if (!priv->child_visible) g_warning ("%s %p is mapped but not child_visible", @@ -6947,7 +7010,7 @@ gtk_widget_verify_invariants (GtkWidget *widget) G_OBJECT_TYPE_NAME (widget), widget); #endif } - else if (!priv->toplevel) + else if (!GTK_IS_ROOT (widget)) { /* No parent or parent not realized on non-toplevel implies... */ @@ -6969,7 +7032,7 @@ gtk_widget_verify_invariants (GtkWidget *widget) G_OBJECT_TYPE_NAME (parent), parent, G_OBJECT_TYPE_NAME (widget), widget); } - else if (!widget->priv->toplevel) + else if (!GTK_IS_ROOT (widget)) { /* No parent or parent not mapped on non-toplevel implies... */ @@ -11130,11 +11193,19 @@ gtk_widget_get_allocation (GtkWidget *widget, GtkAllocation *allocation) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + const graphene_rect_t *margin_rect; + GtkCssBoxes boxes; g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (allocation != NULL); - *allocation = priv->allocation; + gtk_css_boxes_init (&boxes, widget); + margin_rect = gtk_css_boxes_get_margin_rect (&boxes); + + allocation->x = priv->transform.x + ceil (margin_rect->origin.x); + allocation->y = priv->transform.y + ceil (margin_rect->origin.y); + allocation->width = ceil (margin_rect->size.width); + allocation->height = ceil (margin_rect->size.height); } /** @@ -11216,18 +11287,12 @@ gtk_widget_pick (GtkWidget *widget, case GTK_OVERFLOW_HIDDEN: { - GtkBorder margin, border, padding; - GtkCssStyle *style; - - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - - if (x < -padding.left || - y < -padding.top || - x >= priv->allocation.width - margin.left - margin.right - border.left - border.right - padding.left || - y >= priv->allocation.height - margin.top - margin.bottom - border.top - border.bottom - padding.top) + GtkCssBoxes boxes; + + gtk_css_boxes_init (&boxes, widget); + + if (!graphene_rect_contains_point (gtk_css_boxes_get_padding_rect (&boxes), + &GRAPHENE_POINT_INIT (x, y))) return NULL; } break; @@ -11259,39 +11324,26 @@ gtk_widget_compute_bounds (GtkWidget *widget, GtkWidget *target, graphene_rect_t *out_bounds) { - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - GtkBorder margin, border, padding; - GtkCssStyle *style; - GtkAllocation alloc; + GtkCssBoxes boxes; + int x, y; g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); g_return_val_if_fail (GTK_IS_WIDGET (target), FALSE); g_return_val_if_fail (out_bounds != NULL, FALSE); - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - - alloc.x = - (padding.left + border.left); - alloc.y = - (padding.top + border.top); - alloc.width = priv->allocation.width - margin.left - margin.right; - alloc.height = priv->allocation.height -margin.top - margin.bottom; - if (!gtk_widget_translate_coordinates (widget, target, - alloc.x, alloc.y, - &alloc.x, &alloc.y)) + 0, 0, + &x, &y)) { graphene_rect_init_from_rect (out_bounds, graphene_rect_zero ()); return FALSE; } - graphene_rect_init (out_bounds, - alloc.x, - alloc.y, - alloc.width, - alloc.height); + gtk_css_boxes_init (&boxes, widget); + graphene_rect_offset_r (gtk_css_boxes_get_border_rect (&boxes), + x, y, + out_bounds); return TRUE; } @@ -11307,11 +11359,13 @@ gtk_widget_compute_bounds (GtkWidget *widget, int gtk_widget_get_allocated_width (GtkWidget *widget) { - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + GtkCssBoxes boxes; g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - return priv->allocation.width; + gtk_css_boxes_init (&boxes, widget); + + return gtk_css_boxes_get_margin_rect (&boxes)->size.width; } /** @@ -11325,11 +11379,13 @@ gtk_widget_get_allocated_width (GtkWidget *widget) int gtk_widget_get_allocated_height (GtkWidget *widget) { - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + GtkCssBoxes boxes; g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - return priv->allocation.height; + gtk_css_boxes_init (&boxes, widget); + + return gtk_css_boxes_get_margin_rect (&boxes)->size.height; } /** @@ -11352,7 +11408,7 @@ gtk_widget_get_allocated_baseline (GtkWidget *widget) g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - if (priv->allocated_baseline == -1) + if (priv->baseline == -1) return -1; style = gtk_css_node_get_style (priv->cssnode); @@ -11360,7 +11416,7 @@ gtk_widget_get_allocated_baseline (GtkWidget *widget) get_box_border (style, &border); get_box_padding (style, &padding); - return priv->allocated_baseline - margin.top - border.top - padding.top; + return priv->baseline - margin.top - border.top - padding.top; } /** @@ -12948,36 +13004,24 @@ gtk_widget_reset_controllers (GtkWidget *widget) } static inline void -gtk_widget_maybe_add_debug_render_nodes (GtkWidget *widget, - GtkSnapshot *snapshot) +gtk_widget_maybe_add_debug_render_nodes (GtkWidget *widget, + GtkSnapshot *snapshot) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); GdkDisplay *display = _gtk_widget_get_display (widget); - GtkCssStyle *style; - GtkBorder margin, border, padding; - - /* We should be offset to priv->allocation at this point */ if (GTK_DISPLAY_DEBUG_CHECK (display, BASELINES)) { - int baseline = gtk_widget_get_allocated_baseline (widget); - - if (baseline != -1) + if (priv->baseline != -1) { GdkRGBA red = {1, 0, 0, 1}; graphene_rect_t bounds; - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - /* Baselines are relative to the widget's origin, * and we are offset to the widget's allocation here */ graphene_rect_init (&bounds, - 0, - margin.top + border.top + padding.top + baseline, - priv->allocation.width, 1); + 0, priv->baseline, + priv->width, 1); gtk_snapshot_append_color (snapshot, &red, &bounds); @@ -12992,7 +13036,7 @@ gtk_widget_maybe_add_debug_render_nodes (GtkWidget *widget, graphene_rect_init (&bounds, 0, 0, - priv->allocation.width, priv->allocation.height); + priv->width, priv->height); gtk_snapshot_append_color (snapshot, &blue, @@ -13009,74 +13053,43 @@ gtk_widget_create_render_node (GtkWidget *widget, { GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget); GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + GtkCssBoxes boxes; GtkCssValue *filter_value; double opacity; - GtkCssStyle *style; - GtkAllocation allocation; - GtkBorder margin, border, padding; GtkSnapshot *snapshot; opacity = priv->alpha / 255.0; if (opacity <= 0.0) return NULL; + gtk_css_boxes_init (&boxes, widget); snapshot = gtk_snapshot_new_with_parent (parent_snapshot); - _gtk_widget_get_allocation (widget, &allocation); gtk_snapshot_push_debug (snapshot, - "RenderNode for %s %p @ %d x %d", - G_OBJECT_TYPE_NAME (widget), widget, - allocation.width, allocation.height); + "RenderNode for %s %p", + G_OBJECT_TYPE_NAME (widget), widget); filter_value = _gtk_style_context_peek_property (_gtk_widget_get_style_context (widget), GTK_CSS_PROPERTY_FILTER); gtk_css_filter_value_push_snapshot (filter_value, snapshot); - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - if (opacity < 1.0) gtk_snapshot_push_opacity (snapshot, opacity); if (!GTK_IS_WINDOW (widget)) { - gtk_snapshot_offset (snapshot, margin.left, margin.top); - gtk_css_style_snapshot_background (style, - snapshot, - allocation.width - margin.left - margin.right, - allocation.height - margin.top - margin.bottom); - gtk_css_style_snapshot_border (style, - snapshot, - allocation.width - margin.left - margin.right, - allocation.height - margin.top - margin.bottom); - gtk_snapshot_offset (snapshot, - margin.left, - margin.top); + gtk_css_style_snapshot_background (&boxes, snapshot); + gtk_css_style_snapshot_border (&boxes, snapshot); } - /* Offset to content allocation */ - gtk_snapshot_offset (snapshot, margin.left + padding.left + border.left, margin.top + border.top + padding.top); - if (priv->overflow == GTK_OVERFLOW_HIDDEN) - { - gtk_snapshot_push_clip (snapshot, - &GRAPHENE_RECT_INIT (- padding.left, - - padding.top, - allocation.width - margin.left - margin.right - border.left - border.right, - allocation.height - margin.top - margin.bottom - border.top - border.bottom)); - } + gtk_snapshot_push_clip (snapshot, gtk_css_boxes_get_padding_rect (&boxes)); klass->snapshot (widget, snapshot); if (priv->overflow == GTK_OVERFLOW_HIDDEN) gtk_snapshot_pop (snapshot); - gtk_snapshot_offset (snapshot, - (padding.left + border.left), -(border.top + padding.top)); - - gtk_css_style_snapshot_outline (style, - snapshot, - allocation.width - margin.left - margin.right, - allocation.height - margin.top - margin.bottom); - gtk_snapshot_offset (snapshot, - margin.left, - margin.top); + gtk_css_style_snapshot_outline (&boxes, snapshot); if (opacity < 1.0) gtk_snapshot_pop (snapshot); @@ -13137,17 +13150,24 @@ gtk_widget_render (GtkWidget *widget, GtkSnapshot *snapshot; GskRenderer *renderer; GskRenderNode *root; + int x, y; + + if (!GTK_IS_ROOT (widget)) + return; /* We only render double buffered on native windows */ if (!gdk_surface_has_native (surface)) return; - renderer = gtk_widget_get_renderer (widget); + renderer = gtk_root_get_renderer (GTK_ROOT (widget)); if (renderer == NULL) return; snapshot = gtk_snapshot_new (); + gtk_root_get_surface_transform (GTK_ROOT (widget), &x, &y); + gtk_snapshot_offset (snapshot, x, y); gtk_widget_snapshot (widget, snapshot); + gtk_snapshot_offset (snapshot, -x, -y); root = gtk_snapshot_free_to_node (snapshot); if (root != NULL) @@ -13459,14 +13479,12 @@ gtk_widget_snapshot_child (GtkWidget *widget, GtkWidget *child, GtkSnapshot *snapshot) { - GtkWidgetPrivate *priv = gtk_widget_get_instance_private (child); int x, y; g_return_if_fail (_gtk_widget_get_parent (child) == widget); g_return_if_fail (snapshot != NULL); - x = priv->allocation.x; - y = priv->allocation.y; + gtk_widget_get_origin_relative_to_parent (child, &x, &y); gtk_snapshot_offset (snapshot, x, y); gtk_widget_snapshot (child, snapshot); @@ -13658,20 +13676,10 @@ int gtk_widget_get_width (GtkWidget *widget) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - GtkBorder margin, border, padding; - GtkCssStyle *style; g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - - return priv->allocation.width - - margin.left - margin.right - - border.left - border.right - - padding.left - padding.right; + return priv->width; } /** @@ -13688,18 +13696,8 @@ int gtk_widget_get_height (GtkWidget *widget) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); - GtkBorder margin, border, padding; - GtkCssStyle *style; g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); - - return priv->allocation.height - - margin.top - margin.bottom - - border.top - border.bottom - - padding.top - padding.bottom; + return priv->height; } diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 9b89f70246..7e6b91b041 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -152,6 +152,9 @@ struct _GtkWidget * widget is destroyed, which means that gtk_widget_unrealize() has * been called or the widget has been unmapped (that is, it is going * to be hidden). + * @root: Called when the widget gets added to a #GtkRoot widget. + * @unroot: Called when the widget is about to be removed from its + * #GtkRoot widget. * @size_allocate: Signal emitted to get the widget allocation. * @state_flags_changed: Signal emitted when the widget state changes, * see gtk_widget_get_state_flags(). @@ -247,6 +250,8 @@ struct _GtkWidgetClass void (* unmap) (GtkWidget *widget); void (* realize) (GtkWidget *widget); void (* unrealize) (GtkWidget *widget); + void (* root) (GtkWidget *widget); + void (* unroot) (GtkWidget *widget); void (* size_allocate) (GtkWidget *widget, int width, int height, @@ -559,13 +564,16 @@ GDK_AVAILABLE_IN_ALL void gtk_widget_set_parent (GtkWidget *widget, GtkWidget *parent); GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_widget_get_parent (GtkWidget *widget); +GtkWidget * gtk_widget_get_parent (GtkWidget *widget); + +GDK_AVAILABLE_IN_ALL +GtkRoot * gtk_widget_get_root (GtkWidget *widget); GDK_AVAILABLE_IN_ALL void gtk_widget_set_parent_surface (GtkWidget *widget, GdkSurface *parent_surface); GDK_AVAILABLE_IN_ALL -GdkSurface * gtk_widget_get_parent_surface (GtkWidget *widget); +GdkSurface * gtk_widget_get_parent_surface (GtkWidget *widget); GDK_AVAILABLE_IN_ALL void gtk_widget_set_child_visible (GtkWidget *widget, diff --git a/gtk/gtkwidgetpaintable.c b/gtk/gtkwidgetpaintable.c index 976b29d2c7..531b1332fc 100644 --- a/gtk/gtkwidgetpaintable.c +++ b/gtk/gtkwidgetpaintable.c @@ -92,13 +92,15 @@ gtk_widget_paintable_paintable_snapshot (GdkPaintable *paintable, else if (self->snapshot_count > 0) { graphene_matrix_t transform; + graphene_rect_t bounds; gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT(0, 0, width, height)); - graphene_matrix_init_scale (&transform, - width / gtk_widget_get_allocated_width (self->widget), - height / gtk_widget_get_allocated_height (self->widget), - 1.0); + gtk_widget_compute_bounds (self->widget, self->widget, &bounds); + graphene_matrix_init_from_2d (&transform, + width / bounds.size.width, 0.0, + 0.0, height / bounds.size.height, + bounds.origin.x, bounds.origin.y); gtk_snapshot_push_transform (snapshot, &transform); gtk_widget_snapshot (self->widget, snapshot); diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 26c33ba0bc..35753b6736 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -32,6 +32,7 @@ #include "gtkcsstypesprivate.h" #include "gtkeventcontroller.h" #include "gtklistlistmodelprivate.h" +#include "gtkrootprivate.h" #include "gtksizerequestcacheprivate.h" #include "gtkwindowprivate.h" #include "gtkinvisibleprivate.h" @@ -55,7 +56,6 @@ struct _GtkWidgetPrivate #endif guint in_destruction : 1; - guint toplevel : 1; guint anchored : 1; guint no_surface : 1; guint no_surface_set : 1; @@ -124,6 +124,11 @@ struct _GtkWidgetPrivate */ gchar *name; + /* The root this widget belongs to or %NULL if widget is not + * rooted or is a #GtkRoot itself. + */ + GtkRoot *root; + /* The list of attached windows to this widget. * We keep a list in order to call reset_style to all of them, * recursively. @@ -141,8 +146,13 @@ struct _GtkWidgetPrivate /* The widget's allocated size */ GtkAllocation allocated_size; gint allocated_size_baseline; - GtkAllocation allocation; - gint allocated_baseline; + struct { + int x; + int y; + } transform; + int width; + int height; + int baseline; /* The widget's requested sizes */ SizeRequestCache requests; @@ -221,8 +231,6 @@ void _gtk_widget_set_has_default (GtkWidget *widget, gboolean has_default); void _gtk_widget_set_has_grab (GtkWidget *widget, gboolean has_grab); -void _gtk_widget_set_is_toplevel (GtkWidget *widget, - gboolean is_toplevel); void _gtk_widget_grab_notify (GtkWidget *widget, gboolean was_grabbed); @@ -385,7 +393,7 @@ _gtk_widget_get_realized (GtkWidget *widget) static inline gboolean _gtk_widget_is_toplevel (GtkWidget *widget) { - return widget->priv->toplevel; + return GTK_IS_ROOT (widget); } static inline GtkStateFlags @@ -414,20 +422,21 @@ _gtk_widget_get_toplevel (GtkWidget *widget) return widget; } +static inline GtkRoot * +_gtk_widget_get_root (GtkWidget *widget) +{ + return widget->priv->root; +} + static inline GdkDisplay * _gtk_widget_get_display (GtkWidget *widget) { - GtkWidget *toplevel = _gtk_widget_get_toplevel (widget); + GtkRoot *root = _gtk_widget_get_root (widget); - if (_gtk_widget_is_toplevel (toplevel)) - { - if (GTK_IS_WINDOW (toplevel)) - return gtk_window_get_display (GTK_WINDOW (toplevel)); - else if (GTK_IS_INVISIBLE (toplevel)) - return gtk_invisible_get_display (GTK_INVISIBLE (widget)); - } + if (root == NULL) + return gdk_display_get_default (); - return gdk_display_get_default (); + return gtk_root_get_display (root); } static inline GtkStyleContext * @@ -451,13 +460,6 @@ _gtk_widget_get_surface (GtkWidget *widget) return widget->priv->surface; } -static inline void -_gtk_widget_get_allocation (GtkWidget *widget, - GtkAllocation *allocation) -{ - *allocation = widget->priv->allocation; -} - static inline GtkWidget * _gtk_widget_get_prev_sibling (GtkWidget *widget) { diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index b101fc7376..ab5061d5f4 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -61,6 +61,7 @@ #include "gtkpointerfocusprivate.h" #include "gtkpopoverprivate.h" #include "gtkprivate.h" +#include "gtkroot.h" #include "gtkseparatormenuitem.h" #include "gtksettings.h" #include "gtksnapshot.h" @@ -432,7 +433,6 @@ static void gtk_window_focus_out (GtkWidget *widget); static void surface_state_changed (GtkWidget *widget); static void gtk_window_remove (GtkContainer *container, GtkWidget *widget); -static void gtk_window_check_resize (GtkContainer *container); static void gtk_window_forall (GtkContainer *container, GtkCallback callback, gpointer callback_data); @@ -562,6 +562,9 @@ static void gtk_window_buildable_custom_finished (GtkBuildable *buildable, const gchar *tagname, gpointer user_data); +/* GtkRoot */ +static void gtk_window_root_interface_init (GtkRootInterface *iface); + static void ensure_state_flag_backdrop (GtkWidget *widget); static void unset_titlebar (GtkWindow *window); static void on_titlebar_title_notify (GtkHeaderBar *titlebar, @@ -576,7 +579,9 @@ static void gtk_window_update_debugging (void); G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN, G_ADD_PRIVATE (GtkWindow) G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gtk_window_buildable_interface_init)) + gtk_window_buildable_interface_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ROOT, + gtk_window_root_interface_init)) static void add_tab_bindings (GtkBindingSet *binding_set, @@ -809,7 +814,6 @@ gtk_window_class_init (GtkWindowClass *klass) container_class->add = gtk_window_add; container_class->remove = gtk_window_remove; - container_class->check_resize = gtk_window_check_resize; container_class->forall = gtk_window_forall; klass->set_focus = gtk_window_real_set_focus; @@ -1724,7 +1728,7 @@ edge_under_coordinates (GtkWindow *window, (priv->edge_constraints & constraints) != constraints) return FALSE; - _gtk_widget_get_allocation (GTK_WIDGET (window), &allocation); + gtk_widget_get_allocation (GTK_WIDGET (window), &allocation); context = _gtk_widget_get_style_context (GTK_WIDGET (window)); gtk_style_context_save_to_node (context, priv->decoration_node); @@ -1862,7 +1866,6 @@ gtk_window_init (GtkWindow *window) widget = GTK_WIDGET (window); gtk_widget_set_has_surface (widget, TRUE); - _gtk_widget_set_is_toplevel (widget, TRUE); _gtk_widget_set_anchored (widget, TRUE); priv->title = NULL; @@ -2495,6 +2498,50 @@ gtk_window_buildable_custom_finished (GtkBuildable *buildable, } } +static GdkDisplay * +gtk_window_root_get_display (GtkRoot *root) +{ + GtkWindow *window = GTK_WINDOW (root); + GtkWindowPrivate *priv = gtk_window_get_instance_private (window); + + return priv->display; +} + +static GskRenderer * +gtk_window_root_get_renderer (GtkRoot *root) +{ + GtkWindow *self = GTK_WINDOW (root); + GtkWindowPrivate *priv = gtk_window_get_instance_private (self); + + return priv->renderer; +} + +static void +gtk_window_root_get_surface_transform (GtkRoot *root, + int *x, + int *y) +{ + GtkWindow *self = GTK_WINDOW (root); + GtkStyleContext *context; + GtkBorder margin, border, padding; + + context = gtk_widget_get_style_context (GTK_WIDGET (self)); + gtk_style_context_get_margin (context, &margin); + gtk_style_context_get_border (context, &border); + gtk_style_context_get_padding (context, &padding); + + *x = margin.left + border.left + padding.left; + *y = margin.top + border.top + padding.top; +} + +static void +gtk_window_root_interface_init (GtkRootInterface *iface) +{ + iface->get_display = gtk_window_root_get_display; + iface->get_renderer = gtk_window_root_get_renderer; + iface->get_surface_transform = gtk_window_root_get_surface_transform; +} + /** * gtk_window_new: * @type: type of window @@ -5224,7 +5271,7 @@ gtk_window_move (GtkWindow *window, { GtkAllocation allocation; - _gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (widget, &allocation); /* we have now sent a request with this position * with currently-active constraints, so toggle flag. @@ -5704,7 +5751,6 @@ gtk_window_show (GtkWidget *widget) { GtkWindow *window = GTK_WINDOW (widget); GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkContainer *container = GTK_CONTAINER (window); if (!_gtk_widget_is_toplevel (GTK_WIDGET (widget))) { @@ -5718,7 +5764,7 @@ gtk_window_show (GtkWidget *widget) gtk_widget_realize (widget); - gtk_container_check_resize (container); + gtk_window_check_resize (window); gtk_widget_map (widget); @@ -6017,7 +6063,7 @@ popover_get_rect (GtkWindowPopover *popover, gdouble min, max; gtk_widget_get_preferred_size (popover->widget, NULL, &req); - _gtk_widget_get_allocation (GTK_WIDGET (window), &win_alloc); + gtk_widget_get_allocation (GTK_WIDGET (window), &win_alloc); get_shadow_width (window, &win_border); win_alloc.x += win_border.left; @@ -6403,7 +6449,7 @@ gtk_window_realize (GtkWidget *widget) g_return_if_fail (!_gtk_widget_get_realized (widget)); } - _gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (widget, &allocation); if (priv->hardcoded_surface) { @@ -6781,7 +6827,7 @@ gtk_window_configure (GtkWindow *window, * have been a queued resize from child widgets, and so we * need to reallocate our children in case *they* changed. */ - _gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (widget, &allocation); if (priv->configure_request_count == 0 && (allocation.width == width && allocation.height == height)) { @@ -7002,7 +7048,7 @@ get_active_region_type (GtkWindow *window, gint x, gint y) gtk_widget_get_visible (priv->title_box) && gtk_widget_get_child_visible (priv->title_box)) { - _gtk_widget_get_allocation (priv->title_box, &allocation); + gtk_widget_get_allocation (priv->title_box, &allocation); if (allocation.x <= x && allocation.x + allocation.width > x && allocation.y <= y && allocation.y + allocation.height > y) return GTK_WINDOW_REGION_TITLE; @@ -7157,13 +7203,15 @@ gtk_window_remove (GtkContainer *container, GTK_CONTAINER_CLASS (gtk_window_parent_class)->remove (container, widget); } -static void -gtk_window_check_resize (GtkContainer *container) +void +gtk_window_check_resize (GtkWindow *self) { - if (!_gtk_widget_get_alloc_needed (GTK_WIDGET (container))) - GTK_CONTAINER_CLASS (gtk_window_parent_class)->check_resize (container); - else if (gtk_widget_get_visible (GTK_WIDGET (container))) - gtk_window_move_resize (GTK_WINDOW (container)); + GtkWidget *widget = GTK_WIDGET (self); + + if (!_gtk_widget_get_alloc_needed (widget)) + gtk_widget_ensure_allocate (widget); + else if (gtk_widget_get_visible (widget)) + gtk_window_move_resize (self); } static void @@ -7380,7 +7428,7 @@ gtk_window_style_updated (GtkWidget *widget) GtkAllocation allocation; GtkBorder window_border; - _gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (widget, &allocation); get_shadow_width (window, &window_border); update_opaque_region (window, &window_border, &allocation); @@ -7926,7 +7974,7 @@ gtk_window_compute_configure_request (GtkWindow *window, gdk_surface_get_origin (surface, &ox, &oy); - _gtk_widget_get_allocation (parent_widget, &allocation); + gtk_widget_get_allocation (parent_widget, &allocation); x = ox + (allocation.width - w) / 2; y = oy + (allocation.height - h) / 2; @@ -9427,14 +9475,6 @@ gtk_window_on_theme_variant_changed (GtkSettings *settings, } #endif -GdkDisplay * -gtk_window_get_display (GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - - return priv->display; -} - /** * gtk_window_is_active: * @window: a #GtkWindow @@ -10557,14 +10597,6 @@ gtk_window_unexport_handle (GtkWindow *window) #endif } -GskRenderer * -gtk_window_get_renderer (GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - - return priv->renderer; -} - static void gtk_window_add_pointer_focus (GtkWindow *window, GtkPointerFocus *focus) diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h index 1de4e0bedb..de0c853f77 100644 --- a/gtk/gtkwindowprivate.h +++ b/gtk/gtkwindowprivate.h @@ -54,6 +54,7 @@ void _gtk_window_set_allocation (GtkWindow *window, int width, int height, GtkAllocation *allocation_out); +void gtk_window_check_resize (GtkWindow *self); typedef void (*GtkWindowKeysForeachFunc) (GtkWindow *window, guint keyval, @@ -120,8 +121,6 @@ GdkTexture * gtk_window_get_icon_for_size (GtkWindow *window, void gtk_window_set_hardcoded_surface (GtkWindow *window, GdkSurface *surface); -GdkDisplay *gtk_window_get_display (GtkWindow *window); - /* Exported handles */ typedef void (*GtkWindowHandleExported) (GtkWindow *window, @@ -133,8 +132,6 @@ gboolean gtk_window_export_handle (GtkWindow *window, gpointer user_data); void gtk_window_unexport_handle (GtkWindow *window); -GskRenderer *gtk_window_get_renderer (GtkWindow *window); - GtkWidget * gtk_window_lookup_pointer_focus_widget (GtkWindow *window, GdkDevice *device, GdkEventSequence *sequence); diff --git a/gtk/inspector/logs.c b/gtk/inspector/logs.c index a8c59ceba6..1bc73c7629 100644 --- a/gtk/inspector/logs.c +++ b/gtk/inspector/logs.c @@ -35,7 +35,7 @@ #include "gtkprivate.h" #include "gtkdebug.h" #include "gdkinternals.h" -#include "gtkwindowprivate.h" +#include "gtkrootprivate.h" #include "gskdebugprivate.h" #include "gskrendererprivate.h" @@ -146,7 +146,7 @@ flag_toggled (GtkWidget *button, if (toplevel == gtk_widget_get_toplevel (button)) /* skip the inspector */ continue; - renderer = gtk_window_get_renderer (GTK_WINDOW (toplevel)); + renderer = gtk_root_get_renderer (GTK_ROOT (toplevel)); if (!renderer) continue; diff --git a/gtk/inspector/window.c b/gtk/inspector/window.c index 3239cd5770..9bdced31e4 100644 --- a/gtk/inspector/window.c +++ b/gtk/inspector/window.c @@ -51,10 +51,10 @@ #include "gtklabel.h" #include "gtkmodulesprivate.h" #include "gtkprivate.h" +#include "gtkrootprivate.h" #include "gtkstack.h" #include "gtktreeviewcolumn.h" #include "gtkwindowgroup.h" -#include "gtkwindowprivate.h" G_DEFINE_TYPE (GtkInspectorWindow, gtk_inspector_window, GTK_TYPE_WINDOW) @@ -273,7 +273,7 @@ gtk_inspector_window_realize (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_inspector_window_parent_class)->realize (widget); - renderer = gtk_window_get_renderer (GTK_WINDOW (widget)); + renderer = gtk_root_get_renderer (GTK_ROOT (widget)); gsk_renderer_set_debug_flags (renderer, 0); } diff --git a/gtk/meson.build b/gtk/meson.build index 3ebb1b5867..558232b9e7 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -314,6 +314,7 @@ gtk_public_sources = files([ 'gtkrendericon.c', 'gtkrendernodepaintable.c', 'gtkrevealer.c', + 'gtkroot.c', 'gtkroundedbox.c', 'gtkscale.c', 'gtkscalebutton.c', @@ -551,6 +552,7 @@ gtk_public_headers = files([ 'gtkrecentmanager.h', 'gtkrender.h', 'gtkrevealer.h', + 'gtkroot.h', 'gtkscale.h', 'gtkscalebutton.h', 'gtkscrollable.h', |