Merge branch 'transparent-windows'

This commit is contained in:
Alexander Larsson 2011-12-05 14:24:28 +01:00
commit c47ef89aca
5 changed files with 401 additions and 245 deletions

View File

@ -204,6 +204,7 @@ struct _GdkWindow
guint input_only : 1;
guint modal_hint : 1;
guint composited : 1;
guint has_alpha_background : 1;
guint destroyed : 2;
@ -227,10 +228,18 @@ struct _GdkWindow
gint abs_x, abs_y; /* Absolute offset in impl */
gint width, height;
guint32 clip_tag;
cairo_region_t *clip_region; /* Clip region (wrt toplevel) in window coords */
cairo_region_t *clip_region_with_children; /* Clip region in window coords */
/* The clip region is the part of the window, in window coordinates
that is fully or partially (i.e. semi transparently) visible in
the window hierarchy from the toplevel and down */
cairo_region_t *clip_region;
/* This is the clip region, with additionally all the opaque
child windows removed */
cairo_region_t *clip_region_with_children;
/* The layered region is the subset of clip_region that
is covered by non-opaque sibling or ancestor sibling window. */
cairo_region_t *layered_region;
GdkCursor *cursor;
GHashTable *device_cursor;
@ -391,11 +400,6 @@ void _gdk_display_set_window_under_pointer (GdkDisplay *display,
void _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window);
cairo_region_t *_gdk_window_calculate_full_clip_region (GdkWindow *window,
GdkWindow *base_window,
gboolean do_children,
gint *base_x_offset,
gint *base_y_offset);
gboolean _gdk_window_has_impl (GdkWindow *window);
GdkWindow * _gdk_window_get_impl_window (GdkWindow *window);

View File

