[gtk+/client-side-decorations] Drop shadows
- From: Cody Russell <bratsche src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gtk+/client-side-decorations] Drop shadows
- Date: Mon, 30 Nov 2009 15:37:14 +0000 (UTC)
commit 94e0336e63bb90fb350d182b1ca38fd2f7bda5ef
Author: Cody Russell <bratsche gnome org>
Date: Mon Nov 30 09:36:27 2009 -0600
Drop shadows
gtk/gtkstyle.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
gtk/gtkwindow.c | 188 +++++++++++++++++++++++++++++----------
2 files changed, 402 insertions(+), 53 deletions(-)
---
diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c
index 929aadb..0b60b2e 100644
--- a/gtk/gtkstyle.c
+++ b/gtk/gtkstyle.c
@@ -26,6 +26,7 @@
#include "config.h"
#include <math.h>
+#include <pixman.h>
#include <stdlib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>
@@ -3464,6 +3465,244 @@ option_menu_get_props (GtkWidget *widget,
*indicator_spacing = default_option_indicator_spacing;
}
+/* gaussian blur kernel */
+pixman_fixed_t *
+create_blur_kernel (gint radius,
+ gint *length)
+{
+ const gdouble radiusf = fabs (radius) + 1.0f;
+ const gdouble sigma = sqrt (-(radiusf * radiusf) / (2.0f * log (1.0f / 255.0f)));
+ const gdouble scale2 = 2.0f * sigma * sigma;
+ const gdouble scale1 = 1.0f / (G_PI * scale2);
+ const gint size = 2 * radius + 1;
+ const gint n_params = size * size;
+ pixman_fixed_t *params;
+ gdouble *tmp;
+ gdouble sum;
+ gint x;
+ gint y;
+ gint i;
+
+ tmp = g_newa (double, n_params);
+
+ for (i = 0, sum = 0, x = -radius; x <= radius; ++x)
+ {
+ for (y = -radius; y <= radius; ++y, ++i)
+ {
+ const gdouble u = x * x;
+ const gdouble v = y * y;
+
+ tmp[i] = scale1 * exp (-(u + v) / scale2);
+
+ sum += tmp[i];
+ }
+ }
+
+ params = g_new (pixman_fixed_t, n_params + 2);
+
+ params[0] = pixman_int_to_fixed (size);
+ params[1] = pixman_int_to_fixed (size);
+
+ for (i = 0; i < n_params; ++i)
+ params[2 + i] = pixman_double_to_fixed (tmp[i] / sum);
+
+ if (length)
+ *length = n_params + 2;
+
+ return params;
+}
+
+static void
+blur_image_surface (cairo_surface_t *surface,
+ gint radius)
+{
+ cairo_format_t format;
+ pixman_fixed_t *params = NULL;
+ gint n_params;
+ pixman_image_t *src;
+ gint w;
+ gint h;
+ gint s;
+ gpointer p;
+
+ if (radius == 0 ||
+ cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS ||
+ cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE)
+ {
+ return;
+ }
+
+ format = cairo_image_surface_get_format (surface);
+ if (format != CAIRO_FORMAT_A8 &&
+ format != CAIRO_FORMAT_RGB24 &&
+ format != CAIRO_FORMAT_ARGB32)
+ {
+ return;
+ }
+
+ cairo_surface_flush (surface);
+
+ w = cairo_image_surface_get_width (surface);
+ h = cairo_image_surface_get_height (surface);
+ s = cairo_image_surface_get_stride (surface);
+
+ p = cairo_image_surface_get_data (surface);
+ src = pixman_image_create_bits (PIXMAN_a8r8g8b8, w, h, p, s);
+
+ params = create_blur_kernel (radius, &n_params);
+ pixman_image_set_filter (src,
+ PIXMAN_FILTER_CONVOLUTION,
+ params,
+ n_params);
+ g_free (params);
+
+ pixman_image_composite (PIXMAN_OP_SRC,
+ src,
+ NULL,
+ src,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ w, h);
+
+ pixman_image_unref (src);
+
+ cairo_surface_mark_dirty (surface);
+}
+
+typedef struct _TileData
+{
+ guchar *data;
+ cairo_format_t format;
+ gint width;
+ gint height;
+ gint stride;
+} TileData;
+
+/* XXX - leak */
+static TileData *tile = NULL;
+
+static void
+paint_window_shadow (cairo_t *cr,
+ gint width,
+ gint height,
+ gint shadow_radius,
+ gint corner_radius)
+{
+ cairo_surface_t *tmp_surface = NULL;
+ cairo_surface_t *new_surface = NULL;
+ cairo_pattern_t *pattern = NULL;
+ cairo_t *cr_surf = NULL;
+ cairo_matrix_t matrix;
+
+ if (!tile)
+ {
+ guchar *data;
+
+ tmp_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ 4 * shadow_radius,
+ 4 * shadow_radius);
+ if (cairo_surface_status (tmp_surface) != CAIRO_STATUS_SUCCESS)
+ return;
+
+ cr_surf = cairo_create (tmp_surface);
+ if (cairo_status (cr_surf) != CAIRO_STATUS_SUCCESS)
+ {
+ cairo_surface_destroy (tmp_surface);
+ return;
+ }
+
+ cairo_scale (cr_surf, 1.0f, 1.0f);
+ cairo_set_operator (cr_surf, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr_surf);
+ cairo_set_operator (cr_surf, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgba (cr_surf, 0.0f, 0.0f, 0.0f, 0.75f);
+ cairo_arc (cr_surf,
+ 2 * shadow_radius,
+ 2 * shadow_radius,
+ 2.0f * corner_radius,
+ 0.0f,
+ 360.0f * (G_PI / 180.f));
+ cairo_fill (cr_surf);
+ cairo_destroy (cr_surf);
+
+ blur_image_surface (tmp_surface, shadow_radius);
+
+ tile = g_new0 (TileData, 1);
+ tile->format = cairo_image_surface_get_format (tmp_surface);
+ tile->width = cairo_image_surface_get_width (tmp_surface) / 2;
+ tile->height = cairo_image_surface_get_height (tmp_surface) / 2;
+ tile->stride = cairo_image_surface_get_stride (tmp_surface);
+
+ data = cairo_image_surface_get_data (tmp_surface);
+
+ tile->data = g_malloc (tile->height * tile->stride);
+ memcpy (tile->data, data, tile->height * tile->stride);
+ }
+
+ new_surface = cairo_image_surface_create_for_data (tile->data,
+ tile->format,
+ tile->width,
+ tile->height,
+ tile->stride);
+
+ pattern = cairo_pattern_create_for_surface (new_surface);
+ if (cairo_pattern_status (pattern) != CAIRO_STATUS_SUCCESS)
+ {
+ cairo_surface_destroy (tmp_surface);
+ cairo_surface_destroy (new_surface);
+ return;
+ }
+
+ /* top left */
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+ cairo_set_source (cr, pattern);
+ cairo_rectangle (cr,
+ 0.0f,
+ 0.0f,
+ width - 2 * shadow_radius,
+ 2 * shadow_radius);
+ cairo_fill (cr);
+
+ /* bottom left */
+ cairo_matrix_init_scale (&matrix, 1.0f, -1.0f);
+ cairo_matrix_translate (&matrix, 0.0f, -height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_rectangle (cr,
+ 0.0f,
+ 2 * shadow_radius,
+ 2 * shadow_radius,
+ height - 2 * shadow_radius);
+ cairo_fill (cr);
+
+ /* top right */
+ cairo_matrix_init_scale (&matrix, -1.0f, 1.0f);
+ cairo_matrix_translate (&matrix, -width, 0.0f);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_rectangle (cr,
+ width - 2 * shadow_radius,
+ 0.0f,
+ 2 * shadow_radius,
+ height - 2 * shadow_radius);
+ cairo_fill (cr);
+
+ /* bottom right */
+ cairo_matrix_init_scale (&matrix, -1.0f, -1.0f);
+ cairo_matrix_translate (&matrix, -width, -height);
+ cairo_pattern_set_matrix (pattern, &matrix);
+ cairo_rectangle (cr,
+ 2 * shadow_radius,
+ height - 2 * shadow_radius,
+ width - 2 * shadow_radius,
+ 2 * shadow_radius);
+ cairo_fill (cr);
+
+
+ cairo_pattern_destroy (pattern);
+ cairo_surface_destroy (tmp_surface);
+ cairo_surface_destroy (new_surface);
+}
+
static void
paint_decorated_window (GtkStyle *style,
GdkWindow *window,
@@ -3479,14 +3718,16 @@ paint_decorated_window (GtkStyle *style,
{
cairo_pattern_t *gradient;
cairo_t *cr;
- const double hmargin = 2.5, vmargin = 2.5, radius = 5;
+ const double hmargin = 2.5 + x;
+ const double vmargin = 2.5 + y;
+ const double radius = 5;
GdkColor *color;
GdkWindowState state;
if (width == -1)
- width = widget->allocation.width;
+ width = widget->allocation.width - 2 * x;
if (height == -1)
- height = widget->allocation.height;
+ height = widget->allocation.height - 2 * y;
state = gdk_window_get_state (window);
@@ -3504,6 +3745,14 @@ paint_decorated_window (GtkStyle *style,
}
else
{
+ paint_window_shadow (cr,
+ width,
+ height,
+ x / 2 + 2.5,
+ radius);
+
+ cairo_move_to (cr, hmargin, vmargin + radius);
+
cairo_arc (cr, hmargin + radius, vmargin + radius,
radius, M_PI, 3 * M_PI / 2);
cairo_line_to (cr, width - hmargin - radius, vmargin);
@@ -3646,11 +3895,15 @@ gtk_default_draw_box (GtkStyle *style,
}
if (strcmp (detail, "decoration") == 0)
- paint_decorated_window (style, window, state_type, shadow_type,
- area, widget, detail, x, y, width, height);
+ {
+ paint_decorated_window (style, window, state_type, shadow_type,
+ area, widget, detail, x, y, width, height);
+ }
else
- gtk_paint_shadow (style, window, state_type, shadow_type,
- area, widget, detail, x, y, width, height);
+ {
+ gtk_paint_shadow (style, window, state_type, shadow_type,
+ area, widget, detail, x, y, width, height);
+ }
if (detail && strcmp (detail, "optionmenu") == 0)
{
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 31b6c99..2563fc6 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -885,13 +885,15 @@ gtk_window_class_init (GtkWindowClass *klass)
g_param_spec_int ("decoration-border-width",
P_("Decoration border width"),
P_("Decoration border width"),
- 0, G_MAXINT, 6, GTK_PARAM_READWRITE));
+ 0, G_MAXINT,
+ 6, GTK_PARAM_READWRITE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("decoration-resize-handle",
P_("Decoration resize handle size"),
P_("Decoration resize handle size"),
- 0, G_MAXINT, 20, GTK_PARAM_READWRITE));
+ 0, G_MAXINT,
+ 20, GTK_PARAM_READWRITE));
/**
* GtkWindow:decoration-extents:
@@ -900,10 +902,37 @@ gtk_window_class_init (GtkWindowClass *klass)
* used for client-side window drop-shadows or window glow.
*/
gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("decoration-extents",
- P_("Decoration extent size"),
- P_("Decoration extent size"),
- 0, G_MAXINT, 0, GTK_PARAM_READWRITE));
+ g_param_spec_int ("extents-left",
+ P_("Left extents"),
+ P_("Left extents area"),
+ 0, G_MAXINT,
+ 40,
+ GTK_PARAM_READWRITE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("extents-top",
+ P_("Top extents"),
+ P_("Top extents area"),
+ 0, G_MAXINT,
+ 40,
+ GTK_PARAM_READWRITE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("extents-right",
+ P_("Right extents"),
+ P_("Right extents area"),
+ 0, G_MAXINT,
+ 40,
+ GTK_PARAM_READWRITE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("extents-bottom",
+ P_("Bottom extents"),
+ P_("Bottom extents area"),
+ 0, G_MAXINT,
+ 40,
+ GTK_PARAM_READWRITE));
+
window_signals[SET_FOCUS] =
g_signal_new (I_("set-focus"),
@@ -5469,29 +5498,39 @@ gtk_window_size_request (GtkWidget *widget,
GtkBin *bin;
GtkRequisition child_requisition;
GtkWindowPrivate *priv;
- gint frame_width = 0;
- gint extents = 0;
window = GTK_WINDOW (widget);
priv = GTK_WINDOW_GET_PRIVATE (window);
bin = GTK_BIN (window);
- if (priv->client_side_decorations & GDK_DECOR_BORDER)
- {
- frame_width = get_decoration_frame_width (window);
-
- gtk_widget_style_get (widget,
- "decoration-extents", &extents,
- NULL);
- }
-
requisition->width = GTK_CONTAINER (window)->border_width * 2;
requisition->height = GTK_CONTAINER (window)->border_width * 2;
if (is_client_side_decorated (window))
{
- requisition->width += extents * 2;
- requisition->height += extents * 2;
+ gint frame_width = 0;
+ gint extents_left = 0, extents_right = 0, extents_top = 0, extents_bottom = 0;
+ GdkWindowState state;
+
+ if (widget->window != NULL)
+ state = gdk_window_get_state (widget->window);
+
+ if (widget->window && !(state & GDK_WINDOW_STATE_MAXIMIZED))
+ {
+ gtk_widget_style_get (widget,
+ "extents-left", &extents_left,
+ "extents-top", &extents_top,
+ "extents-right", &extents_right,
+ "extents-bottom", &extents_bottom,
+ NULL);
+ }
+
+ if (priv->client_side_decorations & GDK_DECOR_BORDER)
+ {
+ gtk_widget_style_get (widget,
+ "decoration-border-width", &frame_width,
+ NULL);
+ }
if (window->type != GTK_WINDOW_POPUP)
{
@@ -5523,6 +5562,9 @@ gtk_window_size_request (GtkWidget *widget,
requisition->width += frame_width * 2;
requisition->height += frame_width * 2 + child_height;
}
+
+ requisition->width += extents_left + extents_right;
+ requisition->height += extents_top + extents_bottom;
}
if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
@@ -5583,6 +5625,11 @@ gtk_window_size_allocate (GtkWidget *widget,
gint left_width = 0;
GdkRectangle rect;
gboolean client_decorated;
+ gint extents_left = 0;
+ gint extents_top = 0;
+ gint extents_right = 0;
+ gint extents_bottom = 0;
+ GdkWindowState state;
window = GTK_WINDOW (widget);
container = GTK_CONTAINER (widget);
@@ -5590,20 +5637,38 @@ gtk_window_size_allocate (GtkWidget *widget,
priv = GTK_WINDOW_GET_PRIVATE (window);
client_decorated = is_client_side_decorated (window);
+ if (widget->window)
+ state = gdk_window_get_state (widget->window);
deco_allocation.width = deco_allocation.height = 0;
- frame_width = get_decoration_frame_width (window);
+ if (client_decorated)
+ {
+ if (widget->window && !(state & GDK_WINDOW_STATE_MAXIMIZED))
+ {
+ gtk_widget_style_get (widget,
+ "extents-left", &extents_left,
+ "extents-top", &extents_top,
+ "extents-right", &extents_right,
+ "extents-bottom", &extents_bottom,
+ NULL);
+ }
+
+ if (priv->client_side_decorations & GDK_DECOR_BORDER)
+ {
+ frame_width = get_decoration_frame_width (window);
+ }
+ }
if (client_decorated && priv->icon_event_box && GTK_WIDGET_VISIBLE (priv->icon_event_box))
{
gtk_widget_get_child_requisition (priv->icon_event_box, &deco_requisition);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- deco_allocation.x = allocation->width - frame_width - deco_requisition.width;
+ deco_allocation.x = allocation->width - frame_width - deco_requisition.width - extents_left;
else
- deco_allocation.x = frame_width;
- deco_allocation.y = frame_width;
+ deco_allocation.x = frame_width + extents_left;
+ deco_allocation.y = frame_width + extents_top;
deco_allocation.width = deco_requisition.width;
deco_allocation.height = deco_requisition.height;
@@ -5618,10 +5683,10 @@ gtk_window_size_allocate (GtkWidget *widget,
gtk_widget_get_child_requisition (priv->button_box, &box_requisition);
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- box_allocation.x = frame_width;
+ box_allocation.x = frame_width + extents_left;
else
- box_allocation.x = allocation->width - frame_width - box_requisition.width;
- box_allocation.y = frame_width;
+ box_allocation.x = allocation->width - frame_width - box_requisition.width - extents_right;
+ box_allocation.y = frame_width + extents_top;
box_allocation.width = box_requisition.width;
box_allocation.height = box_requisition.height;
@@ -5635,8 +5700,8 @@ gtk_window_size_allocate (GtkWidget *widget,
{
gtk_widget_get_child_requisition (priv->title_label, &deco_requisition);
- deco_allocation.x = 2 * frame_width + left_width;
- deco_allocation.y = frame_width;
+ deco_allocation.x = 2 * frame_width + left_width + extents_left;
+ deco_allocation.y = frame_width + extents_top;
deco_allocation.width = MAX (deco_requisition.width, get_available_size_for_label (window));
deco_allocation.height = deco_requisition.height;
@@ -5649,31 +5714,33 @@ gtk_window_size_allocate (GtkWidget *widget,
{
if (client_decorated && window->type != GTK_WINDOW_POPUP)
{
- child_allocation.x = container->border_width + frame_width;
- child_allocation.y = container->border_width
+ child_allocation.x = container->border_width + frame_width + extents_left;
+ child_allocation.y = container->border_width + extents_top
+ MAX (deco_allocation.height, box_allocation.height)
+ frame_width; // XXX - padding style property?
child_allocation.width = MAX (1, ((gint)allocation->width - container->border_width * 2
+ - extents_left - extents_right
- (frame_width * 2)));
child_allocation.height = MAX (1, ((gint)allocation->height - container->border_width * 2
+ - extents_top - extents_bottom
- (frame_width * 2)
// XXX - padding style property?
- MAX (deco_allocation.height, box_allocation.height)));
}
else
{
- child_allocation.x = GTK_CONTAINER (window)->border_width;
- child_allocation.y = GTK_CONTAINER (window)->border_width;
- child_allocation.width =
- MAX (1, (gint)allocation->width - child_allocation.x * 2);
- child_allocation.height =
- MAX (1, (gint)allocation->height - child_allocation.y * 2);
+ child_allocation.x = GTK_CONTAINER (window)->border_width + extents_left;
+ child_allocation.y = GTK_CONTAINER (window)->border_width + extents_top;
+ child_allocation.width = MAX (1,
+ (gint)allocation->width - child_allocation.x * 2 - extents_left - extents_right);
+ child_allocation.height = MAX (1,
+ (gint)allocation->height - child_allocation.y * 2 - extents_top - extents_bottom);
}
gtk_widget_size_allocate (window->bin.child, &child_allocation);
}
- if (widget->window != NULL)
+ if (widget->window != NULL)
{
rect.x = 0;
rect.y = 0;
@@ -7821,17 +7888,46 @@ gtk_window_paint (GtkWidget *widget,
if (is_client_side_decorated (GTK_WINDOW (widget)))
{
gint frame_width, title_height;
+ gint extents_left, extents_top, extents_right, extents_bottom;
+
+ frame_width = title_height = extents_left = extents_right = extents_top = extents_bottom = 0;
- frame_width = get_decoration_frame_width (GTK_WINDOW (widget));
- title_height = get_title_height (GTK_WINDOW (widget));
+ if (is_client_side_decorated (GTK_WINDOW (widget)))
+ {
+ frame_width = get_decoration_frame_width (GTK_WINDOW (widget));
+ title_height = get_title_height (GTK_WINDOW (widget));
+
+ gtk_widget_style_get (widget,
+ "decoration-border-width", &frame_width,
+ "extents-left", &extents_left,
+ "extents-top", &extents_top,
+ "extents-right", &extents_right,
+ "extents-bottom", &extents_bottom,
+ NULL);
+ }
- gtk_paint_box (widget->style, widget->window, GTK_STATE_NORMAL,
- GTK_SHADOW_OUT, area, widget, "decoration", 0, 0, -1, -1);
- gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE, area, widget, "base",
- frame_width, frame_width + title_height,
- widget->allocation.width - 2 * frame_width,
- widget->allocation.height - 2 * frame_width - title_height);
+ gtk_paint_box (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ area, widget,
+ "decoration",
+ extents_left,
+ extents_top,
+ -1,
+ -1);
+
+ gtk_paint_flat_box (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ area,
+ widget,
+ "base",
+ frame_width + extents_left,
+ frame_width + title_height + extents_top,
+ widget->allocation.width - 2 * frame_width - extents_left - extents_right,
+ widget->allocation.height - 2 * frame_width - title_height - extents_top - extents_bottom);
}
else
gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]