Split out offscreen surface from GtkViewport to GtkPixelCache
This will make it easier to do similar scrolling in other widgets.
This commit is contained in:
@@ -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 \
|
||||
|
||||
312
gtk/gtkpixelcache.c
Normal file
312
gtk/gtkpixelcache.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
48
gtk/gtkpixelcacheprivate.h
Normal file
48
gtk/gtkpixelcacheprivate.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_PIXEL_CACHE_PRIVATE_H__
|
||||
#define __GTK_PIXEL_CACHE_PRIVATE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gtkwidget.h>
|
||||
|
||||
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__ */
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user