MetaShadowFactory: Add the ability to top-fade a shadow
For attached modal dialogs, we want the shadow to fade out at the top as if the window was glued to the parent at the top. Add a shadow-top-fade property to MetaWindowActor and the corresponding parameter to meta_shadow_factory_get_shadow(). The internal implementation of MetaShadow is adjusted to work in terms of an "inner border" and "outer border" instead of doing the calculations in terms of an aggregate border and the spread of the shadow. The old way of doing things gets clumsy when the top_fade distance is added in as well. https://bugzilla.gnome.org/show_bug.cgi?id=592382
This commit is contained in:
parent
ed2fbcd13a
commit
8eb31944a5
@ -54,6 +54,7 @@ struct _MetaShadowCacheKey
|
|||||||
{
|
{
|
||||||
MetaWindowShape *shape;
|
MetaWindowShape *shape;
|
||||||
int radius;
|
int radius;
|
||||||
|
int top_fade;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaShadow
|
struct _MetaShadow
|
||||||
@ -65,11 +66,20 @@ struct _MetaShadow
|
|||||||
CoglHandle texture;
|
CoglHandle texture;
|
||||||
CoglHandle material;
|
CoglHandle material;
|
||||||
|
|
||||||
int spread;
|
/* The outer order is the distance the shadow extends outside the window
|
||||||
int border_top;
|
* shape; the inner border is the unscaled portion inside the window
|
||||||
int border_right;
|
* shape */
|
||||||
int border_bottom;
|
int outer_border_top;
|
||||||
int border_left;
|
int inner_border_top;
|
||||||
|
int outer_border_right;
|
||||||
|
int inner_border_right;
|
||||||
|
int outer_border_bottom;
|
||||||
|
int inner_border_bottom;
|
||||||
|
int outer_border_left;
|
||||||
|
int inner_border_left;
|
||||||
|
|
||||||
|
guint scale_width : 1;
|
||||||
|
guint scale_height : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaShadowFactory
|
struct _MetaShadowFactory
|
||||||
@ -84,7 +94,7 @@ meta_shadow_cache_key_hash (gconstpointer val)
|
|||||||
{
|
{
|
||||||
const MetaShadowCacheKey *key = val;
|
const MetaShadowCacheKey *key = val;
|
||||||
|
|
||||||
return 59 * key->radius + 67 * meta_window_shape_hash (key->shape);
|
return 59 * key->radius + 67 * key->top_fade + 73 * meta_window_shape_hash (key->shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -94,7 +104,7 @@ meta_shadow_cache_key_equal (gconstpointer a,
|
|||||||
const MetaShadowCacheKey *key_a = a;
|
const MetaShadowCacheKey *key_a = a;
|
||||||
const MetaShadowCacheKey *key_b = b;
|
const MetaShadowCacheKey *key_b = b;
|
||||||
|
|
||||||
return (key_a->radius == key_b->radius &&
|
return (key_a->radius == key_b->radius && key_a->top_fade == key_b->top_fade &&
|
||||||
meta_window_shape_equal (key_a->shape, key_b->shape));
|
meta_window_shape_equal (key_a->shape, key_b->shape));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,57 +159,74 @@ meta_shadow_paint (MetaShadow *shadow,
|
|||||||
float texture_width = cogl_texture_get_width (shadow->texture);
|
float texture_width = cogl_texture_get_width (shadow->texture);
|
||||||
float texture_height = cogl_texture_get_height (shadow->texture);
|
float texture_height = cogl_texture_get_height (shadow->texture);
|
||||||
int i, j;
|
int i, j;
|
||||||
|
float src_x[4];
|
||||||
|
float src_y[4];
|
||||||
|
float dest_x[4];
|
||||||
|
float dest_y[4];
|
||||||
|
int n_x, n_y;
|
||||||
|
|
||||||
cogl_material_set_color4ub (shadow->material,
|
cogl_material_set_color4ub (shadow->material,
|
||||||
opacity, opacity, opacity, opacity);
|
opacity, opacity, opacity, opacity);
|
||||||
|
|
||||||
cogl_set_source (shadow->material);
|
cogl_set_source (shadow->material);
|
||||||
|
|
||||||
if (window_width + 2 * shadow->spread == shadow->border_left &&
|
if (shadow->scale_width)
|
||||||
window_height + 2 * shadow->spread == shadow->border_top)
|
|
||||||
{
|
{
|
||||||
/* The non-scaled case - paint with a single rectangle */
|
n_x = 3;
|
||||||
cogl_rectangle_with_texture_coords (window_x - shadow->spread,
|
|
||||||
window_y - shadow->spread,
|
src_x[0] = 0.0;
|
||||||
window_x + window_width + shadow->spread,
|
src_x[1] = (shadow->inner_border_left + shadow->outer_border_left) / texture_width;
|
||||||
window_y + window_height + shadow->spread,
|
src_x[2] = (texture_width - (shadow->inner_border_right + shadow->outer_border_right)) / texture_width;
|
||||||
0.0, 0.0, 1.0, 1.0);
|
src_x[3] = 1.0;
|
||||||
|
|
||||||
|
dest_x[0] = window_x - shadow->outer_border_left;
|
||||||
|
dest_x[1] = window_x + shadow->inner_border_left;
|
||||||
|
dest_x[2] = window_x + window_width - shadow->inner_border_right;
|
||||||
|
dest_x[3] = window_x + window_width + shadow->outer_border_right;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float src_x[4];
|
n_x = 1;
|
||||||
float src_y[4];
|
|
||||||
float dest_x[4];
|
|
||||||
float dest_y[4];
|
|
||||||
|
|
||||||
src_x[0] = 0.0;
|
src_x[0] = 0.0;
|
||||||
src_x[1] = shadow->border_left / texture_width;
|
src_x[1] = 1.0;
|
||||||
src_x[2] = (texture_width - shadow->border_right) / texture_width;
|
|
||||||
src_x[3] = 1.0;
|
dest_x[0] = window_x - shadow->outer_border_left;
|
||||||
|
dest_x[1] = window_x + window_width + shadow->outer_border_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadow->scale_height)
|
||||||
|
{
|
||||||
|
n_y = 3;
|
||||||
|
|
||||||
src_y[0] = 0.0;
|
src_y[0] = 0.0;
|
||||||
src_y[1] = shadow->border_top / texture_height;
|
src_y[1] = (shadow->inner_border_top + shadow->outer_border_top) / texture_height;
|
||||||
src_y[2] = (texture_height - shadow->border_bottom) / texture_height;
|
src_y[2] = (texture_height - (shadow->inner_border_bottom + shadow->outer_border_bottom)) / texture_height;
|
||||||
src_y[3] = 1.0;
|
src_y[3] = 1.0;
|
||||||
|
|
||||||
dest_x[0] = window_x - shadow->spread;
|
dest_y[0] = window_y - shadow->outer_border_top;
|
||||||
dest_x[1] = window_x - shadow->spread + shadow->border_left;
|
dest_y[1] = window_y + shadow->inner_border_top;
|
||||||
dest_x[2] = window_x + window_width + shadow->spread - shadow->border_right;
|
dest_y[2] = window_y + window_height - shadow->inner_border_bottom;
|
||||||
dest_x[3] = window_x + window_width + shadow->spread;
|
dest_y[3] = window_y + window_height + shadow->outer_border_bottom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n_y = 1;
|
||||||
|
|
||||||
dest_y[0] = window_y - shadow->spread;
|
src_y[0] = 0.0;
|
||||||
dest_y[1] = window_y - shadow->spread + shadow->border_top;
|
src_y[1] = 1.0;
|
||||||
dest_y[2] = window_y + window_height + shadow->spread - shadow->border_bottom;
|
|
||||||
dest_y[3] = window_y + window_height + shadow->spread;
|
|
||||||
|
|
||||||
for (j = 0; j < 3; j++)
|
dest_y[0] = window_y - shadow->outer_border_top;
|
||||||
for (i = 0; i < 3; i++)
|
dest_y[1] = window_y + window_height + shadow->outer_border_bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < n_y; j++)
|
||||||
|
for (i = 0; i < n_x; i++)
|
||||||
cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
|
cogl_rectangle_with_texture_coords (dest_x[i], dest_y[j],
|
||||||
dest_x[i + 1], dest_y[j + 1],
|
dest_x[i + 1], dest_y[j + 1],
|
||||||
src_x[i], src_y[j],
|
src_x[i], src_y[j],
|
||||||
src_x[i + 1], src_y[j + 1]);
|
src_x[i + 1], src_y[j + 1]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_shadow_get_bounds:
|
* meta_shadow_get_bounds:
|
||||||
@ -220,10 +247,10 @@ meta_shadow_get_bounds (MetaShadow *shadow,
|
|||||||
int window_height,
|
int window_height,
|
||||||
cairo_rectangle_int_t *bounds)
|
cairo_rectangle_int_t *bounds)
|
||||||
{
|
{
|
||||||
bounds->x = window_x - shadow->spread;
|
bounds->x = window_x - shadow->outer_border_left;
|
||||||
bounds->y = window_x - shadow->spread;
|
bounds->y = window_x - shadow->outer_border_top;
|
||||||
bounds->width = window_width + 2 * shadow->spread;
|
bounds->width = window_width + shadow->outer_border_left + shadow->outer_border_right;
|
||||||
bounds->height = window_width + 2 * shadow->spread;
|
bounds->height = window_height + shadow->outer_border_top + shadow->outer_border_bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaShadowFactory *
|
MetaShadowFactory *
|
||||||
@ -411,6 +438,19 @@ blur_rows (cairo_region_t *convolve_region,
|
|||||||
g_free (tmp_buffer);
|
g_free (tmp_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fade_bytes (guchar *bytes,
|
||||||
|
int width,
|
||||||
|
int distance,
|
||||||
|
int total)
|
||||||
|
{
|
||||||
|
guint32 multiplier = (distance * 0x10000 + 0x8000) / total;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < width; i++)
|
||||||
|
bytes[i] = (bytes[i] * multiplier) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
/* Swaps width and height. Either swaps in-place and returns the original
|
/* Swaps width and height. Either swaps in-place and returns the original
|
||||||
* buffer or allocates a new buffer, frees the original buffer and returns
|
* buffer or allocates a new buffer, frees the original buffer and returns
|
||||||
* the new buffer.
|
* the new buffer.
|
||||||
@ -483,23 +523,33 @@ flip_buffer (guchar *buffer,
|
|||||||
#undef BLOCK_SIZE
|
#undef BLOCK_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
static CoglHandle
|
static void
|
||||||
make_shadow (cairo_region_t *region,
|
make_shadow (MetaShadow *shadow,
|
||||||
int radius)
|
cairo_region_t *region)
|
||||||
{
|
{
|
||||||
int d = get_box_filter_size (radius);
|
int d = get_box_filter_size (shadow->key.radius);
|
||||||
int spread = get_shadow_spread (radius);
|
int spread = get_shadow_spread (shadow->key.radius);
|
||||||
CoglHandle result;
|
|
||||||
cairo_rectangle_int_t extents;
|
cairo_rectangle_int_t extents;
|
||||||
cairo_region_t *row_convolve_region;
|
cairo_region_t *row_convolve_region;
|
||||||
cairo_region_t *column_convolve_region;
|
cairo_region_t *column_convolve_region;
|
||||||
guchar *buffer;
|
guchar *buffer;
|
||||||
int buffer_width;
|
int buffer_width;
|
||||||
int buffer_height;
|
int buffer_height;
|
||||||
|
int x_offset;
|
||||||
|
int y_offset;
|
||||||
int n_rectangles, j, k;
|
int n_rectangles, j, k;
|
||||||
|
|
||||||
cairo_region_get_extents (region, &extents);
|
cairo_region_get_extents (region, &extents);
|
||||||
|
|
||||||
|
/* In the case where top_fade >= 0 and the portion above the top
|
||||||
|
* edge of the shape will be cropped, it seems like we could create
|
||||||
|
* a smaller buffer and omit the top portion, but actually, in our
|
||||||
|
* multi-pass blur algorithm, the blur into the area above the window
|
||||||
|
* in the first pass will contribute back to the final pixel values
|
||||||
|
* for the top pixels, so we create a buffer as if we weren't cropping
|
||||||
|
* and only crop when creating the CoglTexture.
|
||||||
|
*/
|
||||||
|
|
||||||
buffer_width = extents.width + 2 * spread;
|
buffer_width = extents.width + 2 * spread;
|
||||||
buffer_height = extents.height + 2 * spread;
|
buffer_height = extents.height + 2 * spread;
|
||||||
|
|
||||||
@ -521,8 +571,12 @@ make_shadow (cairo_region_t *region,
|
|||||||
* large shadow sizes) we can improve efficiency by restricting the blur
|
* large shadow sizes) we can improve efficiency by restricting the blur
|
||||||
* to the region that actually needs to be blurred.
|
* to the region that actually needs to be blurred.
|
||||||
*/
|
*/
|
||||||
row_convolve_region = meta_make_border_region (region, spread, 0, FALSE);
|
row_convolve_region = meta_make_border_region (region, spread, spread, FALSE);
|
||||||
column_convolve_region = meta_make_border_region (region, spread, spread, TRUE);
|
column_convolve_region = meta_make_border_region (region, 0, spread, TRUE);
|
||||||
|
|
||||||
|
/* Offsets between coordinates of the regions and coordinates in the buffer */
|
||||||
|
x_offset = spread;
|
||||||
|
y_offset = spread;
|
||||||
|
|
||||||
/* Step 1: unblurred image */
|
/* Step 1: unblurred image */
|
||||||
n_rectangles = cairo_region_num_rectangles (region);
|
n_rectangles = cairo_region_num_rectangles (region);
|
||||||
@ -531,35 +585,53 @@ make_shadow (cairo_region_t *region,
|
|||||||
cairo_rectangle_int_t rect;
|
cairo_rectangle_int_t rect;
|
||||||
|
|
||||||
cairo_region_get_rectangle (region, k, &rect);
|
cairo_region_get_rectangle (region, k, &rect);
|
||||||
for (j = spread + rect.y; j < spread + rect.y + rect.height; j++)
|
for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
|
||||||
memset (buffer + buffer_width * j + spread + rect.x, 255, rect.width);
|
memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 2: blur rows */
|
|
||||||
blur_rows (row_convolve_region, spread, spread, buffer, buffer_width, buffer_height, d);
|
|
||||||
|
|
||||||
/* Step 2: swap rows and columns */
|
/* Step 2: swap rows and columns */
|
||||||
buffer = flip_buffer (buffer, buffer_width, buffer_height);
|
buffer = flip_buffer (buffer, buffer_width, buffer_height);
|
||||||
|
|
||||||
/* Step 3: blur rows (really columns) */
|
/* Step 3: blur rows (really columns) */
|
||||||
blur_rows (column_convolve_region, spread, spread, buffer, buffer_height, buffer_width, d);
|
blur_rows (column_convolve_region, y_offset, x_offset,
|
||||||
|
buffer, buffer_height, buffer_width,
|
||||||
|
d);
|
||||||
|
|
||||||
/* Step 3: swap rows and columns */
|
/* Step 4: swap rows and columns */
|
||||||
buffer = flip_buffer (buffer, buffer_height, buffer_width);
|
buffer = flip_buffer (buffer, buffer_height, buffer_width);
|
||||||
|
|
||||||
result = cogl_texture_new_from_data (extents.width + 2 * spread,
|
/* Step 5: blur rows */
|
||||||
extents.height + 2 * spread,
|
blur_rows (row_convolve_region, x_offset, y_offset,
|
||||||
|
buffer, buffer_width, buffer_height,
|
||||||
|
d);
|
||||||
|
|
||||||
|
/* Step 6: fade out the top, if applicable */
|
||||||
|
if (shadow->key.top_fade >= 0)
|
||||||
|
{
|
||||||
|
for (j = y_offset; j < y_offset + MIN (shadow->key.top_fade, extents.height + shadow->outer_border_bottom); j++)
|
||||||
|
fade_bytes(buffer + j * buffer_width, buffer_width, j - y_offset, shadow->key.top_fade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We offset the passed in pixels to crop off the extra area we allocated at the top
|
||||||
|
* in the case of top_fade >= 0. We also account for padding at the left for symmetry
|
||||||
|
* though that doesn't currently occur.
|
||||||
|
*/
|
||||||
|
shadow->texture = cogl_texture_new_from_data (shadow->outer_border_left + extents.width + shadow->outer_border_right,
|
||||||
|
shadow->outer_border_top + extents.height + shadow->outer_border_bottom,
|
||||||
COGL_TEXTURE_NONE,
|
COGL_TEXTURE_NONE,
|
||||||
COGL_PIXEL_FORMAT_A_8,
|
COGL_PIXEL_FORMAT_A_8,
|
||||||
COGL_PIXEL_FORMAT_ANY,
|
COGL_PIXEL_FORMAT_ANY,
|
||||||
buffer_width,
|
buffer_width,
|
||||||
buffer);
|
(buffer +
|
||||||
|
(y_offset - shadow->outer_border_top) * buffer_width +
|
||||||
|
(x_offset - shadow->outer_border_left)));
|
||||||
|
|
||||||
cairo_region_destroy (row_convolve_region);
|
cairo_region_destroy (row_convolve_region);
|
||||||
cairo_region_destroy (column_convolve_region);
|
cairo_region_destroy (column_convolve_region);
|
||||||
g_free (buffer);
|
g_free (buffer);
|
||||||
|
|
||||||
return result;
|
shadow->material = cogl_material_new ();
|
||||||
|
cogl_material_set_layer (shadow->material, 0, shadow->texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -569,6 +641,8 @@ make_shadow (cairo_region_t *region,
|
|||||||
* @width: the actual width of the window's region
|
* @width: the actual width of the window's region
|
||||||
* @width: the actual height of the window's region
|
* @width: the actual height of the window's region
|
||||||
* @radius: the radius (gaussian standard deviation) of the shadow
|
* @radius: the radius (gaussian standard deviation) of the shadow
|
||||||
|
* @top_fade: if >= 0, the shadow doesn't extend above the top
|
||||||
|
* of the shape, and fades out over the given number of pixels
|
||||||
*
|
*
|
||||||
* Gets the appropriate shadow object for drawing shadows for the
|
* Gets the appropriate shadow object for drawing shadows for the
|
||||||
* specified window shape. The region that we are shadowing is specified
|
* specified window shape. The region that we are shadowing is specified
|
||||||
@ -584,14 +658,19 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
|
|||||||
MetaWindowShape *shape,
|
MetaWindowShape *shape,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int radius)
|
int radius,
|
||||||
|
int top_fade)
|
||||||
{
|
{
|
||||||
MetaShadowCacheKey key;
|
MetaShadowCacheKey key;
|
||||||
MetaShadow *shadow;
|
MetaShadow *shadow;
|
||||||
cairo_region_t *region;
|
cairo_region_t *region;
|
||||||
int spread;
|
int spread;
|
||||||
int border_top, border_right, border_bottom, border_left;
|
int shape_border_top, shape_border_right, shape_border_bottom, shape_border_left;
|
||||||
|
int inner_border_top, inner_border_right, inner_border_bottom, inner_border_left;
|
||||||
|
int outer_border_top, outer_border_right, outer_border_bottom, outer_border_left;
|
||||||
|
gboolean scale_width, scale_height;
|
||||||
gboolean cacheable;
|
gboolean cacheable;
|
||||||
|
int center_width, center_height;
|
||||||
|
|
||||||
/* Using a single shadow texture for different window sizes only works
|
/* Using a single shadow texture for different window sizes only works
|
||||||
* when there is a central scaled area that is greater than twice
|
* when there is a central scaled area that is greater than twice
|
||||||
@ -612,21 +691,35 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
|
|||||||
* policy is to only keep around referenced shadows, there wouldn't
|
* policy is to only keep around referenced shadows, there wouldn't
|
||||||
* be any harm in caching them, it would just make the book-keeping
|
* be any harm in caching them, it would just make the book-keeping
|
||||||
* a bit tricker.)
|
* a bit tricker.)
|
||||||
|
*
|
||||||
|
* In the case where we are fading a the top, that also has to fit
|
||||||
|
* within the top unscaled border.
|
||||||
*/
|
*/
|
||||||
spread = get_shadow_spread (radius);
|
spread = get_shadow_spread (radius);
|
||||||
meta_window_shape_get_borders (shape,
|
meta_window_shape_get_borders (shape,
|
||||||
&border_top,
|
&shape_border_top,
|
||||||
&border_right,
|
&shape_border_right,
|
||||||
&border_bottom,
|
&shape_border_bottom,
|
||||||
&border_left);
|
&shape_border_left);
|
||||||
|
|
||||||
cacheable = (border_top + 2 * spread + border_bottom <= height &&
|
inner_border_top = MAX (shape_border_top + spread, top_fade);
|
||||||
border_left + 2 * spread + border_right <= width);
|
outer_border_top = top_fade >= 0 ? 0 : spread;
|
||||||
|
inner_border_right = shape_border_right + spread;
|
||||||
|
outer_border_right = spread;
|
||||||
|
inner_border_bottom = shape_border_bottom + spread;
|
||||||
|
outer_border_bottom = spread;
|
||||||
|
inner_border_left = shape_border_left + spread;
|
||||||
|
outer_border_left = spread;
|
||||||
|
|
||||||
|
scale_width = inner_border_left + inner_border_right <= width;
|
||||||
|
scale_height = inner_border_top + inner_border_bottom <= height;
|
||||||
|
cacheable = scale_width && scale_height;
|
||||||
|
|
||||||
if (cacheable)
|
if (cacheable)
|
||||||
{
|
{
|
||||||
key.shape = shape;
|
key.shape = shape;
|
||||||
key.radius = radius;
|
key.radius = radius;
|
||||||
|
key.top_fade = top_fade;
|
||||||
|
|
||||||
shadow = g_hash_table_lookup (factory->shadows, &key);
|
shadow = g_hash_table_lookup (factory->shadows, &key);
|
||||||
if (shadow)
|
if (shadow)
|
||||||
@ -639,35 +732,34 @@ meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
|
|||||||
shadow->factory = factory;
|
shadow->factory = factory;
|
||||||
shadow->key.shape = meta_window_shape_ref (shape);
|
shadow->key.shape = meta_window_shape_ref (shape);
|
||||||
shadow->key.radius = radius;
|
shadow->key.radius = radius;
|
||||||
|
shadow->key.top_fade = top_fade;
|
||||||
|
|
||||||
shadow->spread = spread;
|
shadow->outer_border_top = outer_border_top;
|
||||||
|
shadow->inner_border_top = inner_border_top;
|
||||||
|
shadow->outer_border_right = outer_border_right;
|
||||||
|
shadow->inner_border_right = inner_border_right;
|
||||||
|
shadow->outer_border_bottom = outer_border_bottom;
|
||||||
|
shadow->inner_border_bottom = inner_border_bottom;
|
||||||
|
shadow->outer_border_left = outer_border_left;
|
||||||
|
shadow->inner_border_left = inner_border_left;
|
||||||
|
|
||||||
if (cacheable)
|
shadow->scale_width = scale_width;
|
||||||
{
|
if (scale_width)
|
||||||
shadow->border_top = border_top + 2 * spread;
|
center_width = inner_border_left + inner_border_right - (shape_border_left + shape_border_right);
|
||||||
shadow->border_right += border_right + 2 * spread;
|
|
||||||
shadow->border_bottom += border_bottom + 2 * spread;
|
|
||||||
shadow->border_left += border_left + 2 * spread;
|
|
||||||
|
|
||||||
region = meta_window_shape_to_region (shape, 2 * spread, 2 * spread);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
center_width = width - (shape_border_left + shape_border_right);
|
||||||
/* In the non-scaled case, we put the entire shadow into the
|
|
||||||
* upper-left-hand corner of the 9-slice */
|
|
||||||
shadow->border_top = height + 2 * spread;
|
|
||||||
shadow->border_right = 0;
|
|
||||||
shadow->border_bottom = 0;
|
|
||||||
shadow->border_left = width + 2 * spread;
|
|
||||||
|
|
||||||
region = meta_window_shape_to_region (shape,
|
shadow->scale_height = scale_height;
|
||||||
width - border_left - border_right,
|
if (scale_height)
|
||||||
height - border_top - border_bottom);
|
center_height = inner_border_top + inner_border_bottom - (shape_border_top + shape_border_bottom);
|
||||||
}
|
else
|
||||||
|
center_height = height - (shape_border_top + shape_border_bottom);
|
||||||
|
|
||||||
|
g_assert (center_width >= 0 && center_height >= 0);
|
||||||
|
|
||||||
|
region = meta_window_shape_to_region (shape, center_width, center_height);
|
||||||
|
make_shadow (shadow, region);
|
||||||
|
|
||||||
shadow->texture = make_shadow (region, radius);
|
|
||||||
shadow->material = cogl_material_new ();
|
|
||||||
cogl_material_set_layer (shadow->material, 0, shadow->texture);
|
|
||||||
cairo_region_destroy (region);
|
cairo_region_destroy (region);
|
||||||
|
|
||||||
if (cacheable)
|
if (cacheable)
|
||||||
|
@ -68,6 +68,7 @@ MetaShadow * meta_shadow_factory_get_shadow (MetaShadowFactory *factory,
|
|||||||
MetaWindowShape *shape,
|
MetaWindowShape *shape,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int radius);
|
int radius,
|
||||||
|
int top_fade);
|
||||||
|
|
||||||
#endif /* __META_SHADOW_FACTORY_H__ */
|
#endif /* __META_SHADOW_FACTORY_H__ */
|
||||||
|
@ -52,6 +52,7 @@ struct _MetaWindowActorPrivate
|
|||||||
gint freeze_count;
|
gint freeze_count;
|
||||||
|
|
||||||
gint shadow_radius;
|
gint shadow_radius;
|
||||||
|
gint shadow_top_fade;
|
||||||
gint shadow_x_offset;
|
gint shadow_x_offset;
|
||||||
gint shadow_y_offset;
|
gint shadow_y_offset;
|
||||||
|
|
||||||
@ -97,6 +98,7 @@ enum
|
|||||||
PROP_X_WINDOW_ATTRIBUTES,
|
PROP_X_WINDOW_ATTRIBUTES,
|
||||||
PROP_NO_SHADOW,
|
PROP_NO_SHADOW,
|
||||||
PROP_SHADOW_RADIUS,
|
PROP_SHADOW_RADIUS,
|
||||||
|
PROP_SHADOW_TOP_FADE,
|
||||||
PROP_SHADOW_X_OFFSET,
|
PROP_SHADOW_X_OFFSET,
|
||||||
PROP_SHADOW_Y_OFFSET,
|
PROP_SHADOW_Y_OFFSET,
|
||||||
PROP_SHADOW_OPACITY
|
PROP_SHADOW_OPACITY
|
||||||
@ -254,6 +256,17 @@ meta_window_actor_class_init (MetaWindowActorClass *klass)
|
|||||||
PROP_SHADOW_RADIUS,
|
PROP_SHADOW_RADIUS,
|
||||||
pspec);
|
pspec);
|
||||||
|
|
||||||
|
pspec = g_param_spec_int ("shadow-top-fade",
|
||||||
|
"Shadow Top Fade",
|
||||||
|
"If >= 0, the shadow doesn't extend above the top "
|
||||||
|
"of the window, and fades out over the given number of pixels",
|
||||||
|
-1, G_MAXINT, -1,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
g_object_class_install_property (object_class,
|
||||||
|
PROP_SHADOW_TOP_FADE,
|
||||||
|
pspec);
|
||||||
|
|
||||||
pspec = g_param_spec_int ("shadow-x-offset",
|
pspec = g_param_spec_int ("shadow-x-offset",
|
||||||
"Shadow X Offset",
|
"Shadow X Offset",
|
||||||
"Distance shadow is offset in the horizontal direction in pixels",
|
"Distance shadow is offset in the horizontal direction in pixels",
|
||||||
@ -296,6 +309,7 @@ meta_window_actor_init (MetaWindowActor *self)
|
|||||||
MetaWindowActorPrivate);
|
MetaWindowActorPrivate);
|
||||||
priv->opacity = 0xff;
|
priv->opacity = 0xff;
|
||||||
priv->shadow_radius = DEFAULT_SHADOW_RADIUS;
|
priv->shadow_radius = DEFAULT_SHADOW_RADIUS;
|
||||||
|
priv->shadow_top_fade = -1;
|
||||||
priv->shadow_x_offset = DEFAULT_SHADOW_X_OFFSET;
|
priv->shadow_x_offset = DEFAULT_SHADOW_X_OFFSET;
|
||||||
priv->shadow_y_offset = DEFAULT_SHADOW_Y_OFFSET;
|
priv->shadow_y_offset = DEFAULT_SHADOW_Y_OFFSET;
|
||||||
priv->shadow_opacity = 0xff;
|
priv->shadow_opacity = 0xff;
|
||||||
@ -547,6 +561,18 @@ meta_window_actor_set_property (GObject *object,
|
|||||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PROP_SHADOW_TOP_FADE:
|
||||||
|
{
|
||||||
|
gint newv = g_value_get_int (value);
|
||||||
|
|
||||||
|
if (newv == priv->shadow_top_fade)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->shadow_top_fade = newv;
|
||||||
|
priv->recompute_shadow = TRUE;
|
||||||
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case PROP_SHADOW_X_OFFSET:
|
case PROP_SHADOW_X_OFFSET:
|
||||||
{
|
{
|
||||||
gint newv = g_value_get_int (value);
|
gint newv = g_value_get_int (value);
|
||||||
@ -614,6 +640,9 @@ meta_window_actor_get_property (GObject *object,
|
|||||||
case PROP_SHADOW_RADIUS:
|
case PROP_SHADOW_RADIUS:
|
||||||
g_value_set_int (value, priv->shadow_radius);
|
g_value_set_int (value, priv->shadow_radius);
|
||||||
break;
|
break;
|
||||||
|
case PROP_SHADOW_TOP_FADE:
|
||||||
|
g_value_set_int (value, priv->shadow_top_fade);
|
||||||
|
break;
|
||||||
case PROP_SHADOW_X_OFFSET:
|
case PROP_SHADOW_X_OFFSET:
|
||||||
g_value_set_int (value, priv->shadow_x_offset);
|
g_value_set_int (value, priv->shadow_x_offset);
|
||||||
break;
|
break;
|
||||||
@ -1813,7 +1842,7 @@ check_needs_shadow (MetaWindowActor *self)
|
|||||||
priv->shadow = meta_shadow_factory_get_shadow (factory,
|
priv->shadow = meta_shadow_factory_get_shadow (factory,
|
||||||
priv->shadow_shape,
|
priv->shadow_shape,
|
||||||
shape_bounds.width, shape_bounds.height,
|
shape_bounds.width, shape_bounds.height,
|
||||||
priv->shadow_radius);
|
priv->shadow_radius, priv->shadow_top_fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_shadow != NULL)
|
if (old_shadow != NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user