From e0ec5caaf868e9a33ec0f5f5bc5b71db99c4a2c4 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 9 Feb 2019 01:44:10 +0100 Subject: [PATCH 01/15] container: Drop gtk_container_check_resize() Instead, hardcode GtkWindow for now. The code for non-windows was entirely broken. --- docs/reference/gtk/gtk4-sections.txt | 1 - gtk/gtkcontainer.c | 57 +++------------------------- gtk/gtkcontainer.h | 5 --- gtk/gtkwindow.c | 19 +++++----- gtk/gtkwindowprivate.h | 1 + 5 files changed, 15 insertions(+), 68 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index fd93df5a50..473a96fb2a 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -753,7 +753,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/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); @@ -125,9 +123,6 @@ GDK_AVAILABLE_IN_ALL 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, diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index b101fc7376..03b8c500e9 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -432,7 +432,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); @@ -809,7 +808,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; @@ -5704,7 +5702,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 +5715,7 @@ gtk_window_show (GtkWidget *widget) gtk_widget_realize (widget); - gtk_container_check_resize (container); + gtk_window_check_resize (window); gtk_widget_map (widget); @@ -7157,13 +7154,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 diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h index 1de4e0bedb..f57a1b377b 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, From d3a2218ff4acac12aeb443f4f2a6aca64e97298f Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 9 Feb 2019 03:03:59 +0100 Subject: [PATCH 02/15] widget: Split up priv->allocation It's not priv->transform (to be turned into a graphene matrix), priv->width and priv->height. The numbers are still the same. The only difference is that unallocated widgets will now have x/y set to 0, not to -1. --- gtk/gtkwidget.c | 76 ++++++++++++++++++++++-------------------- gtk/gtkwidgetprivate.h | 16 +++++++-- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 9207a46b1d..39f50c3241 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -2810,10 +2810,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 +2818,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; @@ -3044,8 +3040,8 @@ 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); @@ -4233,15 +4229,18 @@ 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); + baseline_changed = priv->baseline != baseline; + size_changed = (priv->width != real_allocation.width || + priv->height != real_allocation.height); + position_changed = (priv->transform.x != real_allocation.x || + priv->transform.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; + priv->transform.x = real_allocation.x; + priv->transform.y = real_allocation.y; + priv->width = real_allocation.width; + priv->height = real_allocation.height; + priv->baseline = baseline; if (!alloc_needed && !size_changed && !baseline_changed) { @@ -4390,8 +4389,8 @@ gtk_widget_get_origin_relative_to_parent (GtkWidget *widget, get_box_padding (style, &padding); /* allocation is relative to the parent's origin */ - *origin_x = priv->allocation.x; - *origin_y = priv->allocation.y; + *origin_x = priv->transform.x; + *origin_y = priv->transform.y; /* ... but points to the upper left, excluding widget margins * but including all the css properties */ @@ -6185,10 +6184,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 +6277,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; } /** @@ -11134,7 +11133,10 @@ gtk_widget_get_allocation (GtkWidget *widget, g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (allocation != NULL); - *allocation = priv->allocation; + allocation->x = priv->transform.x; + allocation->y = priv->transform.y; + allocation->width = priv->width; + allocation->height = priv->height; } /** @@ -11226,8 +11228,8 @@ gtk_widget_pick (GtkWidget *widget, 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) + x >= priv->width - margin.left - margin.right - border.left - border.right - padding.left || + y >= priv->height - margin.top - margin.bottom - border.top - border.bottom - padding.top) return NULL; } break; @@ -11275,8 +11277,8 @@ gtk_widget_compute_bounds (GtkWidget *widget, 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; + alloc.width = priv->width - margin.left - margin.right; + alloc.height = priv->height - margin.top - margin.bottom; if (!gtk_widget_translate_coordinates (widget, target, @@ -11311,7 +11313,7 @@ gtk_widget_get_allocated_width (GtkWidget *widget) g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - return priv->allocation.width; + return priv->width; } /** @@ -11329,7 +11331,7 @@ gtk_widget_get_allocated_height (GtkWidget *widget) g_return_val_if_fail (GTK_IS_WIDGET (widget), 0); - return priv->allocation.height; + return priv->height; } /** @@ -11352,7 +11354,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 +11362,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; } /** @@ -12977,7 +12979,7 @@ gtk_widget_maybe_add_debug_render_nodes (GtkWidget *widget, graphene_rect_init (&bounds, 0, margin.top + border.top + padding.top + baseline, - priv->allocation.width, 1); + priv->width, 1); gtk_snapshot_append_color (snapshot, &red, &bounds); @@ -12992,7 +12994,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, @@ -13465,8 +13467,8 @@ gtk_widget_snapshot_child (GtkWidget *widget, g_return_if_fail (_gtk_widget_get_parent (child) == widget); g_return_if_fail (snapshot != NULL); - x = priv->allocation.x; - y = priv->allocation.y; + x = priv->transform.x; + y = priv->transform.y; gtk_snapshot_offset (snapshot, x, y); gtk_widget_snapshot (child, snapshot); @@ -13668,7 +13670,7 @@ gtk_widget_get_width (GtkWidget *widget) get_box_border (style, &border); get_box_padding (style, &padding); - return priv->allocation.width - + return priv->width - margin.left - margin.right - border.left - border.right - padding.left - padding.right; @@ -13698,7 +13700,7 @@ gtk_widget_get_height (GtkWidget *widget) get_box_border (style, &border); get_box_padding (style, &padding); - return priv->allocation.height - + return priv->height - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom; diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 26c33ba0bc..6aa41f2430 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -141,8 +141,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; @@ -455,7 +460,12 @@ static inline void _gtk_widget_get_allocation (GtkWidget *widget, GtkAllocation *allocation) { - *allocation = widget->priv->allocation; + GtkWidgetPrivate *priv = widget->priv; + + allocation->x = priv->transform.x; + allocation->y = priv->transform.y; + allocation->width = priv->width; + allocation->height = priv->height; } static inline GtkWidget * From d65a60e0bdfd7ad3c3c2319b70921608678898a5 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 9 Feb 2019 05:28:44 +0100 Subject: [PATCH 03/15] widget: Move compuatation of what changed further up This way, we can compare with literally the previous allocation and the size will not be influenced by an adjusted allocation. But more importantly, we can now use the transform/width/height values for other stuff. --- gtk/gtkwidget.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 39f50c3241..98505bbb59 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4141,6 +4141,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; @@ -4229,12 +4235,6 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation.height = MAX (1, real_allocation.height); } - baseline_changed = priv->baseline != baseline; - size_changed = (priv->width != real_allocation.width || - priv->height != real_allocation.height); - position_changed = (priv->transform.x != real_allocation.x || - priv->transform.y != real_allocation.y); - /* Set the widget allocation to real_allocation now, pass the smaller allocation to the vfunc */ priv->transform.x = real_allocation.x; priv->transform.y = real_allocation.y; From 2e5bc9fbc38e8ef4dfe7e07514ba5c3d05ed37b6 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 6 Apr 2018 20:21:06 +0200 Subject: [PATCH 04/15] gtk: Add the GtkRoot interface So far, this doesn't do anything. --- gtk/gtk.h | 1 + gtk/gtkroot.c | 44 ++++++++++++++++++++++++++++++++++++++++ gtk/gtkroot.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ gtk/gtktypes.h | 1 + gtk/meson.build | 2 ++ 5 files changed, 101 insertions(+) create mode 100644 gtk/gtkroot.c create mode 100644 gtk/gtkroot.h diff --git a/gtk/gtk.h b/gtk/gtk.h index c79f1a9dfb..368ce0ca69 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -176,6 +176,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c new file mode 100644 index 0000000000..3eecc97ec6 --- /dev/null +++ b/gtk/gtkroot.c @@ -0,0 +1,44 @@ +/* + * 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 . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gtkroot.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 void +gtk_root_default_init (GtkRootInterface *iface) +{ +} + diff --git a/gtk/gtkroot.h b/gtk/gtkroot.h new file mode 100644 index 0000000000..e4894ee46b --- /dev/null +++ b/gtk/gtkroot.h @@ -0,0 +1,53 @@ +/* + * 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 . + * + * Authors: Benjamin Otte + */ + +#ifndef __GTK_ROOT_H__ +#define __GTK_ROOT_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +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 >*/ +}; + + +G_END_DECLS + +#endif /* __GTK_ROOT_H__ */ 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/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', From aeda099f47b0868e84bb26217539904e490d7ea8 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 6 Apr 2018 20:30:34 +0200 Subject: [PATCH 05/15] widget: Remove toplevel flag Instead, rely on GTK_IS_ROOT(). Also implement GtkRoot on GtkWindow and GtkInvisible, the two widgets that used to set the toplevel flag before. --- gtk/gtkinvisible.c | 19 ++++++++++++++----- gtk/gtkprintoperation-win32.c | 2 -- gtk/gtkwidget.c | 19 ++++--------------- gtk/gtkwidgetprivate.h | 6 ++---- gtk/gtkwindow.c | 14 ++++++++++++-- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/gtk/gtkinvisible.c b/gtk/gtkinvisible.c index 37821039a6..910b406376 100644 --- a/gtk/gtkinvisible.c +++ b/gtk/gtkinvisible.c @@ -23,11 +23,13 @@ */ #include "config.h" -#include + #include "gtkinvisibleprivate.h" -#include "gtkwidgetprivate.h" -#include "gtkprivate.h" + #include "gtkintl.h" +#include "gtkprivate.h" +#include "gtkroot.h" +#include "gtkwidgetprivate.h" /** @@ -69,7 +71,15 @@ 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 void +gtk_invisible_root_interface_init (GtkRootInterface *iface) +{ +} + +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 +117,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); 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/gtkwidget.c b/gtk/gtkwidget.c index 98505bbb59..4002e2ba12 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -6314,20 +6314,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); } /** @@ -6898,7 +6887,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", @@ -6946,7 +6935,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... */ @@ -6968,7 +6957,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... */ diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 6aa41f2430..cdfe98b9be 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -32,6 +32,7 @@ #include "gtkcsstypesprivate.h" #include "gtkeventcontroller.h" #include "gtklistlistmodelprivate.h" +#include "gtkroot.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; @@ -226,8 +226,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); @@ -390,7 +388,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 diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 03b8c500e9..4eccf40b2d 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" @@ -561,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, @@ -575,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, @@ -1860,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; @@ -2493,6 +2498,11 @@ gtk_window_buildable_custom_finished (GtkBuildable *buildable, } } +static void +gtk_window_root_interface_init (GtkRootInterface *iface) +{ +} + /** * gtk_window_new: * @type: type of window From 4ca1f7e29f60753621a33215dfa52cec23457f5c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 29 Jul 2018 03:31:36 +0200 Subject: [PATCH 06/15] widget: Add GtkWidgetClass:root and :unroot functions They get added whenever a widget gets added into a hierarchy with a root widget. --- gtk/gtkwidget.c | 71 +++++++++++++++++++++++++++++++++++++++--- gtk/gtkwidget.h | 5 +++ gtk/gtkwidgetprivate.h | 5 +++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 4002e2ba12..23ac98c154 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -602,6 +602,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); @@ -853,6 +855,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) { @@ -899,6 +913,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; @@ -2868,6 +2884,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; } @@ -2995,6 +3014,42 @@ 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); +} + +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; +} + /** * gtk_widget_unparent: * @widget: a #GtkWidget @@ -3046,6 +3101,9 @@ gtk_widget_unparent (GtkWidget *widget) 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 */ @@ -3103,10 +3161,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 @@ -6591,7 +6648,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]); diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 9b89f70246..7afc676351 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, diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index cdfe98b9be..acc8eca031 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -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. From ddf2a3681d8629c042e0a081b6c0a21f01b60676 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 29 Jul 2018 03:40:52 +0200 Subject: [PATCH 07/15] widget: Add a GtkWidget::root property and gtk_widget_get_root() The property is just for API completeness, the getter is meant to replace toplevel usage. --- gtk/gtkwidget.c | 40 ++++++++++++++++++++++++++++++++++++++++ gtk/gtkwidget.h | 7 +++++-- gtk/gtkwidgetprivate.h | 6 ++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 23ac98c154..96b932c4a1 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -507,6 +507,7 @@ enum { PROP_0, PROP_NAME, PROP_PARENT, + PROP_ROOT, PROP_WIDTH_REQUEST, PROP_HEIGHT_REQUEST, PROP_VISIBLE, @@ -964,6 +965,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"), @@ -2384,6 +2398,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; @@ -3031,6 +3048,8 @@ gtk_widget_root (GtkWidget *widget) 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 @@ -3048,6 +3067,8 @@ gtk_widget_unroot (GtkWidget *widget) GTK_WIDGET_GET_CLASS (widget)->unroot (widget); priv->root = NULL; + + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_ROOT]); } /** @@ -6736,6 +6757,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) diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 7afc676351..7e6b91b041 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -564,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/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index acc8eca031..14e23a16ea 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -422,6 +422,12 @@ _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) { From 2fbdd8b849b97ed8a5d3b6f69c065577efb2fb38 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 29 Jul 2018 04:11:14 +0200 Subject: [PATCH 08/15] root: Add GtkRoot:get_display vfunc And use it. --- gtk/gtkinvisible.c | 25 +++++++++---------------- gtk/gtkinvisibleprivate.h | 2 -- gtk/gtkroot.c | 20 +++++++++++++++++++- gtk/gtkroot.h | 1 + gtk/gtkrootprivate.h | 12 ++++++++++++ gtk/gtkwidgetprivate.h | 15 +++++---------- gtk/gtkwindow.c | 18 ++++++++++-------- gtk/gtkwindowprivate.h | 2 -- 8 files changed, 56 insertions(+), 39 deletions(-) create mode 100644 gtk/gtkrootprivate.h diff --git a/gtk/gtkinvisible.c b/gtk/gtkinvisible.c index 910b406376..9b66f3a9c8 100644 --- a/gtk/gtkinvisible.c +++ b/gtk/gtkinvisible.c @@ -71,9 +71,18 @@ static void gtk_invisible_get_property (GObject *object, GParamSpec *pspec); static void gtk_invisible_constructed (GObject *object); +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, @@ -210,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/gtkroot.c b/gtk/gtkroot.c index 3eecc97ec6..23674e48a1 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -19,7 +19,7 @@ #include "config.h" -#include "gtkroot.h" +#include "gtkrootprivate.h" /** * SECTION:root @@ -37,8 +37,26 @@ G_DEFINE_INTERFACE (GtkRoot, gtk_root, GTK_TYPE_WIDGET) +static GdkDisplay * +gtk_root_default_get_display (GtkRoot *self) +{ + return gdk_display_get_default (); +} + static void gtk_root_default_init (GtkRootInterface *iface) { + iface->get_display = gtk_root_default_get_display; +} + +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); } diff --git a/gtk/gtkroot.h b/gtk/gtkroot.h index e4894ee46b..e1d7ee670d 100644 --- a/gtk/gtkroot.h +++ b/gtk/gtkroot.h @@ -45,6 +45,7 @@ struct _GtkRootInterface GTypeInterface g_iface; /*< public >*/ + GdkDisplay * (* get_display) (GtkRoot *self); }; diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h new file mode 100644 index 0000000000..6d633cf2bc --- /dev/null +++ b/gtk/gtkrootprivate.h @@ -0,0 +1,12 @@ +#ifndef __GTK_ROOT_PRIVATE_H__ +#define __GTK_ROOT_PRIVATE_H__ + +#include "gtkroot.h" + +G_BEGIN_DECLS + +GdkDisplay * gtk_root_get_display (GtkRoot *root); + +G_END_DECLS + +#endif /* __GTK_ROOT_PRIVATE_H__ */ diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 14e23a16ea..0392c1bafb 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -32,7 +32,7 @@ #include "gtkcsstypesprivate.h" #include "gtkeventcontroller.h" #include "gtklistlistmodelprivate.h" -#include "gtkroot.h" +#include "gtkrootprivate.h" #include "gtksizerequestcacheprivate.h" #include "gtkwindowprivate.h" #include "gtkinvisibleprivate.h" @@ -431,17 +431,12 @@ _gtk_widget_get_root (GtkWidget *widget) 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 * diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 4eccf40b2d..2497c866c5 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -2498,9 +2498,19 @@ 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 void gtk_window_root_interface_init (GtkRootInterface *iface) { + iface->get_display = gtk_window_root_get_display; } /** @@ -9436,14 +9446,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 diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h index f57a1b377b..ce91bfa59f 100644 --- a/gtk/gtkwindowprivate.h +++ b/gtk/gtkwindowprivate.h @@ -121,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, From 446713fb8b03ec058833e2380c52637a48f9ff1c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 9 Feb 2019 22:15:32 +0100 Subject: [PATCH 09/15] root: Add gtk_root_get_surface_transform() The function isn't used yet, so this is just infrastructure. --- gtk/gtkroot.c | 25 +++++++++++++++++++++++++ gtk/gtkroot.h | 4 ++++ gtk/gtkrootprivate.h | 3 +++ gtk/gtkwindow.c | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index 23674e48a1..d94dd2e273 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -43,10 +43,20 @@ gtk_root_default_get_display (GtkRoot *self) return gdk_display_get_default (); } +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_surface_transform = gtk_root_default_get_surface_transform; } GdkDisplay * @@ -60,3 +70,18 @@ gtk_root_get_display (GtkRoot *self) return iface->get_display (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 index e1d7ee670d..b0680462a5 100644 --- a/gtk/gtkroot.h +++ b/gtk/gtkroot.h @@ -46,6 +46,10 @@ struct _GtkRootInterface /*< public >*/ GdkDisplay * (* get_display) (GtkRoot *self); + + void (* get_surface_transform) (GtkRoot *root, + int *x, + int *y); }; diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h index 6d633cf2bc..964e832ba0 100644 --- a/gtk/gtkrootprivate.h +++ b/gtk/gtkrootprivate.h @@ -7,6 +7,9 @@ G_BEGIN_DECLS GdkDisplay * gtk_root_get_display (GtkRoot *root); +void gtk_root_get_surface_transform (GtkRoot *self, + int *x, + int *y); G_END_DECLS #endif /* __GTK_ROOT_PRIVATE_H__ */ diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 2497c866c5..ba2b37c315 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -2507,10 +2507,20 @@ gtk_window_root_get_display (GtkRoot *root) return priv->display; } +static void +gtk_window_root_get_surface_transform (GtkRoot *root, + int *x, + int *y) +{ + *x = 0; + *y = 0; +} + static void gtk_window_root_interface_init (GtkRootInterface *iface) { iface->get_display = gtk_window_root_get_display; + iface->get_surface_transform = gtk_window_root_get_surface_transform; } /** From 694d7c378b23bbe79acd0a2a848c343e11fff76f Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 10 Feb 2019 01:06:39 +0100 Subject: [PATCH 10/15] root: Move the renderer to the root --- gtk/gtkroot.c | 17 +++++++++++++++++ gtk/gtkroot.h | 1 + gtk/gtkrootprivate.h | 1 + gtk/gtkwidget.c | 17 ++++------------- gtk/gtkwindow.c | 18 ++++++++++-------- gtk/gtkwindowprivate.h | 2 -- gtk/inspector/logs.c | 4 ++-- gtk/inspector/window.c | 4 ++-- 8 files changed, 37 insertions(+), 27 deletions(-) diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index d94dd2e273..1907786e95 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -43,6 +43,12 @@ 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, @@ -56,6 +62,7 @@ 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; } @@ -70,6 +77,16 @@ gtk_root_get_display (GtkRoot *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, diff --git a/gtk/gtkroot.h b/gtk/gtkroot.h index b0680462a5..e3494fcc7a 100644 --- a/gtk/gtkroot.h +++ b/gtk/gtkroot.h @@ -46,6 +46,7 @@ struct _GtkRootInterface /*< public >*/ GdkDisplay * (* get_display) (GtkRoot *self); + GskRenderer * (* get_renderer) (GtkRoot *self); void (* get_surface_transform) (GtkRoot *root, int *x, diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h index 964e832ba0..07ddc380e5 100644 --- a/gtk/gtkrootprivate.h +++ b/gtk/gtkrootprivate.h @@ -6,6 +6,7 @@ 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, diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 96b932c4a1..518a3b8c14 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -5085,18 +5085,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)) @@ -13230,11 +13218,14 @@ gtk_widget_render (GtkWidget *widget, GskRenderer *renderer; GskRenderNode *root; + 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; diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index ba2b37c315..ed9c63f938 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -2507,6 +2507,15 @@ gtk_window_root_get_display (GtkRoot *root) 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, @@ -2520,6 +2529,7 @@ 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; } @@ -10578,14 +10588,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 ce91bfa59f..de0c853f77 100644 --- a/gtk/gtkwindowprivate.h +++ b/gtk/gtkwindowprivate.h @@ -132,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); } From 86978d2654118b2781edb6ddbf2e69c87569104a Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 10 Feb 2019 06:26:41 +0100 Subject: [PATCH 11/15] widget: Store the render node in the widget's coordinate system Also require gtk_widget_snapshot() to be in the widget's coordinate system. --- gtk/gtkwidget.c | 18 +++++++++--------- gtk/gtkwidgetpaintable.c | 10 ++++++---- gtk/gtkwindow.c | 13 +++++++++++-- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 518a3b8c14..67e0e19fbd 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -13121,7 +13121,7 @@ gtk_widget_create_render_node (GtkWidget *widget, if (!GTK_IS_WINDOW (widget)) { - gtk_snapshot_offset (snapshot, margin.left, margin.top); + gtk_snapshot_offset (snapshot, - padding.left - border.left, - border.top - padding.top); gtk_css_style_snapshot_background (style, snapshot, allocation.width - margin.left - margin.right, @@ -13130,12 +13130,9 @@ gtk_widget_create_render_node (GtkWidget *widget, snapshot, allocation.width - margin.left - margin.right, allocation.height - margin.top - margin.bottom); - gtk_snapshot_offset (snapshot, - margin.left, - margin.top); + gtk_snapshot_offset (snapshot, padding.left + border.left, border.top + padding.top); } - /* 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, @@ -13156,7 +13153,8 @@ gtk_widget_create_render_node (GtkWidget *widget, snapshot, allocation.width - margin.left - margin.right, allocation.height - margin.top - margin.bottom); - gtk_snapshot_offset (snapshot, - margin.left, - margin.top); + + gtk_snapshot_offset (snapshot, padding.left + border.left, border.top + padding.top); if (opacity < 1.0) gtk_snapshot_pop (snapshot); @@ -13217,6 +13215,7 @@ gtk_widget_render (GtkWidget *widget, GtkSnapshot *snapshot; GskRenderer *renderer; GskRenderNode *root; + int x, y; if (!GTK_IS_ROOT (widget)) return; @@ -13230,7 +13229,10 @@ gtk_widget_render (GtkWidget *widget, 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) @@ -13542,14 +13544,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->transform.x; - y = priv->transform.y; + gtk_widget_get_origin_relative_to_parent (child, &x, &y); gtk_snapshot_offset (snapshot, x, y); gtk_widget_snapshot (child, snapshot); 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/gtkwindow.c b/gtk/gtkwindow.c index ed9c63f938..abe113e758 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -2521,8 +2521,17 @@ gtk_window_root_get_surface_transform (GtkRoot *root, int *x, int *y) { - *x = 0; - *y = 0; + 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 From 19ffb40b27e372bcbdd3847749248c0282159b0c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 15 Feb 2019 02:57:46 +0100 Subject: [PATCH 12/15] cssboxes: Introduce Split out the code for computing CSS boxes from given variables from the background render code. This way, it can be shared between different codebases. Also, make that code completely be contained of static inline functions. That ensures that it can be 100% inlined in cases where only parts of the rectangle are needed (like in gtk_widget_get_width() in the future). This will require some more patches to actually work, but those will follow. --- gtk/gtkcssboxesimplprivate.h | 493 +++++++++++++++++++++++++++++++++++ gtk/gtkcssboxesprivate.h | 91 +++++++ gtk/gtkrenderbackground.c | 94 +++---- 3 files changed, 621 insertions(+), 57 deletions(-) create mode 100644 gtk/gtkcssboxesimplprivate.h create mode 100644 gtk/gtkcssboxesprivate.h diff --git a/gtk/gtkcssboxesimplprivate.h b/gtk/gtkcssboxesimplprivate.h new file mode 100644 index 0000000000..0cab9750c5 --- /dev/null +++ b/gtk/gtkcssboxesimplprivate.h @@ -0,0 +1,493 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2019 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 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 . + */ + +#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) +{ + gtk_css_boxes_init_content_box (boxes, + gtk_css_node_get_style (widget->priv->cssnode), + 0, 0, + gtk_widget_get_width (widget), + gtk_widget_get_height (widget)); +} + +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 + * + * 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 . + */ + +#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/gtkrenderbackground.c b/gtk/gtkrenderbackground.c index 0be739f679..b18e14d516 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,13 @@ 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) { - GtkThemingBackground bg; + GtkCssBoxes boxes; gint idx; GtkCssValue *background_image; GtkCssValue *box_shadow; @@ -315,13 +295,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_css_boxes_init_border_box (&boxes, style, 0, 0, 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); number_of_layers = _gtk_css_array_value_get_n_values (background_image); @@ -336,25 +316,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); } From 285aba6ece1c85b774cf5e31c2475047c03ee843 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 15 Feb 2019 03:49:05 +0100 Subject: [PATCH 13/15] widget: Make width, height and transform be widget-relative Previously, those numbers stored the values relative to the margin box of the widget. Now they store values relative to the content box, thereby getting rid of the last remains of weird coordinate systems. --- gtk/a11y/gtkentryaccessible.c | 2 +- gtk/gtkcssboxesimplprivate.h | 8 +- gtk/gtkwidget.c | 148 +++++++++++----------------------- gtk/gtkwidgetprivate.h | 12 --- gtk/gtkwindow.c | 16 ++-- 5 files changed, 60 insertions(+), 126 deletions(-) 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); diff --git a/gtk/gtkcssboxesimplprivate.h b/gtk/gtkcssboxesimplprivate.h index 0cab9750c5..98c1b71e0d 100644 --- a/gtk/gtkcssboxesimplprivate.h +++ b/gtk/gtkcssboxesimplprivate.h @@ -31,11 +31,13 @@ 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 (widget->priv->cssnode), + gtk_css_node_get_style (priv->cssnode), 0, 0, - gtk_widget_get_width (widget), - gtk_widget_get_height (widget)); + priv->width, + priv->height); } static inline void diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 67e0e19fbd..fb90d3c458 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" @@ -4313,13 +4314,6 @@ gtk_widget_size_allocate (GtkWidget *widget, real_allocation.height = MAX (1, real_allocation.height); } - /* Set the widget allocation to real_allocation now, pass the smaller allocation to the vfunc */ - priv->transform.x = real_allocation.x; - priv->transform.y = real_allocation.y; - priv->width = real_allocation.width; - priv->height = real_allocation.height; - priv->baseline = baseline; - if (!alloc_needed && !size_changed && !baseline_changed) { /* Still have to move the window... */ @@ -4342,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; @@ -4354,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, @@ -4457,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->transform.x; - *origin_y = priv->transform.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; } /** @@ -11207,14 +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->x = priv->transform.x; - allocation->y = priv->transform.y; - allocation->width = priv->width; - allocation->height = priv->height; + 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); } /** @@ -11296,18 +11287,12 @@ gtk_widget_pick (GtkWidget *widget, case GTK_OVERFLOW_HIDDEN: { - GtkBorder margin, border, padding; - GtkCssStyle *style; + GtkCssBoxes boxes; - style = gtk_css_node_get_style (priv->cssnode); - get_box_margin (style, &margin); - get_box_border (style, &border); - get_box_padding (style, &padding); + gtk_css_boxes_init (&boxes, widget); - if (x < -padding.left || - y < -padding.top || - x >= priv->width - margin.left - margin.right - border.left - border.right - padding.left || - y >= priv->height - margin.top - margin.bottom - border.top - border.bottom - padding.top) + if (!graphene_rect_contains_point (gtk_css_boxes_get_padding_rect (&boxes), + &GRAPHENE_POINT_INIT (x, y))) return NULL; } break; @@ -11339,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->width - margin.left - margin.right; - alloc.height = priv->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; } @@ -11387,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->width; + gtk_css_boxes_init (&boxes, widget); + + return gtk_css_boxes_get_margin_rect (&boxes)->size.width; } /** @@ -11405,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->height; + gtk_css_boxes_init (&boxes, widget); + + return gtk_css_boxes_get_margin_rect (&boxes)->size.height; } /** @@ -13028,35 +13004,23 @@ 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, + 0, priv->baseline, priv->width, 1); gtk_snapshot_append_color (snapshot, &red, @@ -13102,7 +13066,7 @@ gtk_widget_create_render_node (GtkWidget *widget, snapshot = gtk_snapshot_new_with_parent (parent_snapshot); - _gtk_widget_get_allocation (widget, &allocation); + gtk_widget_get_allocation (widget, &allocation); gtk_snapshot_push_debug (snapshot, "RenderNode for %s %p @ %d x %d", G_OBJECT_TYPE_NAME (widget), widget, @@ -13741,20 +13705,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->width - - margin.left - margin.right - - border.left - border.right - - padding.left - padding.right; + return priv->width; } /** @@ -13771,18 +13725,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->height - - margin.top - margin.bottom - - border.top - border.bottom - - padding.top - padding.bottom; + return priv->height; } diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 0392c1bafb..35753b6736 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -460,18 +460,6 @@ _gtk_widget_get_surface (GtkWidget *widget) return widget->priv->surface; } -static inline void -_gtk_widget_get_allocation (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkWidgetPrivate *priv = widget->priv; - - allocation->x = priv->transform.x; - allocation->y = priv->transform.y; - allocation->width = priv->width; - allocation->height = priv->height; -} - static inline GtkWidget * _gtk_widget_get_prev_sibling (GtkWidget *widget) { diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index abe113e758..ab5061d5f4 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1728,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); @@ -5271,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. @@ -6063,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; @@ -6449,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) { @@ -6827,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)) { @@ -7048,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; @@ -7428,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); @@ -7974,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; From 7ad0f7fc525bf01b21532a98069f4b7124d65a86 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 15 Feb 2019 04:06:22 +0100 Subject: [PATCH 14/15] css: Mark some hot functions as G_GNUC_PURE By doing that, gcc will generate code that avoids calling these functions when not needed. --- gtk/gtkcssnodeprivate.h | 30 +++++++++++++++--------------- gtk/gtkcssnumbervalueprivate.h | 6 +++--- gtk/gtkcssrgbavalueprivate.h | 2 +- gtk/gtkcssstyleprivate.h | 6 +++--- 4 files changed, 22 insertions(+), 22 deletions(-) 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, From c44c44ee2510415c3b796e973ac3f525e5d512b9 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 15 Feb 2019 06:15:50 +0100 Subject: [PATCH 15/15] css: Pass boxes to the render functions Instead of style + rect_of_one_box, pass the new GtkCssBoxes object. This has the nice side effect that when drawing background + border + outline, we only compute all the boxes we need once. --- gtk/gtkrenderbackground.c | 27 ++--- gtk/gtkrenderbackgroundprivate.h | 7 +- gtk/gtkrenderborder.c | 177 +++++++++++-------------------- gtk/gtkrenderborderprivate.h | 15 +-- gtk/gtksnapshot.c | 33 +++--- gtk/gtkwidget.c | 45 ++------ 6 files changed, 107 insertions(+), 197 deletions(-) diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c index b18e14d516..32e0305cab 100644 --- a/gtk/gtkrenderbackground.c +++ b/gtk/gtkrenderbackground.c @@ -270,12 +270,9 @@ gtk_theming_background_snapshot_layer (GtkCssBoxes *bg, } void -gtk_css_style_snapshot_background (GtkCssStyle *style, - GtkSnapshot *snapshot, - gdouble width, - gdouble height) +gtk_css_style_snapshot_background (GtkCssBoxes *boxes, + GtkSnapshot *snapshot) { - GtkCssBoxes boxes; gint idx; GtkCssValue *background_image; GtkCssValue *box_shadow; @@ -284,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) && @@ -295,15 +292,13 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, _gtk_css_shadows_value_is_none (box_shadow)) return; - gtk_css_boxes_init_border_box (&boxes, style, 0, 0, width, height); - gtk_snapshot_push_debug (snapshot, "CSS background"); gtk_css_shadows_value_snapshot_outset (box_shadow, snapshot, - gtk_css_boxes_get_border_box (&boxes)); + 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); @@ -316,25 +311,25 @@ gtk_css_style_snapshot_background (GtkCssStyle *style, } if (!gdk_rgba_is_clear (bg_color)) - gtk_theming_background_snapshot_color (&boxes, 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 (&boxes, idx, snapshot); + gtk_theming_background_snapshot_layer (boxes, idx, snapshot); } else { gtk_snapshot_pop (snapshot); - gtk_theming_background_snapshot_layer (&boxes, idx, snapshot); + gtk_theming_background_snapshot_layer (boxes, idx, snapshot); gtk_snapshot_pop (snapshot); } } gtk_css_shadows_value_snapshot_inset (box_shadow, snapshot, - gtk_css_boxes_get_padding_box (&boxes)); + 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 #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/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/gtkwidget.c b/gtk/gtkwidget.c index fb90d3c458..6f871e9ab0 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -13053,72 +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, - padding.left - border.left, - border.top - padding.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, padding.left + border.left, border.top + padding.top); + gtk_css_style_snapshot_background (&boxes, snapshot); + gtk_css_style_snapshot_border (&boxes, snapshot); } 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, padding.left + border.left, border.top + padding.top); + gtk_css_style_snapshot_outline (&boxes, snapshot); if (opacity < 1.0) gtk_snapshot_pop (snapshot);