diff --git a/gtk/gtknative.c b/gtk/gtknative.c index 0154781379..aafdbb163e 100644 --- a/gtk/gtknative.c +++ b/gtk/gtknative.c @@ -19,10 +19,17 @@ #include "config.h" +#include + +#include "gtkintl.h" + +#include "gtkcssboxesimplprivate.h" +#include "gtkcsscolorvalueprivate.h" +#include "gtkcsscornervalueprivate.h" +#include "gtkcssnodeprivate.h" +#include "gtkcssshadowvalueprivate.h" #include "gtknativeprivate.h" #include "gtkwidgetprivate.h" -#include "gtkintl.h" -#include "gtkcssnodeprivate.h" #include "gdk/gdksurfaceprivate.h" @@ -297,3 +304,181 @@ gtk_native_queue_relayout (GtkNative *self) gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE); gdk_surface_request_layout (surface); } + +static void +corner_rect (const GtkCssValue *value, + cairo_rectangle_int_t *rect) +{ + rect->width = _gtk_css_corner_value_get_x (value, 100); + rect->height = _gtk_css_corner_value_get_y (value, 100); +} + +static void +subtract_decoration_corners_from_region (cairo_region_t *region, + cairo_rectangle_int_t *extents, + const GtkCssStyle *style) +{ + cairo_rectangle_int_t rect; + + corner_rect (style->border->border_top_left_radius, &rect); + rect.x = extents->x; + rect.y = extents->y; + cairo_region_subtract_rectangle (region, &rect); + + corner_rect (style->border->border_top_right_radius, &rect); + rect.x = extents->x + extents->width - rect.width; + rect.y = extents->y; + cairo_region_subtract_rectangle (region, &rect); + + corner_rect (style->border->border_bottom_left_radius, &rect); + rect.x = extents->x; + rect.y = extents->y + extents->height - rect.height; + cairo_region_subtract_rectangle (region, &rect); + + corner_rect (style->border->border_bottom_right_radius, &rect); + rect.x = extents->x + extents->width - rect.width; + rect.y = extents->y + extents->height - rect.height; + cairo_region_subtract_rectangle (region, &rect); +} + +static int +get_translucent_border_edge (const GtkCssValue *color, + const GtkCssValue *border_color, + const GtkCssValue *border_width) +{ + if (border_color == NULL) + border_color = color; + + if (!gdk_rgba_is_opaque (gtk_css_color_value_get_rgba (border_color))) + return round (_gtk_css_number_value_get (border_width, 100)); + + return 0; +} + +static void +get_translucent_border_width (GtkWidget *widget, + GtkBorder *border) +{ + GtkCssNode *css_node = gtk_widget_get_css_node (widget); + GtkCssStyle *style = gtk_css_node_get_style (css_node); + + border->top = get_translucent_border_edge (style->core->color, + style->border->border_top_color, + style->border->border_top_width); + border->bottom = get_translucent_border_edge (style->core->color, + style->border->border_bottom_color, + style->border->border_bottom_width); + border->left = get_translucent_border_edge (style->core->color, + style->border->border_left_color, + style->border->border_left_width); + border->right = get_translucent_border_edge (style->core->color, + style->border->border_right_color, + style->border->border_right_width); +} + +static gboolean +get_opaque_rect (GtkWidget *widget, + const GtkCssStyle *style, + cairo_rectangle_int_t *rect) +{ + gboolean is_opaque = gdk_rgba_is_opaque (gtk_css_color_value_get_rgba (style->background->background_color)); + + if (is_opaque && gtk_widget_get_opacity (widget) < 1.0) + is_opaque = FALSE; + + if (is_opaque) + { + const graphene_rect_t *border_rect; + GtkCssBoxes css_boxes; + GtkBorder border; + + gtk_css_boxes_init (&css_boxes, widget); + border_rect = gtk_css_boxes_get_border_rect (&css_boxes); + get_translucent_border_width (widget, &border); + + rect->x = border_rect->origin.x + border.left; + rect->y = border_rect->origin.y + border.top; + rect->width = border_rect->size.width - border.left - border.right; + rect->height = border_rect->size.height - border.top - border.bottom; + } + + return is_opaque; +} + +static void +get_shadow_width (GtkWidget *widget, + GtkBorder *shadow_width, + int resize_handle_size) +{ + GtkCssNode *css_node = gtk_widget_get_css_node (widget); + const GtkCssStyle *style = gtk_css_node_get_style (css_node); + + gtk_css_shadow_value_get_extents (style->background->box_shadow, shadow_width); + + shadow_width->left = MAX (shadow_width->left, resize_handle_size); + shadow_width->top = MAX (shadow_width->top, resize_handle_size); + shadow_width->bottom = MAX (shadow_width->bottom, resize_handle_size); + shadow_width->right = MAX (shadow_width->right, resize_handle_size); +} + +void +gtk_native_update_opaque_region (GtkNative *native, + GtkWidget *contents, + gboolean subtract_decoration_corners, + gboolean subtract_shadow, + int resize_handle_size) +{ + cairo_rectangle_int_t rect; + cairo_region_t *opaque_region = NULL; + const GtkCssStyle *style; + GtkCssNode *css_node; + GdkSurface *surface; + GtkBorder shadow; + + g_return_if_fail (GTK_IS_NATIVE (native)); + g_return_if_fail (!contents || GTK_IS_WIDGET (contents)); + + if (contents == NULL) + contents = GTK_WIDGET (native); + + if (!_gtk_widget_get_realized (GTK_WIDGET (native)) || + !_gtk_widget_get_realized (contents)) + return; + + css_node = gtk_widget_get_css_node (contents); + + if (subtract_shadow) + get_shadow_width (contents, &shadow, resize_handle_size); + else + shadow = (GtkBorder) {0, 0, 0, 0}; + + surface = gtk_native_get_surface (native); + style = gtk_css_node_get_style (css_node); + + if (get_opaque_rect (contents, style, &rect)) + { + double native_x, native_y; + + gtk_native_get_surface_transform (native, &native_x, &native_y); + rect.x += native_x; + rect.y += native_y; + + if (contents != GTK_WIDGET (native)) + { + double contents_x, contents_y; + + gtk_widget_translate_coordinates (contents, GTK_WIDGET (native), 0, 0, &contents_x, &contents_y); + rect.x += contents_x; + rect.y += contents_y; + } + + opaque_region = cairo_region_create_rectangle (&rect); + + if (subtract_decoration_corners) + subtract_decoration_corners_from_region (opaque_region, &rect, style); + } + + gdk_surface_set_opaque_region (surface, opaque_region); + + cairo_region_destroy (opaque_region); +} diff --git a/gtk/gtknativeprivate.h b/gtk/gtknativeprivate.h index 021402dcbf..d00ebc50cd 100644 --- a/gtk/gtknativeprivate.h +++ b/gtk/gtknativeprivate.h @@ -29,6 +29,11 @@ struct _GtkNativeInterface }; void gtk_native_queue_relayout (GtkNative *native); +void gtk_native_update_opaque_region (GtkNative *native, + GtkWidget *contents, + gboolean subtract_decoration_corners, + gboolean subtract_shadow, + int resize_handle_size); G_END_DECLS diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 3c16e89312..2f4a33493e 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -957,6 +957,8 @@ gtk_popover_realize (GtkWidget *widget) priv->renderer = gsk_renderer_new_for_surface (priv->surface); gtk_native_realize (GTK_NATIVE (popover)); + + gtk_native_update_opaque_region (GTK_NATIVE (popover), priv->contents_widget, TRUE, TRUE, 0); } static void @@ -1392,6 +1394,9 @@ gtk_popover_update_shape (GtkPopover *popover) gdk_surface_set_input_region (priv->surface, region); cairo_region_destroy (region); } + + if (_gtk_widget_get_realized (GTK_WIDGET (popover))) + gtk_native_update_opaque_region (GTK_NATIVE (popover), priv->contents_widget, TRUE, TRUE, 0); } static int diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index c36d16ca34..d9856d8b5e 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -4055,112 +4055,39 @@ out: } static void -corner_rect (cairo_rectangle_int_t *rect, - const GtkCssValue *value) -{ - rect->width = _gtk_css_corner_value_get_x (value, 100); - rect->height = _gtk_css_corner_value_get_y (value, 100); -} - -static void -subtract_decoration_corners_from_region (cairo_region_t *region, - cairo_rectangle_int_t *extents, - GtkCssStyle *style, - GtkWindow *window) +update_opaque_region (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - cairo_rectangle_int_t rect; + gboolean subtract_decoration_corners; + gboolean subtract_shadow; - if (!priv->client_decorated || - !priv->decorated || - priv->fullscreen || - priv->maximized) - return; + subtract_decoration_corners = (priv->client_decorated && + priv->decorated && + !priv->fullscreen && + !priv->maximized); + subtract_shadow = (priv->client_decorated && + priv->decorated && + priv->use_client_shadow && + !priv->maximized && + !priv->fullscreen); - corner_rect (&rect, style->border->border_top_left_radius); - rect.x = extents->x; - rect.y = extents->y; - cairo_region_subtract_rectangle (region, &rect); - - corner_rect (&rect, style->border->border_top_right_radius); - rect.x = extents->x + extents->width - rect.width; - rect.y = extents->y; - cairo_region_subtract_rectangle (region, &rect); - - corner_rect (&rect, style->border->border_bottom_left_radius); - rect.x = extents->x; - rect.y = extents->y + extents->height - rect.height; - cairo_region_subtract_rectangle (region, &rect); - - corner_rect (&rect, style->border->border_bottom_right_radius); - rect.x = extents->x + extents->width - rect.width; - rect.y = extents->y + extents->height - rect.height; - cairo_region_subtract_rectangle (region, &rect); -} - -static void -update_opaque_region (GtkWindow *window, - const GtkBorder *shadow) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWidget *widget = GTK_WIDGET (window); - cairo_region_t *opaque_region; - gboolean is_opaque = FALSE; - GtkCssStyle *style; - - if (!_gtk_widget_get_realized (widget)) - return; - - style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (window))); - - is_opaque = gdk_rgba_is_opaque (gtk_css_color_value_get_rgba (style->background->background_color)); - - if (is_opaque && gtk_widget_get_opacity (widget) < 1.0) - is_opaque = FALSE; - - if (is_opaque) - { - cairo_rectangle_int_t rect; - GtkCssBoxes css_boxes; - const graphene_rect_t *border_rect; - double native_x, native_y; - - gtk_native_get_surface_transform (GTK_NATIVE (window), &native_x, &native_y); - - gtk_css_boxes_init (&css_boxes, widget); - border_rect = gtk_css_boxes_get_border_rect (&css_boxes); - - rect.x = native_x + border_rect->origin.x; - rect.y = native_y + border_rect->origin.y; - rect.width = border_rect->size.width; - rect.height = border_rect->size.height; - - opaque_region = cairo_region_create_rectangle (&rect); - - subtract_decoration_corners_from_region (opaque_region, &rect, style, window); - } - else - { - opaque_region = NULL; - } - - gdk_surface_set_opaque_region (priv->surface, opaque_region); - - cairo_region_destroy (opaque_region); + gtk_native_update_opaque_region (GTK_NATIVE (window), + NULL, + subtract_decoration_corners, + subtract_shadow, + RESIZE_HANDLE_SIZE); } static void update_realized_window_properties (GtkWindow *window) { GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkBorder shadow; GdkRectangle rect; GtkCssBoxes css_boxes; const graphene_rect_t *border_rect; double native_x, native_y; - get_shadow_width (window, &shadow); - update_opaque_region (window, &shadow); + update_opaque_region (window); if (!priv->client_decorated || !priv->use_client_shadow) return; @@ -5227,13 +5154,7 @@ gtk_window_css_changed (GtkWidget *widget, if (!_gtk_widget_get_alloc_needed (widget) && (change == NULL || gtk_css_style_change_changes_property (change, GTK_CSS_PROPERTY_BACKGROUND_COLOR))) - { - GtkBorder shadow; - - get_shadow_width (window, &shadow); - - update_opaque_region (window, &shadow); - } + update_opaque_region (window); } /*