window: rework the CSD theming layer

Instead of having three different boxes and style classes, we can just
get away with the regular background box, plus a window-frame, which
contains the external frame, together with the window drop shadows.

GtkWindow now has special code to ensure the backing actual window is
allocated big enough to accomodate the shadows (using the shadow size
calculations introduced in the previous commit). We also use the margin
value to determine the size of the invisible borders (which can then be
different than the shadow).
This commit is contained in:
Cosimo Cecchi 2013-04-22 17:28:23 -04:00
parent a44d6816d3
commit 7bbbb01ff5

View File

@ -35,6 +35,7 @@
#include "gtkwindowprivate.h"
#include "gtkaccelgroupprivate.h"
#include "gtkbindings.h"
#include "gtkcssshadowsvalueprivate.h"
#include "gtkkeyhash.h"
#include "gtkmain.h"
#include "gtkmnemonichash.h"
@ -6067,68 +6068,65 @@ set_grip_position (GtkWindow *window)
}
static void
get_decoration_borders (GtkWidget *widget,
GtkBorder *window_border,
GtkBorder *outer_border)
sum_borders (GtkBorder *one,
GtkBorder *two)
{
GtkStyleContext *context;
GtkStateFlags state;
GdkWindow *window;
gboolean maximized = FALSE;
const GtkBorder empty = { 0 };
GtkBorder outer;
context = gtk_widget_get_style_context (widget);
state = gtk_style_context_get_state (context);
window = gtk_widget_get_window (widget);
if (window != NULL)
maximized = gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED;
if (window_border != NULL)
{
if (maximized)
{
*window_border = empty;
}
else
{
gtk_style_context_save (context);
gtk_style_context_add_class (context, "window-border");
gtk_style_context_get_border (context, state, window_border);
gtk_style_context_restore (context);
}
}
if (window_border != NULL || outer_border != NULL)
{
if (maximized)
{
outer = empty;
}
else
{
gtk_style_context_save (context);
gtk_style_context_add_class (context, "window-outer-border");
gtk_style_context_get_border (context, state, &outer);
gtk_style_context_restore (context);
}
if (outer_border != NULL)
{
*outer_border = outer;
}
else
{
window_border->left += outer.left;
window_border->right += outer.right;
window_border->top += outer.top;
window_border->bottom += outer.bottom;
}
}
one->top += two->top;
one->right += two->right;
one->bottom += two->bottom;
one->left += two->left;
}
static void
update_border_windows (GtkWindow *window, GtkBorder *border)
get_decoration_size (GtkWidget *widget,
GtkBorder *decorations)
{
GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
GtkBorder border = { 0 };
GtkBorder margin;
GtkStyleContext *context;
GtkStateFlags state;
GtkCssValue *shadows;
*decorations = border;
if (!priv->client_decorated)
return;
if (gtk_window_get_maximized (GTK_WINDOW (widget)))
return;
state = gtk_widget_get_state_flags (widget);
context = gtk_widget_get_style_context (widget);
gtk_style_context_save (context);
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
gtk_style_context_add_class (context, "window-frame");
/* Always sum border + padding */
gtk_style_context_get_border (context, state, decorations);
gtk_style_context_get_padding (context, state, &border);
sum_borders (decorations, &border);
/* Calculate the size of the drop shadows ... */
shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW);
_gtk_css_shadows_value_get_extents (shadows, &border);
/* ... and compare it to the margin size, which we use for resize grips */
gtk_style_context_get_margin (context, state, &margin);
border.top = MAX (border.top, margin.top);
border.right = MAX (border.right, margin.right);
border.bottom = MAX (border.bottom, margin.bottom);
border.left = MAX (border.left, margin.left);
sum_borders (decorations, &border);
gtk_style_context_restore (context);
}
static void
update_border_windows (GtkWindow *window)
{
GtkWidget *widget = (GtkWidget *)window;
GtkWindowPrivate *priv = window->priv;
@ -6137,10 +6135,20 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
cairo_region_t *region;
cairo_rectangle_int_t rect;
gint width, height;
GtkBorder border;
GtkStyleContext *context;
if (priv->border_window[0] == NULL)
return;
context = gtk_widget_get_style_context (widget);
gtk_style_context_save (context);
gtk_style_context_add_class (context, "window-frame");
gtk_style_context_get_margin (context,
gtk_widget_get_state_flags (widget),
&border);
gtk_style_context_restore (context);
if (!priv->resizable || gtk_window_get_maximized (window))
{
resize_h = resize_v = FALSE;
@ -6165,31 +6173,31 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
"decoration-resize-handle", &handle,
NULL);
width = gtk_widget_get_allocated_width (widget) - (border->left + border->right);
height = gtk_widget_get_allocated_height (widget) - (border->top + border->bottom);
width = gtk_widget_get_allocated_width (widget) - (border.left + border.right);
height = gtk_widget_get_allocated_height (widget) - (border.top + border.bottom);
if (resize_h && resize_v)
{
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST],
0, 0,
border->left + handle, border->top + handle);
border.left + handle, border.top + handle);
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST],
border->left + width - handle, 0,
border->right + handle, border->top + handle);
border.left + width - handle, 0,
border.right + handle, border.top + handle);
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST],
0, border->top + height - handle,
border->left + handle, border->bottom + handle);
0, border.top + height - handle,
border.left + handle, border.bottom + handle);
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST],
border->left + width - handle, border->top + height - handle,
border->right + handle, border->bottom + handle);
border.left + width - handle, border.top + height - handle,
border.right + handle, border.bottom + handle);
rect.x = 0;
rect.y = 0;
rect.width = border->left + handle;
rect.height = border->top + handle;
rect.width = border.left + handle;
rect.height = border.top + handle;
region = cairo_region_create_rectangle (&rect);
rect.x = border->left;
rect.y = border->top;
rect.x = border.left;
rect.y = border.top;
rect.width = handle;
rect.height = handle;
cairo_region_subtract_rectangle (region, &rect);
@ -6199,11 +6207,11 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
rect.x = 0;
rect.y = 0;
rect.width = border->right + handle;
rect.height = border->top + handle;
rect.width = border.right + handle;
rect.height = border.top + handle;
region = cairo_region_create_rectangle (&rect);
rect.x = 0;
rect.y = border->top;
rect.y = border.top;
rect.width = handle;
rect.height = handle;
cairo_region_subtract_rectangle (region, &rect);
@ -6213,10 +6221,10 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
rect.x = 0;
rect.y = 0;
rect.width = border->left + handle;
rect.height = border->bottom + handle;
rect.width = border.left + handle;
rect.height = border.bottom + handle;
region = cairo_region_create_rectangle (&rect);
rect.x = border->left;
rect.x = border.left;
rect.y = 0;
rect.width = handle;
rect.height = handle;
@ -6227,8 +6235,8 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
rect.x = 0;
rect.y = 0;
rect.width = border->right + handle;
rect.height = border->bottom + handle;
rect.width = border.right + handle;
rect.height = border.bottom + handle;
region = cairo_region_create_rectangle (&rect);
rect.x = 0;
rect.y = 0;
@ -6258,21 +6266,21 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
if (resize_h)
{
x = border->left + handle;
x = border.left + handle;
w = width - 2 * handle;
}
else
{
x = 0;
w = width + border->left + border->right;
w = width + border.left + border.right;
}
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH],
x, 0,
w, border->top);
w, border.top);
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH],
x, border->top + height,
w, border->bottom);
x, border.top + height,
w, border.bottom);
gdk_window_show (priv->border_window[GDK_WINDOW_EDGE_NORTH]);
gdk_window_show (priv->border_window[GDK_WINDOW_EDGE_SOUTH]);
@ -6289,22 +6297,22 @@ update_border_windows (GtkWindow *window, GtkBorder *border)
if (resize_v)
{
y = border->top + handle;
y = border.top + handle;
h = height - 2 * handle;
}
else
{
y = 0;
h = height + border->top + border->bottom;
h = height + border.top + border.bottom;
}
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST],
0, y,
border->left, h);
border.left, h);
gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST],
border->left + width, y,
border->right, h);
border.left + width, y,
border.right, h);
gdk_window_show (priv->border_window[GDK_WINDOW_EDGE_WEST]);
gdk_window_show (priv->border_window[GDK_WINDOW_EDGE_EAST]);
@ -6352,7 +6360,7 @@ _gtk_window_set_allocation (GtkWindow *window,
gtk_widget_set_allocation (widget, allocation);
get_decoration_borders (widget, &window_border, NULL);
get_decoration_size (widget, &window_border);
border_width = gtk_container_get_border_width (GTK_CONTAINER (window));
child_allocation.x = 0;
@ -6407,7 +6415,7 @@ _gtk_window_set_allocation (GtkWindow *window,
{
update_grip_visibility (window);
set_grip_position (window);
update_border_windows (window, &window_border);
update_border_windows (window);
}
}
@ -6554,6 +6562,7 @@ gtk_window_style_updated (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
GtkWindowPrivate *priv = window->priv;
GdkRGBA transparent = { 0.0, 0.0, 0.0, 0.0 };
GdkRectangle rect;
GTK_WIDGET_CLASS (gtk_window_parent_class)->style_updated (widget);
@ -6566,6 +6575,13 @@ gtk_window_style_updated (GtkWidget *widget)
set_grip_shape (window);
}
if (gtk_widget_get_realized (widget))
{
gdk_window_set_background_rgba (gtk_widget_get_window (widget),
&transparent);
gtk_widget_queue_resize (widget);
}
}
static void
@ -6783,12 +6799,10 @@ gtk_window_get_resize_grip_area (GtkWindow *window,
g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
if (!window->priv->has_resize_grip)
if (!priv->has_resize_grip)
return FALSE;
if (priv->client_decorated)
get_decoration_borders (widget, &window_border, NULL);
get_decoration_size (widget, &window_border);
gtk_widget_get_allocation (widget, &allocation);
gtk_widget_style_get (widget,
@ -7449,7 +7463,7 @@ gtk_window_get_preferred_width (GtkWidget *widget,
if (priv->decorated &&
!priv->fullscreen)
{
get_decoration_borders (widget, &window_border, NULL);
get_decoration_size (widget, &window_border);
if (priv->title_box != NULL)
gtk_widget_get_preferred_width (priv->title_box,
@ -7498,7 +7512,7 @@ gtk_window_get_preferred_width_for_height (GtkWidget *widget,
if (priv->decorated &&
!priv->fullscreen)
{
get_decoration_borders (widget, &window_border, NULL);
get_decoration_size (widget, &window_border);
if (priv->title_box != NULL)
gtk_widget_get_preferred_width_for_height (priv->title_box,
@ -7551,7 +7565,7 @@ gtk_window_get_preferred_height (GtkWidget *widget,
if (priv->decorated &&
!priv->fullscreen)
{
get_decoration_borders (widget, &window_border, NULL);
get_decoration_size (widget, &window_border);
if (priv->title_box != NULL)
gtk_widget_get_preferred_height (priv->title_box,
@ -7602,7 +7616,7 @@ gtk_window_get_preferred_height_for_width (GtkWidget *widget,
if (priv->decorated &&
!priv->fullscreen)
{
get_decoration_borders (widget, &window_border, NULL);
get_decoration_size (widget, &window_border);
if (priv->title_box != NULL)
gtk_widget_get_preferred_height_for_width (priv->title_box,
@ -8827,17 +8841,14 @@ gtk_window_draw (GtkWidget *widget,
GtkStyleContext *context;
gboolean ret = FALSE;
GtkAllocation allocation;
GtkBorder inner_border = { 0 };
GtkBorder outer_border = { 0 };
GtkBorder window_border;
gint title_height;
context = gtk_widget_get_style_context (widget);
get_decoration_size (widget, &window_border);
gtk_widget_get_allocation (widget, &allocation);
if (priv->client_decorated)
get_decoration_borders (widget, &inner_border, &outer_border);
if (!gtk_widget_get_app_paintable (widget) &&
gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
{
@ -8848,25 +8859,22 @@ gtk_window_draw (GtkWidget *widget,
{
gtk_style_context_save (context);
gtk_style_context_add_class (context, "window-border");
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND);
gtk_style_context_add_class (context, "window-frame");
gtk_render_background (context, cr,
inner_border.left + outer_border.left,
inner_border.top + outer_border.top,
window_border.left, window_border.top,
allocation.width -
(inner_border.left + inner_border.right +
outer_border.left + outer_border.right),
(window_border.left + window_border.right),
allocation.height -
(inner_border.top + inner_border.bottom +
outer_border.top + outer_border.bottom));
(window_border.top + window_border.bottom));
gtk_render_frame (context, cr,
outer_border.left,
outer_border.top,
allocation.width - (outer_border.left + outer_border.right),
allocation.height - (outer_border.top + outer_border.bottom));
gtk_style_context_remove_class (context, "window-border");
gtk_style_context_add_class (context, "window-outer-border");
gtk_render_frame (context, cr,
0, 0, allocation.width, allocation.height);
window_border.left, window_border.top,
allocation.width -
(window_border.left + window_border.right),
allocation.height -
(window_border.top + window_border.bottom));
gtk_style_context_restore (context);
}
@ -8874,20 +8882,23 @@ gtk_window_draw (GtkWidget *widget,
title_height = gtk_widget_get_allocated_height (priv->title_box);
else
title_height = 0;
gtk_style_context_save (context);
gtk_style_context_add_class (context, "window-content");
gtk_render_background (context, cr,
inner_border.left + outer_border.left,
inner_border.top + outer_border.top +
title_height,
window_border.left,
window_border.top + title_height,
allocation.width -
(inner_border.left + inner_border.right +
outer_border.left + outer_border.right),
(window_border.left + window_border.right),
allocation.height -
(inner_border.top + inner_border.bottom +
outer_border.top + outer_border.bottom +
(window_border.top + window_border.bottom +
title_height));
gtk_style_context_restore (context);
gtk_render_frame (context, cr,
window_border.left,
window_border.top + title_height,
allocation.width -
(window_border.left + window_border.right),
allocation.height -
(window_border.top + window_border.bottom +
title_height));
}
if (GTK_WIDGET_CLASS (gtk_window_parent_class)->draw)