diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 6e7bbf1ae7..09ca89010f 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -519,6 +519,7 @@ gtk_private_h_sources = \ gtkprintoperation-private.h \ gtkprintutils.h \ gtkprivate.h \ + gtkpixelcacheprivate.h \ gtkquery.h \ gtkrbtree.h \ gtkrecentchooserdefault.h \ @@ -800,6 +801,7 @@ gtk_base_c_sources = \ gtkprivate.c \ gtkprivatetypebuiltins.c \ gtkprogressbar.c \ + gtkpixelcache.c \ gtkradioaction.c \ gtkradiobutton.c \ gtkradiomenuitem.c \ diff --git a/gtk/gtkpixelcache.c b/gtk/gtkpixelcache.c new file mode 100644 index 0000000000..7b0b345b6f --- /dev/null +++ b/gtk/gtkpixelcache.c @@ -0,0 +1,312 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkpixelcacheprivate.h" + +/* The extra size of the offscreen surface we allocate + to make scrolling more efficient */ +#define EXTRA_SIZE 64 + +/* When resizing viewport to smaller we allow this extra + size to avoid constantly reallocating when resizing */ +#define ALLOW_LARGER_SIZE 32 + +struct _GtkPixelCache { + cairo_surface_t *surface; + + /* Valid if surface != NULL */ + int surface_x; + int surface_y; + int surface_w; + int surface_h; + + /* may be null if not dirty */ + cairo_region_t *surface_dirty; +}; + +GtkPixelCache * +_gtk_pixel_cache_new () +{ + GtkPixelCache *cache; + + cache = g_new0 (GtkPixelCache, 1); + + return cache; +} + +void +_gtk_pixel_cache_free (GtkPixelCache *cache) +{ + if (cache == NULL) + return; + + if (cache->surface != NULL) + cairo_surface_destroy (cache->surface); + + if (cache->surface_dirty != NULL) + cairo_region_destroy (cache->surface_dirty); + + g_free (cache); +} + +/* Region is in canvas coordinates */ +void +_gtk_pixel_cache_invalidate (GtkPixelCache *cache, + cairo_region_t *region) +{ + cairo_rectangle_int_t r; + + if (cache->surface == NULL || cairo_region_is_empty (region)) + return; + + if (cache->surface_dirty == NULL) + { + cache->surface_dirty = cairo_region_copy (region); + cairo_region_translate (cache->surface_dirty, + -cache->surface_x, + -cache->surface_y); + } + else + { + cairo_region_translate (region, + -cache->surface_x, + -cache->surface_y); + cairo_region_union (cache->surface_dirty, region); + cairo_region_translate (region, + cache->surface_x, + cache->surface_y); + } + + r.x = 0; + r.y = 0; + r.width = cache->surface_w; + r.height = cache->surface_h; + cairo_region_intersect_rectangle (cache->surface_dirty, &r); +} + +static void +_gtk_pixel_cache_create_surface_if_needed (GtkPixelCache *cache, + GdkWindow *window, + cairo_rectangle_int_t *view_rect, + cairo_rectangle_int_t *canvas_rect) +{ + cairo_rectangle_int_t rect; + int surface_w, surface_h; + + surface_w = view_rect->width; + if (canvas_rect->width > surface_w) + surface_w = MIN (surface_w + EXTRA_SIZE, canvas_rect->width); + + surface_h = view_rect->height; + if (canvas_rect->height > surface_h) + surface_h = MIN (surface_h + EXTRA_SIZE, canvas_rect->height); + + /* If current surface can't fit view_rect or is too large, kill it */ + if (cache->surface != NULL && + (cache->surface_w < view_rect->width || + cache->surface_w > surface_w + ALLOW_LARGER_SIZE || + cache->surface_h < view_rect->height || + cache->surface_h > surface_h + ALLOW_LARGER_SIZE)) + { + cairo_surface_destroy (cache->surface); + cache->surface = NULL; + if (cache->surface_dirty) + cairo_region_destroy (cache->surface_dirty); + cache->surface_dirty = NULL; + } + + /* Don't allocate a surface if view >= canvas, as we won't + be scrolling then anyway */ + if (cache->surface == NULL && + (view_rect->width < canvas_rect->width || + view_rect->height < canvas_rect->height)) + { + cache->surface_x = -canvas_rect->x; + cache->surface_y = -canvas_rect->y; + cache->surface_w = surface_w; + cache->surface_h = surface_h; + cache->surface = + gdk_window_create_similar_surface (window, + CAIRO_CONTENT_COLOR_ALPHA, + surface_w, surface_h); + rect.x = 0; + rect.y = 0; + rect.width = surface_w; + rect.height = surface_h; + cache->surface_dirty = + cairo_region_create_rectangle (&rect); + } +} + +void +_gtk_pixel_cache_set_position (GtkPixelCache *cache, + cairo_rectangle_int_t *view_rect, + cairo_rectangle_int_t *canvas_rect) +{ + cairo_rectangle_int_t r, view_pos; + cairo_region_t *copy_region; + int new_surf_x, new_surf_y; + cairo_t *backing_cr; + + if (cache->surface == NULL) + return; + + /* Position of view inside canvas */ + view_pos.x = -canvas_rect->x; + view_pos.y = -canvas_rect->y; + view_pos.width = view_rect->width; + view_pos.height = view_rect->height; + + /* Reposition so all is visible */ + if (view_pos.x < cache->surface_x || + view_pos.x + view_pos.width > + cache->surface_x + cache->surface_w || + view_pos.y < cache->surface_y || + view_pos.y + view_pos.height > + cache->surface_y + cache->surface_h) + { + new_surf_x = cache->surface_x; + if (view_pos.x < cache->surface_x) + new_surf_x = MAX (view_pos.x + view_pos.width - cache->surface_w, 0); + else if (view_pos.x + view_pos.width > + cache->surface_x + cache->surface_w) + new_surf_x = MIN (view_pos.x, canvas_rect->width - cache->surface_w); + + new_surf_y = cache->surface_y; + if (view_pos.y < cache->surface_y) + new_surf_y = MAX (view_pos.y + view_pos.height - cache->surface_h, 0); + else if (view_pos.y + view_pos.height > + cache->surface_y + cache->surface_h) + new_surf_y = MIN (view_pos.y, canvas_rect->height - cache->surface_h); + + r.x = 0; + r.y = 0; + r.width = cache->surface_w; + r.height = cache->surface_h; + copy_region = cairo_region_create_rectangle (&r); + + if (cache->surface_dirty) + { + cairo_region_subtract (copy_region, cache->surface_dirty); + cairo_region_destroy (cache->surface_dirty); + cache->surface_dirty = NULL; + } + + cairo_region_translate (copy_region, + cache->surface_x - new_surf_x, + cache->surface_y - new_surf_y); + cairo_region_intersect_rectangle (copy_region, &r); + + backing_cr = cairo_create (cache->surface); + gdk_cairo_region (backing_cr, copy_region); + cairo_clip (backing_cr); + cairo_push_group (backing_cr); + cairo_set_source_surface (backing_cr, cache->surface, + cache->surface_x - new_surf_x, + cache->surface_y - new_surf_y); + cairo_paint (backing_cr); + cairo_pop_group_to_source (backing_cr); + cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (backing_cr); + cairo_destroy (backing_cr); + + cache->surface_x = new_surf_x; + cache->surface_y = new_surf_y; + + cairo_region_xor_rectangle (copy_region, &r); + cache->surface_dirty = copy_region; + } +} + +void +_gtk_pixel_cache_repaint (GtkPixelCache *cache, + GtkPixelCacheDrawFunc draw, + cairo_rectangle_int_t *view_rect, + cairo_rectangle_int_t *canvas_rect, + gpointer user_data) +{ + cairo_t *backing_cr; + + if (cache->surface && + cache->surface_dirty && + !cairo_region_is_empty (cache->surface_dirty)) + { + backing_cr = cairo_create (cache->surface); + gdk_cairo_region (backing_cr, cache->surface_dirty); + cairo_clip (backing_cr); + cairo_translate (backing_cr, + -cache->surface_x - canvas_rect->x - view_rect->x, + -cache->surface_y - canvas_rect->y - view_rect->y); + cairo_set_source_rgba (backing_cr, + 0.0, 0, 0, 0.0); + cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (backing_cr); + + cairo_set_operator (backing_cr, CAIRO_OPERATOR_OVER); + + draw (backing_cr, user_data); + + cairo_destroy (backing_cr); + } + + if (cache->surface_dirty) + { + cairo_region_destroy (cache->surface_dirty); + cache->surface_dirty = NULL; + } +} + +void +_gtk_pixel_cache_draw (GtkPixelCache *cache, + cairo_t *cr, + GdkWindow *window, + /* View position in widget coords */ + cairo_rectangle_int_t *view_rect, + /* Size and position of canvas in view coords */ + cairo_rectangle_int_t *canvas_rect, + GtkPixelCacheDrawFunc draw, + gpointer user_data) +{ + _gtk_pixel_cache_create_surface_if_needed (cache, window, + view_rect, canvas_rect); + _gtk_pixel_cache_set_position (cache, view_rect, canvas_rect); + _gtk_pixel_cache_repaint (cache, draw, view_rect, canvas_rect, user_data); + + if (cache->surface && + /* Don't use backing surface if rendering elsewhere */ + cairo_surface_get_type (cache->surface) == cairo_surface_get_type (cairo_get_target (cr))) + { + cairo_save (cr); + cairo_set_source_surface (cr, cache->surface, + cache->surface_x + view_rect->x + canvas_rect->x, + cache->surface_y + view_rect->y + canvas_rect->y); + cairo_rectangle (cr, view_rect->x, view_rect->x, + view_rect->width, view_rect->height); + cairo_fill (cr); + cairo_restore (cr); + } + else + { + cairo_rectangle (cr, + view_rect->x, view_rect->x, + view_rect->width, view_rect->height); + cairo_clip (cr); + draw (cr, user_data); + } +} diff --git a/gtk/gtkpixelcacheprivate.h b/gtk/gtkpixelcacheprivate.h new file mode 100644 index 0000000000..2b916d0b9c --- /dev/null +++ b/gtk/gtkpixelcacheprivate.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2013 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Alexander Larsson + */ + +#ifndef __GTK_PIXEL_CACHE_PRIVATE_H__ +#define __GTK_PIXEL_CACHE_PRIVATE_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GtkPixelCache GtkPixelCache; + +typedef void (*GtkPixelCacheDrawFunc) (cairo_t *cr, + gpointer user_data); + +GtkPixelCache *_gtk_pixel_cache_new (void); +void _gtk_pixel_cache_free (GtkPixelCache *cache); +void _gtk_pixel_cache_invalidate (GtkPixelCache *cache, + cairo_region_t *region); +void _gtk_pixel_cache_draw (GtkPixelCache *cache, + cairo_t *cr, + GdkWindow *window, + cairo_rectangle_int_t *view_rect, + cairo_rectangle_int_t *canvas_rect, + GtkPixelCacheDrawFunc draw, + gpointer user_data); + + +G_END_DECLS + +#endif /* __GTK_PIXEL_CACHE_PRIVATE_H__ */ diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c index 06f6643b44..c8d47b76df 100644 --- a/gtk/gtkviewport.c +++ b/gtk/gtkviewport.c @@ -32,6 +32,7 @@ #include "gtkprivate.h" #include "gtkscrollable.h" #include "gtktypebuiltins.h" +#include "gtkpixelcacheprivate.h" /** @@ -66,12 +67,7 @@ struct _GtkViewportPrivate GdkWindow *bin_window; GdkWindow *view_window; - int backing_surface_x; - int backing_surface_y; - int backing_surface_w; - int backing_surface_h; - cairo_surface_t *backing_surface; - cairo_region_t *backing_surface_dirty; + GtkPixelCache *pixel_cache; /* GtkScrollablePolicy needs to be checked when * driving the scrollable adjustment values */ @@ -256,6 +252,8 @@ gtk_viewport_init (GtkViewport *viewport) priv->hadjustment = NULL; priv->vadjustment = NULL; + priv->pixel_cache = _gtk_pixel_cache_new (); + viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, NULL); viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, NULL); } @@ -308,10 +306,15 @@ static void gtk_viewport_destroy (GtkWidget *widget) { GtkViewport *viewport = GTK_VIEWPORT (widget); + GtkViewportPrivate *priv = viewport->priv; viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL); viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL); + if (priv->pixel_cache) + _gtk_pixel_cache_free (priv->pixel_cache); + priv->pixel_cache = NULL; + GTK_WIDGET_CLASS (gtk_viewport_parent_class)->destroy (widget); } @@ -663,28 +666,12 @@ gtk_viewport_bin_window_invalidate_handler (GdkWindow *window, gpointer widget; GtkViewport *viewport; GtkViewportPrivate *priv; - cairo_rectangle_int_t r; gdk_window_get_user_data (window, &widget); viewport = GTK_VIEWPORT (widget); priv = viewport->priv; - if (priv->backing_surface_dirty == NULL) - priv->backing_surface_dirty = cairo_region_create (); - - cairo_region_translate (region, - -priv->backing_surface_x, - -priv->backing_surface_y); - cairo_region_union (priv->backing_surface_dirty, region); - cairo_region_translate (region, - priv->backing_surface_x, - priv->backing_surface_y); - - r.x = 0; - r.y = 0; - r.width = priv->backing_surface_w; - r.height = priv->backing_surface_h; - cairo_region_intersect_rectangle (priv->backing_surface_dirty, &r); + _gtk_pixel_cache_invalidate (priv->pixel_cache, region); } static void @@ -783,6 +770,25 @@ gtk_viewport_unrealize (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_viewport_parent_class)->unrealize (widget); } +static void +draw_bin (cairo_t *cr, + gpointer user_data) +{ + GtkWidget *widget = GTK_WIDGET (user_data); + GtkViewport *viewport = GTK_VIEWPORT (widget); + GtkViewportPrivate *priv = viewport->priv; + GtkStyleContext *context; + int x, y; + + context = gtk_widget_get_style_context (widget); + + gdk_window_get_position (priv->bin_window, &x, &y); + gtk_render_background (context, cr, x, y, + gdk_window_get_width (priv->bin_window), + gdk_window_get_height (priv->bin_window)); + GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr); +} + static gint gtk_viewport_draw (GtkWidget *widget, cairo_t *cr) @@ -790,10 +796,6 @@ gtk_viewport_draw (GtkWidget *widget, GtkViewport *viewport = GTK_VIEWPORT (widget); GtkViewportPrivate *priv = viewport->priv; GtkStyleContext *context; - cairo_t *backing_cr; - GtkWidget *child; - int x, y, bin_x, bin_y, new_surf_x, new_surf_y; - cairo_rectangle_int_t view_pos; context = gtk_widget_get_style_context (widget); @@ -810,150 +812,22 @@ gtk_viewport_draw (GtkWidget *widget, gtk_style_context_restore (context); } - if (priv->backing_surface && - /* Don't use backing surface if rendering elsewhere */ - cairo_surface_get_type (priv->backing_surface) == cairo_surface_get_type (cairo_get_target (cr))) + if (gtk_cairo_should_draw_window (cr, priv->bin_window)) { - gdk_window_get_position (priv->bin_window, &bin_x, &bin_y); - view_pos.x = -bin_x; - view_pos.y = -bin_y; - view_pos.width = gdk_window_get_width (priv->view_window); - view_pos.height = gdk_window_get_height (priv->view_window); + cairo_rectangle_int_t view_rect; + cairo_rectangle_int_t canvas_rect; - /* Reposition so all is visible visible */ - if (priv->backing_surface) - { - cairo_rectangle_int_t r; - cairo_region_t *copy_region; - if (view_pos.x < priv->backing_surface_x || - view_pos.x + view_pos.width > - priv->backing_surface_x + priv->backing_surface_w || - view_pos.y < priv->backing_surface_y || - view_pos.y + view_pos.height > - priv->backing_surface_y + priv->backing_surface_h) - { - new_surf_x = priv->backing_surface_x; - if (view_pos.x < priv->backing_surface_x) - new_surf_x = view_pos.x - (priv->backing_surface_w - view_pos.width); - else if (view_pos.x + view_pos.width > - priv->backing_surface_x + priv->backing_surface_w) - new_surf_x = view_pos.x; + gdk_window_get_position (priv->view_window, &view_rect.x, &view_rect.y); + view_rect.width = gdk_window_get_width (priv->view_window); + view_rect.height = gdk_window_get_height (priv->view_window); - new_surf_y = priv->backing_surface_y; - if (view_pos.y < priv->backing_surface_y) - new_surf_y = view_pos.y - (priv->backing_surface_h - view_pos.height); - else if (view_pos.y + view_pos.height > - priv->backing_surface_y + priv->backing_surface_h) - new_surf_y = view_pos.y; + gdk_window_get_position (priv->bin_window, &canvas_rect.x, &canvas_rect.y); + canvas_rect.width = gdk_window_get_width (priv->bin_window); + canvas_rect.height = gdk_window_get_height (priv->bin_window); - r.x = 0; - r.y = 0; - r.width = priv->backing_surface_w; - r.height = priv->backing_surface_h; - copy_region = cairo_region_create_rectangle (&r); - - if (priv->backing_surface_dirty) - { - cairo_region_subtract (copy_region, priv->backing_surface_dirty); - cairo_region_destroy (priv->backing_surface_dirty); - priv->backing_surface_dirty = NULL; - } - - cairo_region_translate (copy_region, - priv->backing_surface_x - new_surf_x, - priv->backing_surface_y - new_surf_y); - cairo_region_intersect_rectangle (copy_region, &r); - - backing_cr = cairo_create (priv->backing_surface); - gdk_cairo_region (backing_cr, copy_region); - cairo_clip (backing_cr); - cairo_push_group (backing_cr); - cairo_set_source_surface (backing_cr, priv->backing_surface, - priv->backing_surface_x - new_surf_x, - priv->backing_surface_y - new_surf_y); - cairo_paint (backing_cr); - cairo_pop_group_to_source (backing_cr); - cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (backing_cr); - cairo_destroy (backing_cr); - - priv->backing_surface_x = new_surf_x; - priv->backing_surface_y = new_surf_y; - - cairo_region_xor_rectangle (copy_region, &r); - priv->backing_surface_dirty = copy_region; - } - } - - if (priv->backing_surface_dirty && - !cairo_region_is_empty (priv->backing_surface_dirty)) - { - backing_cr = cairo_create (priv->backing_surface); - gdk_cairo_region (backing_cr, priv->backing_surface_dirty); - cairo_clip (backing_cr); - cairo_translate (backing_cr, - -priv->backing_surface_x, - -priv->backing_surface_y); - cairo_set_source_rgba (backing_cr, - 0, 0, 0, 0); - cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE); - cairo_paint (backing_cr); - cairo_set_operator (backing_cr, CAIRO_OPERATOR_OVER); - gtk_render_background (context, backing_cr, - 0,0, - gdk_window_get_width (priv->bin_window), - gdk_window_get_height (priv->bin_window)); - child = gtk_bin_get_child (GTK_BIN (widget)); - if (child && gtk_widget_get_visible (child)) { - if (!gtk_widget_get_has_window (child)) - { - GtkAllocation child_allocation; - gtk_widget_get_allocation (child, &child_allocation); - cairo_translate (backing_cr, - child_allocation.x, - child_allocation.y); - } - - gtk_widget_draw (child, backing_cr); - } - - cairo_destroy (backing_cr); - } - - if (priv->backing_surface_dirty) - { - cairo_region_destroy (priv->backing_surface_dirty); - priv->backing_surface_dirty = NULL; - } - - if (gtk_cairo_should_draw_window (cr, priv->bin_window)) - { - gdk_window_get_position (priv->view_window, &x, &y); - cairo_set_source_surface (cr, priv->backing_surface, - priv->backing_surface_x + bin_x + x, - priv->backing_surface_y + bin_y + y); - cairo_rectangle (cr, x, y, - gdk_window_get_width (priv->view_window), - gdk_window_get_height (priv->view_window)); - cairo_fill (cr); - } - } - else - { - /* Don't use backing_surface */ - if (gtk_cairo_should_draw_window (cr, priv->bin_window)) - { - gdk_window_get_position (priv->view_window, &x, &y); - cairo_rectangle (cr, x, y, - gdk_window_get_width (priv->view_window), - gdk_window_get_height (priv->view_window)); - cairo_clip (cr); - gdk_window_get_position (priv->bin_window, &x, &y); - gtk_render_background (context, cr, x, y, - gdk_window_get_width (priv->bin_window), - gdk_window_get_height (priv->bin_window)); - GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr); - } + _gtk_pixel_cache_draw (priv->pixel_cache, cr, priv->bin_window, + &view_rect, &canvas_rect, + draw_bin, widget); } return FALSE; @@ -987,7 +861,6 @@ gtk_viewport_size_allocate (GtkWidget *widget, GtkAdjustment *vadjustment = priv->vadjustment; GtkAllocation child_allocation; GtkWidget *child; - int surface_w, surface_h; border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); @@ -1016,7 +889,6 @@ gtk_viewport_size_allocate (GtkWidget *widget, if (gtk_widget_get_realized (widget)) { GtkAllocation view_allocation; - cairo_rectangle_int_t rect; gdk_window_move_resize (gtk_widget_get_window (widget), allocation->x + border_width, @@ -1035,48 +907,6 @@ gtk_viewport_size_allocate (GtkWidget *widget, - gtk_adjustment_get_value (vadjustment), child_allocation.width, child_allocation.height); - - surface_w = view_allocation.width; - if (child_allocation.width > view_allocation.width) - surface_w = MIN (surface_w + 64, child_allocation.width); - - surface_h = view_allocation.height; - if (child_allocation.height > view_allocation.height) - surface_h = MIN (surface_h + 64, child_allocation.height); - - if (priv->backing_surface != NULL && - (priv->backing_surface_w < view_allocation.width || - priv->backing_surface_w > surface_w + 32 || - priv->backing_surface_h < view_allocation.height || - priv->backing_surface_h > surface_h + 32)) - { - cairo_surface_destroy (priv->backing_surface); - priv->backing_surface = NULL; - if (priv->backing_surface_dirty) - cairo_region_destroy (priv->backing_surface_dirty); - priv->backing_surface_dirty = NULL; - } - - if (priv->backing_surface == NULL && - (view_allocation.width < child_allocation.width || - view_allocation.height < child_allocation.height)) - { - priv->backing_surface_x = gtk_adjustment_get_value (hadjustment); - priv->backing_surface_y = gtk_adjustment_get_value (vadjustment); - priv->backing_surface_w = surface_w; - priv->backing_surface_h = surface_h; - priv->backing_surface_dirty = cairo_region_create (); - priv->backing_surface = - gdk_window_create_similar_surface (priv->bin_window, - CAIRO_CONTENT_COLOR_ALPHA, - surface_w, surface_h); - rect.x = 0; - rect.y = 0; - rect.width = surface_w; - rect.height = surface_h; - cairo_region_union_rectangle (priv->backing_surface_dirty, - &rect); - } } child = gtk_bin_get_child (bin);