From 45df163e9dd77670c99e26e49cdbe85c142cbe57 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 13:38:04 +0100 Subject: [PATCH 01/16] gdk: Remove now unused region tags completely --- gdk/gdkinternals.h | 1 - gdk/gdkwindow.c | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index a9a5917962..27afe026ac 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -227,7 +227,6 @@ 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 */ diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index cc251a9e1a..750f186df8 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -205,7 +205,6 @@ struct _GdkWindowPaint cairo_surface_t *surface; guint uses_implicit : 1; guint flushed : 1; - guint32 region_tag; }; typedef struct { @@ -263,14 +262,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 @@ -949,10 +940,6 @@ recompute_visible_regions_internal (GdkWindow *private, 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); } @@ -2859,7 +2846,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); From 7fd225c766b1d149e7d503fb0678cb711ee6d76f Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 13:42:09 +0100 Subject: [PATCH 02/16] gdk: Expose bottommost windows first This cleans up the expose handling a bit by using the existing clip regions, and it allows us later to use painters algorithm to do transparent windows. --- gdk/gdkwindow.c | 96 +++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 750f186df8..dba089704f 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -3765,8 +3765,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)) @@ -3776,57 +3775,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) @@ -3837,8 +3792,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); @@ -3857,11 +3812,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 From 9613e6ae196a3c61ba1798789ead21b2cd22d5f1 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 14:09:52 +0100 Subject: [PATCH 03/16] testwindows: Test transparent backgrounds --- gdk/gdkwindow.h | 4 +++ tests/testwindows.c | 78 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h index 50779fe365..58f98bd75a 100644 --- a/gdk/gdkwindow.h +++ b/gdk/gdkwindow.h @@ -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 diff --git a/tests/testwindows.c b/tests/testwindows.c index a68f3bc20d..ecae1cf907 100644 --- a/tests/testwindows.c +++ b/tests/testwindows.c @@ -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))); @@ -330,21 +331,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 +688,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 +992,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), From 30ad4e676fe91351a2e5e71216ce74f1ef0c5c18 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 16:21:45 +0100 Subject: [PATCH 04/16] testwindows: Add a button to cause a repaint This makes it easy to find various kinds of repaint bugs --- tests/testwindows.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/testwindows.c b/tests/testwindows.c index ecae1cf907..0535b6327b 100644 --- a/tests/testwindows.c +++ b/tests/testwindows.c @@ -274,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) @@ -1050,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) From f51482e283f7c9c2d7d0e0394dced2ea57d4b67b Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 13:57:27 +0100 Subject: [PATCH 05/16] gdk: Track wether windows have alpha in the background This will let us handle such windows differently in the drawing machinery --- gdk/gdkinternals.h | 1 + gdk/gdkwindow.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 27afe026ac..9bd1ea9e65 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -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; diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index dba089704f..ae0850c58b 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -6476,6 +6476,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) @@ -6487,6 +6490,54 @@ gdk_window_set_background_pattern (GdkWindow *window, cairo_pattern_destroy (window->background); window->background = pattern; + has_alpha = TRUE; + 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); + } + if (gdk_window_has_impl (window)) { GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl); From 46d5b89830c555bb50af5be848b4415381971924 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 13:57:47 +0100 Subject: [PATCH 06/16] gdk: Track the layered area We track the areas that have alpha coverage so that we can avoid using these as sources when copying window contents. We also don't remove such areas from the clipping regions so that they are painted both by parent and child. --- gdk/gdkinternals.h | 13 +++++++++++-- gdk/gdkwindow.c | 42 ++++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 9bd1ea9e65..8567fd4fb3 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -229,8 +229,17 @@ struct _GdkWindow gint abs_x, abs_y; /* Absolute offset in impl */ gint width, height; - 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; diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index ae0850c58b..d1ac763efa 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -652,7 +652,8 @@ static void remove_child_area (GdkWindow *private, 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; @@ -723,7 +724,13 @@ 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); } @@ -868,7 +875,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; @@ -901,6 +908,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 */ @@ -913,35 +921,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 (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) @@ -7163,7 +7181,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); @@ -7282,7 +7300,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); From 0f6784a919dd2ee223a30c1ff6e602994373730f Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 16:27:37 +0100 Subject: [PATCH 07/16] gdk: Make sure we don't copy to/from layered regions when moving a window --- gdk/gdkwindow.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index d1ac763efa..a5b373a705 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -5979,7 +5979,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; @@ -6012,6 +6012,7 @@ gdk_window_move_resize_internal (GdkWindow *window, expose = FALSE; old_region = NULL; + old_layered = NULL; impl_window = gdk_window_get_impl_window (window); @@ -6025,8 +6026,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) @@ -6106,7 +6109,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); @@ -6155,6 +6170,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); } From f0c8c4a94beb6ad46f0e6b39ec730f8f0bbe68d6 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 16:44:51 +0100 Subject: [PATCH 08/16] gdk: Fix repaint of layered region during raise --- gdk/gdkwindow.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index a5b373a705..7265f786a9 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -5251,8 +5251,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) @@ -5260,26 +5258,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 From 8e28f53a1db931b62826f7ce4c47b81cbc4c4c05 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 16:45:18 +0100 Subject: [PATCH 09/16] gdk: Fix repaint of layered region during scroll --- gdk/gdkwindow.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 7265f786a9..c13b9a88b8 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -6266,7 +6266,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; @@ -6280,6 +6280,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) { @@ -6320,7 +6321,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 @@ -6334,6 +6339,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); @@ -6355,6 +6361,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) { From 7a263c68a0ad87019f36485aa108fb655e3eeaad Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 1 Dec 2011 16:45:36 +0100 Subject: [PATCH 10/16] gdk: Fix repaint of layered region during move_region --- gdk/gdkwindow.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index c13b9a88b8..04026ac414 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -6409,12 +6409,17 @@ 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); /* 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); /* Invalidate parts of the region (source and dest) not covered by the copy */ From f00cfe1facf37cab4e42a901cb365d0991ad46e5 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 5 Dec 2011 10:55:55 +0100 Subject: [PATCH 11/16] Handle has_alpha_background for parent-relative backgrounds --- gdk/gdkwindow.c | 121 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 35 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 04026ac414..4c669b51b4 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -255,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 }; @@ -1637,10 +1638,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) && @@ -6491,6 +6504,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 @@ -6523,53 +6559,68 @@ gdk_window_set_background_pattern (GdkWindow *window, window->background = pattern; has_alpha = TRUE; - 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++) + 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) { - cairo_pattern_get_color_stop_rgba (pattern, i, NULL, - NULL, NULL, NULL, &alpha); - if (alpha != 1.0) + 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++) { - has_alpha = TRUE; - break; + 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; + 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); + 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); From 68843a3e93913c12d00b47380614f67e7e9763b4 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 5 Dec 2011 10:59:07 +0100 Subject: [PATCH 12/16] gdk: Remove unused _gdk_window_calculate_full_clip_region --- gdk/gdkinternals.h | 5 --- gdk/gdkwindow.c | 108 --------------------------------------------- 2 files changed, 113 deletions(-) diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 8567fd4fb3..3042bcb9d4 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -400,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); diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 4c669b51b4..a3a62669a4 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -7631,114 +7631,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) From 76ea76831670188fbe54a2994a58929a12eecab6 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 5 Dec 2011 11:40:30 +0100 Subject: [PATCH 13/16] gdk: Fix alpha window background paintings on non-implicit paints --- gdk/gdkwindow.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index a3a62669a4..912b9b4e31 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -2907,6 +2907,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); From 65ef15812bc889a2158732d0519c899fb9e436cf Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 5 Dec 2011 12:16:55 +0100 Subject: [PATCH 14/16] gdk: gdk_window_move_region gdk_window_move_region doesn't move children, so we can't copy transparent child window regions with copyarea, so we remove these from the copy region. --- gdk/gdkwindow.c | 64 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 912b9b4e31..2fd50769bb 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -650,7 +650,60 @@ 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, @@ -662,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; @@ -700,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) @@ -714,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) @@ -733,7 +786,6 @@ remove_child_area (GdkWindow *private, else cairo_region_subtract (region, child_region); cairo_region_destroy (child_region); - } } @@ -6442,11 +6494,13 @@ gdk_window_move_region (GdkWindow *window, 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 */ From 4597f1ea6ad7bed980195c29af39e8e30f7dd54f Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 5 Dec 2011 12:18:22 +0100 Subject: [PATCH 15/16] gdk: gdk_window_get_update_area don't remove alpha covered areas gdk_window_get_update_area is supposed to get the area where things need painting, and remove them from the update areas. However, if some area is covered by other windows with an alpha background we can't just expect whatever the app choses to render in the update area as correct, so we don't actually remove these areas, meaning they will get correctly rendered when we get to the expose handlers. --- gdk/gdkwindow.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 2fd50769bb..ae57b27ef6 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -4650,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); @@ -4670,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) @@ -4681,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 From 93c086ec80494c5edf84fd6e21c34aec196ea359 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 5 Dec 2011 12:51:55 +0100 Subject: [PATCH 16/16] Make window handle transparent Instead of painting the window background on the grip_window we now only paint it on the GtkWindow->window, and we make the grip_window have a transparent background. We can't really make transparent window handle background optional via css atm, because the handle color is actually based on the background color, so if that is set to transparent we won't draw anything. --- gtk/gtkwindow.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 50370a589a..fd23dd9a71 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -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;