@ -205,7 +205,6 @@ struct _GdkWindowPaint
cairo_surface_t *surface;
guint uses_implicit : 1;
guint flushed : 1;
guint32 region_tag;
};
typedef struct {
@ -256,6 +255,7 @@ static void gdk_window_invalidate_rect_full (GdkWindow *window,
const GdkRectangle *rect,
gboolean invalidate_children,
ClearBg clear_bg);
static void _gdk_window_propagate_has_alpha_background (GdkWindow *window);
static guint signals[LAST_SIGNAL] = { 0 };
@ -263,14 +263,6 @@ static gpointer parent_class = NULL;
static const cairo_user_data_key_t gdk_window_cairo_key;
static guint32
new_region_tag (void)
{
static guint32 tag = 0;
return ++tag;
}
G_DEFINE_ABSTRACT_TYPE (GdkWindow, gdk_window, G_TYPE_OBJECT)
GType
@ -658,10 +650,64 @@ gdk_window_has_no_impl (GdkWindow *window)
}
static void
remove_child_area (GdkWindow *private,
remove_layered_child_area (GdkWindow *window,
cairo_region_t *region)
{
GdkWindow *child;
cairo_region_t *child_region;
GdkRectangle r;
GList *l;
for (l = window->children; l; l = l->next)
{
child = l->data;
/* If region is empty already, no need to do
anything potentially costly */
if (cairo_region_is_empty (region))
break;
if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
continue;
/* Ignore offscreen children, as they don't draw in their parent and
* don't take part in the clipping */
if (gdk_window_is_offscreen (child))
continue;
/* Only non-impl children with alpha add to the layered region */
if (!child->has_alpha_background && gdk_window_has_impl (child))
continue;
r.x = child->x;
r.y = child->y;
r.width = child->width;
r.height = child->height;
/* Bail early if child totally outside region */
if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
continue;
child_region = cairo_region_create_rectangle (&r);
if (child->shape)
{
/* Adjust shape region to parent window coords */
cairo_region_translate (child->shape, child->x, child->y);
cairo_region_intersect (child_region, child->shape);
cairo_region_translate (child->shape, -child->x, -child->y);
}
cairo_region_subtract (region, child_region);
cairo_region_destroy (child_region);
}
}
static void
remove_child_area (GdkWindow *window,
GdkWindow *until,
gboolean for_input,
cairo_region_t *region)
cairo_region_t *region,
cairo_region_t *layered_region)
{
GdkWindow *child;
cairo_region_t *child_region;
@ -669,7 +715,7 @@ remove_child_area (GdkWindow *private,
GList *l;
cairo_region_t *shape;
for (l = private->children; l; l = l->next)
for (l = window->children; l; l = l->next)
{
child = l->data;
@ -707,7 +753,7 @@ remove_child_area (GdkWindow *private,
cairo_region_intersect (child_region, child->shape);
cairo_region_translate (child->shape, -child->x, -child->y);
}
else if (private->window_type == GDK_WINDOW_FOREIGN)
else if (window->window_type == GDK_WINDOW_FOREIGN)
{
shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_shape (child);
if (shape)
@ -721,7 +767,7 @@ remove_child_area (GdkWindow *private,
{
if (child->input_shape)
cairo_region_intersect (child_region, child->input_shape);
else if (private->window_type == GDK_WINDOW_FOREIGN)
else if (window->window_type == GDK_WINDOW_FOREIGN)
{
shape = GDK_WINDOW_IMPL_GET_CLASS (child)->get_input_shape (child);
if (shape)
@ -732,9 +778,14 @@ remove_child_area (GdkWindow *private,
}
}
cairo_region_subtract (region, child_region);
if (child->has_alpha_background)
{
if (layered_region != NULL)
cairo_region_union (layered_region, child_region);
}
else
cairo_region_subtract (region, child_region);
cairo_region_destroy (child_region);
}
}
@ -877,7 +928,7 @@ recompute_visible_regions_internal (GdkWindow *private,
GdkRectangle r;
GList *l;
GdkWindow *child;
cairo_region_t *new_clip, *old_clip_region_with_children;
cairo_region_t *new_clip, *new_layered;
gboolean clip_region_changed;
gboolean abs_pos_changed;
int old_abs_x, old_abs_y;
@ -910,6 +961,7 @@ recompute_visible_regions_internal (GdkWindow *private,
clip_region_changed = FALSE;
if (recalculate_clip)
{
new_layered = cairo_region_create ();
if (private->viewable)
{
/* Calculate visible region (sans children) in parent window coords */
@ -922,39 +974,45 @@ recompute_visible_regions_internal (GdkWindow *private,
if (!gdk_window_is_toplevel (private))
{
cairo_region_intersect (new_clip, private->parent->clip_region);
cairo_region_union (new_layered, private->parent->layered_region);
/* Remove all overlapping children from parent. */
remove_child_area (private->parent, private, FALSE, new_clip);
remove_child_area (private->parent, private, FALSE, new_clip, new_layered);
}
/* Convert from parent coords to window coords */
cairo_region_translate (new_clip, -private->x, -private->y);
cairo_region_translate (new_layered, -private->x, -private->y);
if (private->shape)
cairo_region_intersect (new_clip, private->shape);
}
else
new_clip = cairo_region_create ();
new_clip = cairo_region_create ();
cairo_region_intersect (new_layered, new_clip);
if (private->clip_region == NULL ||
!cairo_region_equal (private->clip_region, new_clip))
clip_region_changed = TRUE;
if (private->layered_region == NULL ||
!cairo_region_equal (private->layered_region, new_layered))
clip_region_changed = TRUE;
if (private->clip_region)
cairo_region_destroy (private->clip_region);
private->clip_region = new_clip;
old_clip_region_with_children = private->clip_region_with_children;
if (private->layered_region != NULL)
cairo_region_destroy (private->layered_region);
private->layered_region = new_layered;
if (private->clip_region_with_children)
cairo_region_destroy (private->clip_region_with_children);
private->clip_region_with_children = cairo_region_copy (private->clip_region);
if (private->window_type != GDK_WINDOW_ROOT)
remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
if (clip_region_changed ||
!cairo_region_equal (private->clip_region_with_children, old_clip_region_with_children))
private->clip_tag = new_region_tag ();
if (old_clip_region_with_children)
cairo_region_destroy (old_clip_region_with_children);
remove_child_area (private, NULL, FALSE, private->clip_region_with_children, NULL);
}
if (clip_region_changed)
@ -1632,10 +1690,22 @@ gdk_window_reparent (GdkWindow *window,
_gdk_window_update_viewable (window);
if (window->background == NULL)
{
/* parent relative background, update has_alpha_background */
if (window->parent == NULL ||
window->parent->window_type == GDK_WINDOW_ROOT)
window->has_alpha_background = FALSE;
else
window->has_alpha_background = window->parent->has_alpha_background;
}
recompute_visible_regions (window, TRUE, FALSE);
if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
recompute_visible_regions (old_parent, FALSE, TRUE);
_gdk_window_propagate_has_alpha_background (window);
/* We used to apply the clip as the shape, but no more.
Reset this to the real shape */
if (gdk_window_has_impl (window) &&
@ -2859,7 +2929,6 @@ gdk_window_begin_paint_region (GdkWindow *window,
paint = g_new (GdkWindowPaint, 1);
paint->region = cairo_region_copy (region);
paint->region_tag = new_region_tag ();
cairo_region_intersect (paint->region, window->clip_region_with_children);
cairo_region_get_extents (paint->region, &clip_box);
@ -2890,6 +2959,20 @@ gdk_window_begin_paint_region (GdkWindow *window,
gdk_window_get_content (window),
MAX (clip_box.width, 1),
MAX (clip_box.height, 1));
/* Normally alpha backgrounded client side windows are composited on the implicit paint
by being drawn in back to front order. However, if implicit paints are not used, for
instance if it was flushed due to a non-double-buffered paint in the middle of the
expose we need to copy in the existing data here. */
if (!gdk_window_has_impl (window) && window->has_alpha_background)
{
cairo_t *cr = cairo_create (paint->surface);
gdk_cairo_set_source_window (cr, impl_window,
- (window->abs_x + clip_box.x),
- (window->abs_y + clip_box.y));
cairo_paint (cr);
cairo_destroy (cr);
}
}
cairo_surface_set_device_offset (paint->surface, -clip_box.x, -clip_box.y);
@ -3779,8 +3862,7 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
cairo_region_t *expose_region)
{
GdkWindow *child;
cairo_region_t *child_region;
GdkRectangle r;
cairo_region_t *clipped_expose_region;
GList *l, *children;
if (cairo_region_is_empty (expose_region))
@ -3790,57 +3872,13 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
window == window->impl_window)
_gdk_window_add_damage ((GdkWindow *) window->impl_window, expose_region);
/* Make this reentrancy safe for expose handlers freeing windows */
children = g_list_copy (window->children);
g_list_foreach (children, (GFunc)g_object_ref, NULL);
/* Iterate over children, starting at topmost */
for (l = children; l != NULL; l = l->next)
{
child = l->data;
/* Paint the window before the children, clipped to the window region
with visible child windows removed */
clipped_expose_region = cairo_region_copy (expose_region);
cairo_region_intersect (clipped_expose_region, window->clip_region_with_children);
if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
continue;
/* Ignore offscreen children, as they don't draw in their parent and
* don't take part in the clipping */
if (gdk_window_is_offscreen (child))
continue;
r.x = child->x;
r.y = child->y;
r.width = child->width;
r.height = child->height;
child_region = cairo_region_create_rectangle (&r);
if (child->shape)
{
/* Adjust shape region to parent window coords */
cairo_region_translate (child->shape, child->x, child->y);
cairo_region_intersect (child_region, child->shape);
cairo_region_translate (child->shape, -child->x, -child->y);
}
if (child->impl == window->impl)
{
/* Client side child, expose */
cairo_region_intersect (child_region, expose_region);
cairo_region_subtract (expose_region, child_region);
cairo_region_translate (child_region, -child->x, -child->y);
_gdk_window_process_updates_recurse ((GdkWindow *)child, child_region);
}
else
{
/* Native child, just remove area from expose region */
cairo_region_subtract (expose_region, child_region);
}
cairo_region_destroy (child_region);
}
g_list_foreach (children, (GFunc)g_object_unref, NULL);
g_list_free (children);
if (!cairo_region_is_empty (expose_region) &&
if (!cairo_region_is_empty (clipped_expose_region) &&
!window->destroyed)
{
if (window->event_mask & GDK_EXPOSURE_MASK)
@ -3851,8 +3889,8 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
event.expose.window = g_object_ref (window);
event.expose.send_event = FALSE;
event.expose.count = 0;
event.expose.region = expose_region;
cairo_region_get_extents (expose_region, &event.expose.area);
event.expose.region = clipped_expose_region;
cairo_region_get_extents (clipped_expose_region, &event.expose.area);
_gdk_event_emit (&event);
@ -3871,11 +3909,42 @@ _gdk_window_process_updates_recurse (GdkWindow *window,
* We use begin/end_paint around the clear so that we can
* piggyback on the implicit paint */
gdk_window_begin_paint_region (window, expose_region);
gdk_window_clear_region_internal (window, expose_region);
gdk_window_begin_paint_region (window, clipped_expose_region);
gdk_window_clear_region_internal (window, clipped_expose_region);
gdk_window_end_paint (window);
}
}
cairo_region_destroy (clipped_expose_region);
/* Make this reentrancy safe for expose handlers freeing windows */
children = g_list_copy (window->children);
g_list_foreach (children, (GFunc)g_object_ref, NULL);
/* Iterate over children, starting at bottommost */
for (l = g_list_last (children); l != NULL; l = l->prev)
{
child = l->data;
if (child->destroyed || !GDK_WINDOW_IS_MAPPED (child) || child->input_only || child->composited)
continue;
/* Ignore offscreen children, as they don't draw in their parent and
* don't take part in the clipping */
if (gdk_window_is_offscreen (child))
continue;
/* Client side child, expose */
if (child->impl == window->impl)
{
cairo_region_translate (expose_region, -child->x, -child->y);
_gdk_window_process_updates_recurse ((GdkWindow *)child, expose_region);
cairo_region_translate (expose_region, child->x, child->y);
}
}
g_list_foreach (children, (GFunc)g_object_unref, NULL);
g_list_free (children);
}
/* Process and remove any invalid area on the native window by creating
@ -4581,7 +4650,7 @@ cairo_region_t *
gdk_window_get_update_area (GdkWindow *window)
{
GdkWindow *impl_window;
cairo_region_t *tmp_region;
cairo_region_t *tmp_region, *to_remove;
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
@ -4601,7 +4670,21 @@ gdk_window_get_update_area (GdkWindow *window)
}
else
{
cairo_region_subtract (impl_window->update_area, tmp_region);
/* Convert from impl coords */
cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
/* Don't remove any update area that is overlapped by non-opaque windows
(children or siblings) with alpha, as these really need to be repainted
independently of this window. */
to_remove = cairo_region_copy (tmp_region);
cairo_region_subtract (to_remove, window->parent->layered_region);
remove_layered_child_area (window, to_remove);
/* Remove from update_area */
cairo_region_translate (to_remove, window->abs_x, window->abs_y);
cairo_region_subtract (impl_window->update_area, to_remove);
cairo_region_destroy (to_remove);
if (cairo_region_is_empty (impl_window->update_area) &&
impl_window->outstanding_moves == NULL)
@ -4612,10 +4695,7 @@ gdk_window_get_update_area (GdkWindow *window)
gdk_window_remove_update_window ((GdkWindow *)impl_window);
}
/* Convert from impl coords */
cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
return tmp_region;
}
}
else
@ -5261,8 +5341,6 @@ gdk_window_show_unraised (GdkWindow *window)
void
gdk_window_raise (GdkWindow *window)
{
cairo_region_t *old_region, *new_region;
g_return_if_fail (GDK_IS_WINDOW (window));
if (window->destroyed)
@ -5270,26 +5348,14 @@ gdk_window_raise (GdkWindow *window)
gdk_window_flush_if_exposing (window);
old_region = NULL;
if (gdk_window_is_viewable (window) &&
!window->input_only)
old_region = cairo_region_copy (window->clip_region);
/* Keep children in (reverse) stacking order */
gdk_window_raise_internal (window);
recompute_visible_regions (window, TRUE, FALSE);
if (old_region)
{
new_region = cairo_region_copy (window->clip_region);
cairo_region_subtract (new_region, old_region);
gdk_window_invalidate_region_full (window, new_region, TRUE, CLEAR_BG_ALL);
cairo_region_destroy (old_region);
cairo_region_destroy (new_region);
}
if (gdk_window_is_viewable (window) &&
!window->input_only)
gdk_window_invalidate_region_full (window, window->clip_region, TRUE, CLEAR_BG_ALL);
}
static void
@ -5989,7 +6055,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
gint width,
gint height)
{
cairo_region_t *old_region, *new_region, *copy_area;
cairo_region_t *old_region, *old_layered, *new_region, *copy_area;
cairo_region_t *old_native_child_region, *new_native_child_region;
GdkWindow *impl_window;
GdkWindowImplClass *impl_class;
@ -6022,6 +6088,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
expose = FALSE;
old_region = NULL;
old_layered = NULL;
impl_window = gdk_window_get_impl_window (window);
@ -6035,8 +6102,10 @@ gdk_window_move_resize_internal (GdkWindow *window,
expose = TRUE;
old_region = cairo_region_copy (window->clip_region);
/* Adjust region to parent window coords */
old_layered = cairo_region_copy (window->layered_region);
/* Adjust regions to parent window coords */
cairo_region_translate (old_region, window->x, window->y);
cairo_region_translate (old_layered, window->x, window->y);
old_native_child_region = collect_native_child_region (window, TRUE);
if (old_native_child_region)
@ -6116,7 +6185,19 @@ gdk_window_move_resize_internal (GdkWindow *window,
* Everything in the old and new regions that is not copied must be
* invalidated (including children) as this is newly exposed
*/
copy_area = cairo_region_copy (new_region);
if (window->has_alpha_background)
copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
else
copy_area = cairo_region_copy (new_region);
/* Don't copy from a previously layered region */
cairo_region_translate (old_layered, dx, dy);
cairo_region_subtract (copy_area, old_layered);
/* Don't copy into a layered region */
cairo_region_translate (copy_area, -window->x, -window->y);
cairo_region_subtract (copy_area, window->layered_region);
cairo_region_translate (copy_area, window->x, window->y);
cairo_region_union (new_region, old_region);
@ -6165,6 +6246,7 @@ gdk_window_move_resize_internal (GdkWindow *window,
gdk_window_invalidate_region_full (window->parent, new_region, TRUE, CLEAR_BG_ALL);
cairo_region_destroy (old_region);
cairo_region_destroy (old_layered);
cairo_region_destroy (new_region);
}
@ -6274,7 +6356,7 @@ gdk_window_scroll (GdkWindow *window,
gint dy)
{
GdkWindow *impl_window;
cairo_region_t *copy_area, *noncopy_area;
cairo_region_t *copy_area, *noncopy_area, *old_layered_area;
cairo_region_t *old_native_child_region, *new_native_child_region;
GList *tmp_list;
@ -6288,6 +6370,7 @@ gdk_window_scroll (GdkWindow *window,
gdk_window_flush_if_exposing (window);
old_layered_area = cairo_region_copy (window->layered_region);
old_native_child_region = collect_native_child_region (window, FALSE);
if (old_native_child_region)
{
@ -6328,7 +6411,11 @@ gdk_window_scroll (GdkWindow *window,
impl_window = gdk_window_get_impl_window (window);
/* Calculate the area that can be gotten by copying the old area */
copy_area = cairo_region_copy (window->clip_region);
if (window->has_alpha_background)
copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
else
copy_area = cairo_region_copy (window->clip_region);
cairo_region_subtract (copy_area, old_layered_area);
if (old_native_child_region)
{
/* Don't copy from inside native children, as this is copied by
@ -6342,6 +6429,7 @@ gdk_window_scroll (GdkWindow *window,
}
cairo_region_translate (copy_area, dx, dy);
cairo_region_intersect (copy_area, window->clip_region);
cairo_region_subtract (copy_area, window->layered_region);
/* And the rest need to be invalidated */
noncopy_area = cairo_region_copy (window->clip_region);
@ -6363,6 +6451,7 @@ gdk_window_scroll (GdkWindow *window,
gdk_window_invalidate_region_full (window, noncopy_area, TRUE, CLEAR_BG_ALL);
cairo_region_destroy (noncopy_area);
cairo_region_destroy (old_layered_area);
if (old_native_child_region)
{
@ -6410,12 +6499,19 @@ gdk_window_move_region (GdkWindow *window,
impl_window = gdk_window_get_impl_window (window);
/* compute source regions */
copy_area = cairo_region_copy (region);
if (window->has_alpha_background)
copy_area = cairo_region_create (); /* Copy nothing for alpha windows */
else
copy_area = cairo_region_copy (region);
cairo_region_intersect (copy_area, window->clip_region_with_children);
cairo_region_subtract (copy_area, window->layered_region);
remove_layered_child_area (window, copy_area);
/* compute destination regions */
cairo_region_translate (copy_area, dx, dy);
cairo_region_intersect (copy_area, window->clip_region_with_children);
cairo_region_subtract (copy_area, window->layered_region);
remove_layered_child_area (window, copy_area);
/* Invalidate parts of the region (source and dest) not covered
by the copy */
@ -6487,6 +6583,29 @@ gdk_window_set_background_rgba (GdkWindow *window,
cairo_pattern_destroy (pattern);
}
/* Updates has_alpha_background recursively for all child windows
that have parent-relative alpha */
static void
_gdk_window_propagate_has_alpha_background (GdkWindow *window)
{
GdkWindow *child;
GList *l;
for (l = window->children; l; l = l->next)
{
child = l->data;
if (child->background == NULL &&
child->has_alpha_background != window->has_alpha_background)
{
child->has_alpha_background = window->has_alpha_background;
recompute_visible_regions (child, TRUE, FALSE);
_gdk_window_propagate_has_alpha_background (child);
}
}
}
/**
* gdk_window_set_background_pattern:
* @window: a #GdkWindow
@ -6504,6 +6623,9 @@ void
gdk_window_set_background_pattern (GdkWindow *window,
cairo_pattern_t *pattern)
{
gboolean has_alpha;
cairo_pattern_type_t type;
g_return_if_fail (GDK_IS_WINDOW (window));
if (window->input_only)
@ -6515,6 +6637,69 @@ gdk_window_set_background_pattern (GdkWindow *window,
cairo_pattern_destroy (window->background);
window->background = pattern;
has_alpha = TRUE;
if (pattern == NULL)
{
/* parent-relative, copy has_alpha from parent */
if (window->parent == NULL ||
window->parent->window_type == GDK_WINDOW_ROOT)
has_alpha = FALSE;
else
has_alpha = window->parent->has_alpha_background;
}
else
{
type = cairo_pattern_get_type (pattern);
if (type == CAIRO_PATTERN_TYPE_SOLID)
{
double alpha;
cairo_pattern_get_rgba (pattern, NULL, NULL, NULL, &alpha);
if (alpha == 1.0)
has_alpha = FALSE;
}
else if (type == CAIRO_PATTERN_TYPE_LINEAR ||
type == CAIRO_PATTERN_TYPE_RADIAL)
{
int i, n;
double alpha;
n = 0;
cairo_pattern_get_color_stop_count (pattern, &n);
has_alpha = FALSE;
for (i = 0; i < n; i++)
{
cairo_pattern_get_color_stop_rgba (pattern, i, NULL,
NULL, NULL, NULL, &alpha);
if (alpha != 1.0)
{
has_alpha = TRUE;
break;
}
}
}
else if (type == CAIRO_PATTERN_TYPE_SURFACE)
{
cairo_surface_t *surface;
cairo_content_t content;
cairo_pattern_get_surface (pattern, &surface);
content = cairo_surface_get_content (surface);
has_alpha =
(content == CAIRO_CONTENT_ALPHA) ||
(content == CAIRO_CONTENT_COLOR_ALPHA);
}
}
if (has_alpha != window->has_alpha_background)
{
window->has_alpha_background = has_alpha;
recompute_visible_regions (window, TRUE, FALSE);
_gdk_window_propagate_has_alpha_background (window);
}
if (gdk_window_has_impl (window))
{
GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
@ -7140,7 +7325,7 @@ do_child_shapes (GdkWindow *window,
r.height = window->height;
region = cairo_region_create_rectangle (&r);
remove_child_area (window, NULL, FALSE, region);
remove_child_area (window, NULL, FALSE, region, NULL);
if (merge && window->shape)
cairo_region_subtract (region, window->shape);
@ -7259,7 +7444,7 @@ do_child_input_shapes (GdkWindow *window,
r.height = window->height;
region = cairo_region_create_rectangle (&r);
remove_child_area (window, NULL, TRUE, region);
remove_child_area (window, NULL, TRUE, region, NULL);
if (merge && window->shape)
cairo_region_subtract (region, window->shape);
@ -7525,114 +7710,6 @@ gdk_window_is_shaped (GdkWindow *window)
return window->shaped;
}
static void
window_get_size_rectangle (GdkWindow *window,
GdkRectangle *rect)
{
rect->x = rect->y = 0;
rect->width = window->width;
rect->height = window->height;
}
/* Calculates the real clipping region for a window, in window coordinates,
* taking into account other windows, gc clip region and gc clip mask.
*/
cairo_region_t *
_gdk_window_calculate_full_clip_region (GdkWindow *window,
GdkWindow *base_window,
gboolean do_children,
gint *base_x_offset,
gint *base_y_offset)
{
GdkRectangle visible_rect;
cairo_region_t *real_clip_region;
gint x_offset, y_offset;
GdkWindow *parentwin, *lastwin;
if (base_x_offset)
*base_x_offset = 0;
if (base_y_offset)
*base_y_offset = 0;
if (!window->viewable || window->input_only)
return cairo_region_create ();
window_get_size_rectangle (window, &visible_rect);
/* real_clip_region is in window coordinates */
real_clip_region = cairo_region_create_rectangle (&visible_rect);
x_offset = y_offset = 0;
lastwin = window;
if (do_children)
parentwin = lastwin;
else
parentwin = lastwin->parent;
/* Remove the areas of all overlapping windows above parentwin in the hiearachy */
for (; parentwin != NULL &&
(parentwin == window || lastwin != base_window);
lastwin = parentwin, parentwin = lastwin->parent)
{
GList *cur;
GdkRectangle real_clip_rect;
if (parentwin != window)
{
x_offset += lastwin->x;
y_offset += lastwin->y;
}
/* children is ordered in reverse stack order */
for (cur = parentwin->children;
cur && cur->data != lastwin;
cur = cur->next)
{
GdkWindow *child = cur->data;
if (!GDK_WINDOW_IS_MAPPED (child) || child->input_only)
continue;
/* Ignore offscreen children, as they don't draw in their parent and
* don't take part in the clipping */
if (gdk_window_is_offscreen (child))
continue;
window_get_size_rectangle (child, &visible_rect);
/* Convert rect to "window" coords */
visible_rect.x += child->x - x_offset;
visible_rect.y += child->y - y_offset;
/* This shortcut is really necessary for performance when there are a lot of windows */
cairo_region_get_extents (real_clip_region, &real_clip_rect);
if (visible_rect.x >= real_clip_rect.x + real_clip_rect.width ||
visible_rect.x + visible_rect.width <= real_clip_rect.x ||
visible_rect.y >= real_clip_rect.y + real_clip_rect.height ||
visible_rect.y + visible_rect.height <= real_clip_rect.y)
continue;
cairo_region_subtract_rectangle (real_clip_region, &visible_rect);
}
/* Clip to the parent */
window_get_size_rectangle ((GdkWindow *)parentwin, &visible_rect);
/* Convert rect to "window" coords */
visible_rect.x += - x_offset;
visible_rect.y += - y_offset;
cairo_region_intersect_rectangle (real_clip_region, &visible_rect);
}
if (base_x_offset)
*base_x_offset = x_offset;
if (base_y_offset)
*base_y_offset = y_offset;
return real_clip_region;
}
void
_gdk_window_add_damage (GdkWindow *toplevel,
cairo_region_t *damaged_region)

View File

@ -580,6 +580,10 @@ gboolean gdk_window_get_composited (GdkWindow *window);
void gdk_window_set_composited (GdkWindow *window,
gboolean composited);
gboolean gdk_window_get_layered (GdkWindow *window);
void gdk_window_set_layered (GdkWindow *window,
gboolean layered);
/*
* This routine allows you to merge (ie ADD) child shapes to your
* own window's shape keeping its current shape and ADDING the child

View File

@ -5521,6 +5521,7 @@ resize_grip_create_window (GtkWindow *window)
GdkWindowAttr attributes;
gint attributes_mask;
GdkRectangle rect;
GdkRGBA transparent = {0, 0, 0, 0};
priv = window->priv;
widget = GTK_WIDGET (window);
@ -5545,6 +5546,7 @@ resize_grip_create_window (GtkWindow *window)
priv->grip_window = gdk_window_new (gtk_widget_get_window (widget),
&attributes,
attributes_mask);
gdk_window_set_background_rgba (priv->grip_window, &transparent);
gdk_window_set_user_data (priv->grip_window, widget);
@ -7440,7 +7442,8 @@ gtk_window_draw (GtkWidget *widget,
gtk_style_context_save (context);
if (!gtk_widget_get_app_paintable (widget))
if (!gtk_widget_get_app_paintable (widget) &&
gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
{
GtkStateFlags state;

View File

@ -15,12 +15,12 @@ static GtkWidget *main_window;
GdkWindow *
create_window (GdkWindow *parent,
int x, int y, int w, int h,
GdkColor *color)
GdkRGBA *color)
{
GdkWindowAttr attributes;
gint attributes_mask;
GdkWindow *window;
GdkColor *bg;
GdkRGBA *bg;
attributes.x = x;
attributes.y = y;
@ -41,17 +41,18 @@ create_window (GdkWindow *parent,
window = gdk_window_new (parent, &attributes, attributes_mask);
gdk_window_set_user_data (window, darea);
bg = g_new (GdkColor, 1);
bg = g_new (GdkRGBA, 1);
if (color)
*bg = *color;
else
{
bg->red = g_random_int_range (0, 0xffff);
bg->blue = g_random_int_range (0, 0xffff);
bg->green = g_random_int_range (0, 0xffff);;
bg->red = g_random_double ();
bg->blue = g_random_double ();
bg->green = g_random_double ();
bg->alpha = 1.0;
}
gdk_window_set_background (window, bg);
gdk_window_set_background_rgba (window, bg);
g_object_set_data_full (G_OBJECT (window), "color", bg, g_free);
gdk_window_show (window);
@ -238,16 +239,16 @@ save_window (GString *s,
GdkWindow *window)
{
gint x, y;
GdkColor *color;
GdkRGBA *color;
gdk_window_get_position (window, &x, &y);
color = g_object_get_data (G_OBJECT (window), "color");
g_string_append_printf (s, "%d,%d %dx%d (%d,%d,%d) %d %d\n",
g_string_append_printf (s, "%d,%d %dx%d (%f,%f,%f,%f) %d %d\n",
x, y,
gdk_window_get_width (window),
gdk_window_get_height (window),
color->red, color->green, color->blue,
color->red, color->green, color->blue, color->alpha,
gdk_window_has_native (window),
g_list_length (gdk_window_peek_children (window)));
@ -273,6 +274,13 @@ save_children (GString *s,
}
static void
refresh_clicked (GtkWidget *button,
gpointer data)
{
gtk_widget_queue_draw (darea);
}
static void
save_clicked (GtkWidget *button,
gpointer data)
@ -330,21 +338,23 @@ destroy_children (GdkWindow *window)
static char **
parse_window (GdkWindow *parent, char **lines)
{
int x, y, w, h, r, g, b, native, n_children;
int x, y, w, h, native, n_children;
double r, g, b, a;
GdkWindow *window;
GdkColor color;
GdkRGBA color;
int i;
if (*lines == NULL)
return lines;
if (sscanf(*lines, "%d,%d %dx%d (%d,%d,%d) %d %d",
&x, &y, &w, &h, &r, &g, &b, &native, &n_children) == 9)
if (sscanf(*lines, "%d,%d %dx%d (%lf,%lf,%lf,%lf) %d %d",
&x, &y, &w, &h, &r, &g, &b, &a, &native, &n_children) == 10)
{
lines++;
color.red = r;
color.green = g;
color.blue = b;
color.alpha = a;
window = create_window (parent, x, y, w, h, &color);
if (native)
gdk_window_ensure_native (window);
@ -685,6 +695,39 @@ native_window_clicked (GtkWidget *button,
update_store ();
}
static void
alpha_clicked (GtkWidget *button,
gpointer data)
{
GList *selected, *l;
GdkWindow *window;
GdkRGBA *color;
selected = get_selected_windows ();
for (l = selected; l != NULL; l = l->next)
{
window = l->data;
color = g_object_get_data (G_OBJECT (window), "color");
if (GPOINTER_TO_INT(data) > 0)
color->alpha += 0.2;
else
color->alpha -= 0.2;
if (color->alpha < 0)
color->alpha = 0;
if (color->alpha > 1)
color->alpha = 1;
gdk_window_set_background_rgba (window, color);
}
g_list_free (selected);
update_store ();
}
static gboolean
darea_button_release_event (GtkWidget *widget,
GdkEventButton *event)
@ -956,6 +999,20 @@ main (int argc, char **argv)
gtk_grid_attach (GTK_GRID (grid), button, 3, 2, 1, 1);
gtk_widget_show (button);
button = gtk_button_new_with_label ("More transparent");
g_signal_connect (button, "clicked",
G_CALLBACK (alpha_clicked),
GINT_TO_POINTER (-1));
gtk_grid_attach (GTK_GRID (grid), button, 0, 3, 1, 1);
gtk_widget_show (button);
button = gtk_button_new_with_label ("Less transparent");
g_signal_connect (button, "clicked",
G_CALLBACK (alpha_clicked),
GINT_TO_POINTER (1));
gtk_grid_attach (GTK_GRID (grid), button, 1, 3, 1, 1);
gtk_widget_show (button);
button = gtk_button_new_with_label ("Restack above");
g_signal_connect (button, "clicked",
G_CALLBACK (restack_clicked),
@ -1000,6 +1057,17 @@ main (int argc, char **argv)
G_CALLBACK (save_clicked),
NULL);
button = gtk_button_new_with_label ("Refresh");
gtk_box_pack_start (GTK_BOX (vbox),
button,
FALSE, FALSE,
2);
gtk_widget_show (button);
g_signal_connect (button, "clicked",
G_CALLBACK (refresh_clicked),
NULL);
gtk_widget_show (window);
if (argc == 2)