X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Frenderer-tiles.c;h=70257c0cb8a1149404e4d61a352b7eaa535a6857;hb=729b21ef8f0e73aec8e87acaa09a2c5e85273631;hp=e5f549645d696f67102ddeb3ead6e1da3b777e53;hpb=b4c4a924121c3aa6b2f1eb7570dd3f419d2f4d83;p=geeqie.git diff --git a/src/renderer-tiles.c b/src/renderer-tiles.c index e5f54964..70257c0c 100644 --- a/src/renderer-tiles.c +++ b/src/renderer-tiles.c @@ -1,14 +1,22 @@ /* - * Geeqie - * (C) 2006 John Ellis - * Copyright (C) 2008 - 2012 The Geeqie Team + * Copyright (C) 2006 John Ellis + * Copyright (C) 2008 - 2021 The Geeqie Team * * Author: John Ellis - * Author: Vladimir Nadvornik * - * This software is released under the GNU General Public License (GNU GPL). - * Please read the included file COPYING for more information. - * This software comes with no warranty of any kind, use at your own risk! + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include @@ -50,10 +58,6 @@ typedef enum { } ExifOrientationType; #endif - -/* size to use when breaking up image pane for rendering */ -#define PR_TILE_SIZE 128 - typedef struct _ImageTile ImageTile; typedef struct _QueueData QueueData; @@ -115,7 +119,7 @@ struct _RendererTiles RendererFuncs f; PixbufRenderer *pr; - gint tile_cache_max; /* max mb to use for offscreen buffer */ + gint tile_cache_max; /* max MiB to use for offscreen buffer */ gint tile_width; gint tile_height; @@ -127,18 +131,20 @@ struct _RendererTiles GList *overlay_list; cairo_surface_t *overlay_buffer; - + cairo_surface_t *surface; + guint draw_idle_id; /* event source id */ GdkPixbuf *spare_tile; - + gint stereo_mode; gint stereo_off_x; gint stereo_off_y; - + gint x_scroll; /* allow local adjustment and mirroring */ gint y_scroll; - + + gint hidpi_scale; }; @@ -157,8 +163,6 @@ static void rt_queue(RendererTiles *rt, gint x, gint y, gint w, gint h, static void rt_hierarchy_changed_cb(GtkWidget *widget, GtkWidget *previous_toplevel, gpointer data); static gint rt_queue_draw_idle_cb(gpointer data); -static void renderer_redraw(void *renderer, gint x, gint y, gint w, gint h, - gint clamp, ImageRenderType render, gboolean new_data, gboolean only_existing); #define GET_RIGHT_PIXBUF_OFFSET(rt) \ (( (rt->stereo_mode & PR_STEREO_RIGHT) && !(rt->stereo_mode & PR_STEREO_SWAP)) || \ @@ -174,13 +178,13 @@ static void renderer_redraw(void *renderer, gint x, gint y, gint w, gint h, static void rt_sync_scroll(RendererTiles *rt) { PixbufRenderer *pr = rt->pr; - - rt->x_scroll = (rt->stereo_mode & PR_STEREO_MIRROR) ? - pr->width - pr->vis_width - pr->x_scroll + + rt->x_scroll = (rt->stereo_mode & PR_STEREO_MIRROR) ? + pr->width - pr->vis_width - pr->x_scroll : pr->x_scroll; - - rt->y_scroll = (rt->stereo_mode & PR_STEREO_FLIP) ? - pr->height - pr->vis_height - pr->y_scroll + + rt->y_scroll = (rt->stereo_mode & PR_STEREO_FLIP) ? + pr->height - pr->vis_height - pr->y_scroll : pr->y_scroll; } @@ -203,8 +207,11 @@ static void rt_border_draw(RendererTiles *rt, gint x, gint y, gint w, gint h) if (!window) return; +#if GTK_CHECK_VERSION(3,0,0) + cr = cairo_create(rt->surface); +#else cr = gdk_cairo_create(window); - +#endif if (!pr->pixbuf && !pr->source_tiles_enabled) { @@ -213,12 +220,12 @@ static void rt_border_draw(RendererTiles *rt, gint x, gint y, gint w, gint h) pr->viewport_width, pr->viewport_height, &rx, &ry, &rw, &rh)) { - cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_source_rgb(cr, (double)pr->color.red/65535, (double)pr->color.green/65535, (double)pr->color.blue/65535); cairo_rectangle(cr, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh); cairo_fill(cr); - cairo_destroy(cr); rt_overlay_draw(rt, rx, ry, rw, rh, NULL); } + cairo_destroy(cr); return; } @@ -230,7 +237,7 @@ static void rt_border_draw(RendererTiles *rt, gint x, gint y, gint w, gint h) pr->x_offset, pr->viewport_height, &rx, &ry, &rw, &rh)) { - cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_source_rgb(cr, (double)pr->color.red/65535, (double)pr->color.green/65535, (double)pr->color.blue/65535); cairo_rectangle(cr, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh); cairo_fill(cr); rt_overlay_draw(rt, rx, ry, rw, rh, NULL); @@ -241,7 +248,7 @@ static void rt_border_draw(RendererTiles *rt, gint x, gint y, gint w, gint h) pr->viewport_width - pr->vis_width - pr->x_offset, pr->viewport_height, &rx, &ry, &rw, &rh)) { - cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_source_rgb(cr, (double)pr->color.red/65535, (double)pr->color.green/65535, (double)pr->color.blue/65535); cairo_rectangle(cr, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh); cairo_fill(cr); rt_overlay_draw(rt, rx, ry, rw, rh, NULL); @@ -255,7 +262,7 @@ static void rt_border_draw(RendererTiles *rt, gint x, gint y, gint w, gint h) pr->vis_width, pr->y_offset, &rx, &ry, &rw, &rh)) { - cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_source_rgb(cr, (double)pr->color.red/65535, (double)pr->color.green/65535, (double)pr->color.blue/65535); cairo_rectangle(cr, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh); cairo_fill(cr); rt_overlay_draw(rt, rx, ry, rw, rh, NULL); @@ -266,7 +273,7 @@ static void rt_border_draw(RendererTiles *rt, gint x, gint y, gint w, gint h) pr->vis_width, pr->viewport_height - pr->vis_height - pr->y_offset, &rx, &ry, &rw, &rh)) { - cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_source_rgb(cr, (double)pr->color.red/65535, (double)pr->color.green/65535, (double)pr->color.blue/65535); cairo_rectangle(cr, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh); cairo_fill(cr); rt_overlay_draw(rt, rx, ry, rw, rh, NULL); @@ -490,7 +497,26 @@ static gint pixmap_calc_size(cairo_surface_t *surface) // d = gdk_drawable_get_depth(pixmap); // gdk_drawable_get_size(pixmap, &w, &h); - return PR_TILE_SIZE * PR_TILE_SIZE * 4 / 8; + return options->image.tile_size * options->image.tile_size * 4 / 8; +} + +static void rt_hidpi_aware_draw( + RendererTiles *rt, + cairo_t *cr, + GdkPixbuf *pixbuf, + double x, + double y) +{ +#if GTK_CHECK_VERSION(3, 10, 0) + cairo_surface_t *surface; + surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, rt->hidpi_scale, NULL); + cairo_set_source_surface(cr, surface, x, y); + cairo_fill(cr); + cairo_surface_destroy(surface); +#else + gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y); + cairo_fill(cr); +#endif } static void rt_tile_prepare(RendererTiles *rt, ImageTile *it) @@ -505,7 +531,7 @@ static void rt_tile_prepare(RendererTiles *rt, ImageTile *it) CAIRO_CONTENT_COLOR, rt->tile_width, rt->tile_height); - size = pixmap_calc_size(surface); + size = pixmap_calc_size(surface) * rt->hidpi_scale * rt->hidpi_scale; rt_tile_free_space(rt, size, it); it->surface = surface; @@ -517,9 +543,9 @@ static void rt_tile_prepare(RendererTiles *rt, ImageTile *it) { GdkPixbuf *pixbuf; guint size; - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height); + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->hidpi_scale * rt->tile_width, rt->hidpi_scale * rt->tile_height); - size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height; + size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height * rt->hidpi_scale; rt_tile_free_space(rt, size, it); it->pixbuf = pixbuf; @@ -576,18 +602,17 @@ static void rt_overlay_init_window(RendererTiles *rt, OverlayData *od) od->window = gdk_window_new(gtk_widget_get_window(GTK_WIDGET(pr)), &attributes, attributes_mask); gdk_window_set_user_data(od->window, pr); gdk_window_move(od->window, px + rt->stereo_off_x, py + rt->stereo_off_y); +#if !GTK_CHECK_VERSION(3,0,0) gdk_window_show(od->window); +#endif } static void rt_overlay_draw(RendererTiles *rt, gint x, gint y, gint w, gint h, ImageTile *it) { PixbufRenderer *pr = rt->pr; - GtkWidget *box; GList *work; - box = GTK_WIDGET(pr); - work = rt->overlay_list; while (work) { @@ -599,7 +624,7 @@ static void rt_overlay_draw(RendererTiles *rt, gint x, gint y, gint w, gint h, work = work->next; if (!od->window) rt_overlay_init_window(rt, od); - + rt_overlay_get_position(rt, od, &px, &py, &pw, &ph); if (pr_clip_region(x, y, w, h, px, py, pw, ph, &rx, &ry, &rw, &rh)) { @@ -618,48 +643,16 @@ static void rt_overlay_draw(RendererTiles *rt, gint x, gint y, gint w, gint h, cairo_set_source_surface(cr, it->surface, (pr->x_offset + (it->x - rt->x_scroll)) - rx, (pr->y_offset + (it->y - rt->y_scroll)) - ry); cairo_rectangle(cr, 0, 0, rw, rh); cairo_fill_preserve(cr); - + gdk_cairo_set_source_pixbuf(cr, od->pixbuf, px - rx, py - ry); - cairo_fill (cr); + cairo_fill(cr); cairo_destroy (cr); - + cr = gdk_cairo_create(od->window); cairo_set_source_surface(cr, rt->overlay_buffer, rx - px, ry - py); cairo_rectangle (cr, rx - px, ry - py, rw, rh); cairo_fill (cr); cairo_destroy (cr); - -#if 0 - - -#if GTK_CHECK_VERSION(2,20,0) - gdk_draw_drawable(rt->overlay_buffer, box->style->fg_gc[gtk_widget_get_state(box)], -#else - gdk_draw_drawable(rt->overlay_buffer, box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - it->pixmap, - rx - (pr->x_offset + (it->x - rt->x_scroll)), - ry - (pr->y_offset + (it->y - rt->y_scroll)), - 0, 0, rw, rh); - gdk_draw_pixbuf(rt->overlay_buffer, -#if GTK_CHECK_VERSION(2,20,0) - box->style->fg_gc[gtk_widget_get_state(box)], -#else - box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - od->pixbuf, - rx - px, ry - py, - 0, 0, rw, rh, - pr->dither_quality, rx, ry); -#if GTK_CHECK_VERSION(2,20,0) - gdk_draw_drawable(od->window, box->style->fg_gc[gtk_widget_get_state(box)], -#else - gdk_draw_drawable(od->window, box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - rt->overlay_buffer, - 0, 0, - rx - px, ry - py, rw, rh); -#endif } else { @@ -679,44 +672,16 @@ static void rt_overlay_draw(RendererTiles *rt, gint x, gint y, gint w, gint h, cairo_set_source_rgb(cr, 0, 0, 0); cairo_rectangle(cr, 0, 0, sw, sh); cairo_fill_preserve(cr); - + gdk_cairo_set_source_pixbuf(cr, od->pixbuf, px - sx, py - sy); cairo_fill (cr); cairo_destroy (cr); - + cr = gdk_cairo_create(od->window); cairo_set_source_surface(cr, rt->overlay_buffer, sx - px, sy - py); cairo_rectangle (cr, sx - px, sy - py, sw, sh); cairo_fill(cr); cairo_destroy(cr); - -#if 0 - gdk_draw_rectangle(rt->overlay_buffer, -#if GTK_CHECK_VERSION(2,20,0) - box->style->bg_gc[gtk_widget_get_state(box)], TRUE, -#else - box->style->bg_gc[GTK_WIDGET_STATE(box)], TRUE, -#endif - 0, 0, sw, sh); - gdk_draw_pixbuf(rt->overlay_buffer, -#if GTK_CHECK_VERSION(2,20,0) - box->style->fg_gc[gtk_widget_get_state(box)], -#else - box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - od->pixbuf, - sx - px, sy - py, - 0, 0, sw, sh, - pr->dither_quality, sx, sy); -#if GTK_CHECK_VERSION(2,20,0) - gdk_draw_drawable(od->window, box->style->fg_gc[gtk_widget_get_state(box)], -#else - gdk_draw_drawable(od->window, box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - rt->overlay_buffer, - 0, 0, - sx - px, sy - py, sw, sh); -#endif } } } @@ -729,13 +694,13 @@ static void rt_overlay_queue_draw(RendererTiles *rt, OverlayData *od, gint x1, g gint x, y, w, h; rt_overlay_get_position(rt, od, &x, &y, &w, &h); - + /* add borders */ x -= x1; y -= y1; w += x1 + x2; h += y1 + y2; - + rt_queue(rt, rt->x_scroll - pr->x_offset + x, rt->y_scroll - pr->y_offset + y, w, h, @@ -767,9 +732,9 @@ static void rt_overlay_update_sizes(RendererTiles *rt) { OverlayData *od = work->data; work = work->next; - + if (!od->window) rt_overlay_init_window(rt, od); - + if (od->flags & OVL_RELATIVE) { gint x, y, w, h; @@ -797,9 +762,10 @@ static OverlayData *rt_overlay_find(RendererTiles *rt, gint id) } -gint renderer_tiles_overlay_add(RendererTiles *rt, GdkPixbuf *pixbuf, gint x, gint y, +gint renderer_tiles_overlay_add(void *renderer, GdkPixbuf *pixbuf, gint x, gint y, OverlayRendererFlags flags) { + RendererTiles *rt = (RendererTiles *) renderer; PixbufRenderer *pr = rt->pr; OverlayData *od; gint id; @@ -819,10 +785,14 @@ gint renderer_tiles_overlay_add(RendererTiles *rt, GdkPixbuf *pixbuf, gint x, gi od->flags = flags; rt_overlay_init_window(rt, od); - + rt->overlay_list = g_list_append(rt->overlay_list, od); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_queue_draw(GTK_WIDGET(rt->pr)); +#else rt_overlay_queue_draw(rt, od, 0, 0, 0, 0); +#endif return od->id; } @@ -870,8 +840,35 @@ static void rt_overlay_list_reset_window(RendererTiles *rt) } } -void renderer_tiles_overlay_set(RendererTiles *rt, gint id, GdkPixbuf *pixbuf, gint x, gint y) +#if GTK_CHECK_VERSION(3,0,0) +void renderer_tiles_overlay_set(void *renderer, gint id, GdkPixbuf *pixbuf, gint x, gint y) +{ + RendererTiles *rc = (RendererTiles *)renderer; + PixbufRenderer *pr = rc->pr; + OverlayData *od; + + g_return_if_fail(IS_PIXBUF_RENDERER(pr)); + + od = rt_overlay_find(rc, id); + if (!od) return; + + if (pixbuf) + { + g_object_ref(G_OBJECT(pixbuf)); + g_object_unref(G_OBJECT(od->pixbuf)); + od->pixbuf = pixbuf; + } + else + { + rt_overlay_free(rc, od); + } + + gtk_widget_queue_draw(GTK_WIDGET(rc->pr)); +} +#else +void renderer_tiles_overlay_set(void *renderer, gint id, GdkPixbuf *pixbuf, gint x, gint y) { + RendererTiles *rt = (RendererTiles *) renderer; PixbufRenderer *pr = rt->pr; OverlayData *od; @@ -903,9 +900,11 @@ void renderer_tiles_overlay_set(RendererTiles *rt, gint id, GdkPixbuf *pixbuf, g rt_overlay_free(rt, od); } } +#endif -gboolean renderer_tiles_overlay_get(RendererTiles *rt, gint id, GdkPixbuf **pixbuf, gint *x, gint *y) +gboolean renderer_tiles_overlay_get(void *renderer, gint id, GdkPixbuf **pixbuf, gint *x, gint *y) { + RendererTiles *rt = (RendererTiles *) renderer; PixbufRenderer *pr = rt->pr; OverlayData *od; @@ -935,7 +934,7 @@ static void rt_hierarchy_changed_cb(GtkWidget *widget, GtkWidget *previous_tople static GdkPixbuf *rt_get_spare_tile(RendererTiles *rt) { - if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height); + if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width * rt->hidpi_scale, rt->tile_height * rt->hidpi_scale); return rt->spare_tile; } @@ -950,7 +949,7 @@ static void rt_tile_rotate_90_clockwise(RendererTiles *rt, GdkPixbuf **tile, gin guchar *sp, *dp; guchar *ip, *spi, *dpi; gint i, j; - gint tw = rt->tile_width; + gint tw = rt->tile_width * rt->hidpi_scale; srs = gdk_pixbuf_get_rowstride(src); s_pix = gdk_pixbuf_get_pixels(src); @@ -986,7 +985,7 @@ static void rt_tile_rotate_90_counter_clockwise(RendererTiles *rt, GdkPixbuf **t guchar *sp, *dp; guchar *ip, *spi, *dpi; gint i, j; - gint th = rt->tile_height; + gint th = rt->tile_height * rt->hidpi_scale; srs = gdk_pixbuf_get_rowstride(src); s_pix = gdk_pixbuf_get_pixels(src); @@ -1023,7 +1022,7 @@ static void rt_tile_mirror_only(RendererTiles *rt, GdkPixbuf **tile, gint x, gin guchar *spi, *dpi; gint i, j; - gint tw = rt->tile_width; + gint tw = rt->tile_width * rt->hidpi_scale; srs = gdk_pixbuf_get_rowstride(src); s_pix = gdk_pixbuf_get_pixels(src); @@ -1057,14 +1056,13 @@ static void rt_tile_mirror_and_flip(RendererTiles *rt, GdkPixbuf **tile, gint x, gint srs, drs; guchar *s_pix, *d_pix; guchar *sp, *dp; - guchar *spi, *dpi; + guchar *dpi; gint i, j; - gint tw = rt->tile_width; - gint th = rt->tile_height; + gint tw = rt->tile_width * rt->hidpi_scale; + gint th = rt->tile_height * rt->hidpi_scale; srs = gdk_pixbuf_get_rowstride(src); s_pix = gdk_pixbuf_get_pixels(src); - spi = s_pix + (x * COLOR_BYTES); dest = rt_get_spare_tile(rt); drs = gdk_pixbuf_get_rowstride(dest); @@ -1096,7 +1094,7 @@ static void rt_tile_flip_only(RendererTiles *rt, GdkPixbuf **tile, gint x, gint guchar *sp, *dp; guchar *spi, *dpi; gint i; - gint th = rt->tile_height; + gint th = rt->tile_height * rt->hidpi_scale; srs = gdk_pixbuf_get_rowstride(src); s_pix = gdk_pixbuf_get_pixels(src); @@ -1178,13 +1176,10 @@ static gboolean rt_source_tile_render(RendererTiles *rt, ImageTile *it, gboolean new_data, gboolean fast) { PixbufRenderer *pr = rt->pr; - GtkWidget *box; GList *list; GList *work; gboolean draw = FALSE; - box = GTK_WIDGET(pr); - if (pr->zoom == 1.0 || pr->scale == 1.0) { list = pr_source_tile_compute_region(pr, it->x + x, it->y + y, w, h, TRUE); @@ -1203,34 +1198,17 @@ static gboolean rt_source_tile_render(RendererTiles *rt, ImageTile *it, { cairo_t *cr; cr = cairo_create(it->surface); - cairo_rectangle (cr, rx - st->x, ry - st->y, rw, rh); + cairo_rectangle (cr, rx - it->x, ry - it->y, rw, rh); if (st->blank) { cairo_set_source_rgb(cr, 0, 0, 0); -#if 0 - gdk_draw_rectangle(it->pixmap, box->style->black_gc, TRUE, - rx - st->x, ry - st->y, rw, rh); -#endif + cairo_fill (cr); } else /* (pr->zoom == 1.0 || pr->scale == 1.0) */ { - gdk_cairo_set_source_pixbuf(cr, st->pixbuf, it->x + st->x, it->y + st->y); -#if 0 - gdk_draw_pixbuf(it->pixmap, -#if GTK_CHECK_VERSION(2,20,0) - box->style->fg_gc[gtk_widget_get_state(box)], -#else - box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - st->pixbuf, - rx - st->x, ry - st->y, - rx - it->x, ry - it->y, - rw, rh, - pr->dither_quality, rx, ry); -#endif + rt_hidpi_aware_draw(rt, cr, st->pixbuf, -it->x + st->x, -it->y + st->y); } - cairo_fill (cr); cairo_destroy (cr); } } @@ -1285,10 +1263,6 @@ static gboolean rt_source_tile_render(RendererTiles *rt, ImageTile *it, cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill (cr); cairo_destroy (cr); -#if 0 - gdk_draw_rectangle(it->pixmap, box->style->black_gc, TRUE, - rx - st->x, ry - st->y, rw, rh); -#endif } else { @@ -1315,43 +1289,124 @@ static gboolean rt_source_tile_render(RendererTiles *rt, ImageTile *it, return draw; } -static void rt_tile_get_region(gboolean has_alpha, +/** + * @brief + * @param has_alpha + * @param ignore_alpha + * @param src + * @param dest + * @param pb_x + * @param pb_y + * @param pb_w + * @param pb_h + * @param offset_x + * @param offset_y + * @param scale_x + * @param scale_y + * @param interp_type + * @param check_x + * @param check_y + * @param wide_image Used as a work-around for a GdkPixbuf problem. Set when image width is > 32767. Problem exhibited with gdk_pixbuf_copy_area() and GDK_INTERP_NEAREST. See #772 on GitHub Geeqie + * + * + */ +static void rt_tile_get_region(gboolean has_alpha, gboolean ignore_alpha, const GdkPixbuf *src, GdkPixbuf *dest, int pb_x, int pb_y, int pb_w, int pb_h, double offset_x, double offset_y, double scale_x, double scale_y, GdkInterpType interp_type, - int check_x, int check_y) + int check_x, int check_y, gboolean wide_image) { + GdkPixbuf* tmppixbuf; + gint srs; + gint drs; + gint x; + gint y; + gint c; + guchar *psrc; + guchar *pdst; + if (!has_alpha) { if (scale_x == 1.0 && scale_y == 1.0) { - gdk_pixbuf_copy_area(src, - -offset_x + pb_x, -offset_y + pb_y, - pb_w, pb_h, - dest, - pb_x, pb_y); - } + if (wide_image) + { + srs = gdk_pixbuf_get_rowstride(src); + drs = gdk_pixbuf_get_rowstride(dest); + psrc = gdk_pixbuf_get_pixels(src); + pdst = gdk_pixbuf_get_pixels(dest); + for (y = 0; y < pb_h; y++) + { + for (x = 0; x < pb_w; x++) + { + for (c = 0; c < 3; c++) + { + pdst[(y * drs) + x*3 + c] = psrc[(-(int)offset_y + pb_y + y) * srs + (-(int)offset_x + pb_x+x)*3 + c]; + } + } + } + } + else + { + gdk_pixbuf_copy_area(src, + -offset_x + pb_x, -offset_y + pb_y, + pb_w, pb_h, + dest, + pb_x, pb_y); + } + } else { - gdk_pixbuf_scale(src, dest, - pb_x, pb_y, pb_w, pb_h, - offset_x, - offset_y, - scale_x, scale_y, - interp_type); + gdk_pixbuf_scale(src, dest, + pb_x, pb_y, pb_w, pb_h, + offset_x, + offset_y, + scale_x, scale_y, + (wide_image && interp_type == GDK_INTERP_NEAREST) ? GDK_INTERP_TILES : interp_type); } } else { - gdk_pixbuf_composite_color(src, dest, - pb_x, pb_y, pb_w, pb_h, - offset_x, - offset_y, - scale_x, scale_y, - interp_type, - 255, check_x, check_y, - PR_ALPHA_CHECK_SIZE, PR_ALPHA_CHECK1, PR_ALPHA_CHECK2); + if (ignore_alpha) + { + tmppixbuf = gdk_pixbuf_add_alpha(src, FALSE, 0, 0, 0); + + pixbuf_ignore_alpha_rect(tmppixbuf, 0, 0, gdk_pixbuf_get_width(src), gdk_pixbuf_get_height(src)); + + gdk_pixbuf_composite_color(tmppixbuf, dest, + pb_x, pb_y, pb_w, pb_h, + offset_x, + offset_y, + scale_x, scale_y, + (scale_x == 1.0 && scale_y == 1.0) ? GDK_INTERP_NEAREST : interp_type, + 255, check_x, check_y, + PR_ALPHA_CHECK_SIZE, + ((options->image.alpha_color_1.red << 8 & 0x00FF0000) + + (options->image.alpha_color_1.green & 0x00FF00) + + (options->image.alpha_color_1.blue >> 8 & 0x00FF)), + ((options->image.alpha_color_2.red << 8 & 0x00FF0000) + + (options->image.alpha_color_2.green & 0x00FF00) + + (options->image.alpha_color_2.blue >> 8 & 0x00FF))); + g_object_unref(tmppixbuf); + } + else + { + gdk_pixbuf_composite_color(src, dest, + pb_x, pb_y, pb_w, pb_h, + offset_x, + offset_y, + scale_x, scale_y, + (scale_x == 1.0 && scale_y == 1.0) ? GDK_INTERP_NEAREST : interp_type, + 255, check_x, check_y, + PR_ALPHA_CHECK_SIZE, + ((options->image.alpha_color_1.red << 8 & 0x00FF0000) + + (options->image.alpha_color_1.green & 0x00FF00) + + (options->image.alpha_color_1.blue >> 8 & 0x00FF)), + ((options->image.alpha_color_2.red << 8 & 0x00FF0000) + + (options->image.alpha_color_2.green & 0x00FF00) + + (options->image.alpha_color_2.blue >> 8 & 0x00FF))); + } } } @@ -1375,10 +1430,10 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, gboolean new_data, gboolean fast) { PixbufRenderer *pr = rt->pr; - GtkWidget *box; gboolean has_alpha; gboolean draw = FALSE; gint orientation = rt_get_orientation(rt); + gboolean wide_image = FALSE; if (it->render_todo == TILE_RENDER_NONE && it->surface && !new_data) return; @@ -1403,9 +1458,7 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, rt_tile_prepare(rt, it); has_alpha = (pr->pixbuf && gdk_pixbuf_get_has_alpha(pr->pixbuf)); - box = GTK_WIDGET(pr); - - /* FIXME checker colors for alpha should be configurable, + /** @FIXME checker colors for alpha should be configurable, * also should be drawn for blank = TRUE */ @@ -1418,44 +1471,11 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill (cr); cairo_destroy (cr); -#if 0 - gdk_draw_rectangle(it->pixmap, box->style->black_gc, TRUE, - 0, 0, it->w, it->h); -#endif } else if (pr->source_tiles_enabled) { draw = rt_source_tile_render(rt, it, x, y, w, h, new_data, fast); } - else if ((pr->zoom == 1.0 || pr->scale == 1.0) && - pr->aspect_ratio == 1.0 && - !has_alpha && - orientation == EXIF_ORIENTATION_TOP_LEFT && - !(pr->func_post_process && !(pr->post_process_slow && fast)) && - !(rt->stereo_mode & PR_STEREO_ANAGLYPH)) - { - /* special case: faster, simple, scale 1.0, base orientation, no postprocessing */ - cairo_t *cr; - cr = cairo_create(it->surface); - cairo_rectangle (cr, x, y, w, h); - gdk_cairo_set_source_pixbuf(cr, pr->pixbuf, -it->x - GET_RIGHT_PIXBUF_OFFSET(rt), -it->y); - cairo_fill (cr); - cairo_destroy (cr); - -#if 0 - gdk_draw_pixbuf(it->pixmap, -#if GTK_CHECK_VERSION(2,20,0) - box->style->fg_gc[gtk_widget_get_state(box)], -#else - box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - pr->pixbuf, - it->x + x + GET_RIGHT_PIXBUF_OFFSET(rt), it->y + y, - x, y, - w, h, - pr->dither_quality, it->x + x, it->y + y); -#endif - } else { gdouble scale_x, scale_y; @@ -1465,8 +1485,8 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, if (pr->image_width == 0 || pr->image_height == 0) return; - scale_x = (gdouble)pr->width / pr->image_width; - scale_y = (gdouble)pr->height / pr->image_height; + scale_x = rt->hidpi_scale * (gdouble)pr->width / pr->image_width; + scale_y = rt->hidpi_scale * (gdouble)pr->height / pr->image_height; pr_tile_coords_map_orientation(orientation, it->x, it->y, pr->width, pr->height, @@ -1478,6 +1498,13 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, &pb_x, &pb_y, &pb_w, &pb_h); + src_x *= rt->hidpi_scale; + src_y *= rt->hidpi_scale; + pb_x *= rt->hidpi_scale; + pb_y *= rt->hidpi_scale; + pb_w *= rt->hidpi_scale; + pb_h *= rt->hidpi_scale; + switch (orientation) { gdouble tmp; @@ -1493,30 +1520,31 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, /* nothing to do */ break; } - + /* HACK: The pixbuf scalers get kinda buggy(crash) with extremely * small sizes for anything but GDK_INTERP_NEAREST */ if (pr->width < PR_MIN_SCALE_SIZE || pr->height < PR_MIN_SCALE_SIZE) fast = TRUE; + if (pr->image_width > 32767) wide_image = TRUE; - rt_tile_get_region(has_alpha, + rt_tile_get_region(has_alpha, pr->ignore_alpha, pr->pixbuf, it->pixbuf, pb_x, pb_y, pb_w, pb_h, (gdouble) 0.0 - src_x - GET_RIGHT_PIXBUF_OFFSET(rt) * scale_x, (gdouble) 0.0 - src_y, scale_x, scale_y, (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality, - it->x + pb_x, it->y + pb_y); - if (rt->stereo_mode & PR_STEREO_ANAGLYPH && + it->x + pb_x, it->y + pb_y, wide_image); + if (rt->stereo_mode & PR_STEREO_ANAGLYPH && (pr->stereo_pixbuf_offset_right > 0 || pr->stereo_pixbuf_offset_left > 0)) { GdkPixbuf *right_pb = rt_get_spare_tile(rt); - rt_tile_get_region(has_alpha, + rt_tile_get_region(has_alpha, pr->ignore_alpha, pr->pixbuf, right_pb, pb_x, pb_y, pb_w, pb_h, (gdouble) 0.0 - src_x - GET_LEFT_PIXBUF_OFFSET(rt) * scale_x, (gdouble) 0.0 - src_y, scale_x, scale_y, (fast) ? GDK_INTERP_NEAREST : pr->zoom_quality, - it->x + pb_x, it->y + pb_y); + it->x + pb_x, it->y + pb_y, wide_image); pr_create_anaglyph(rt->stereo_mode, it->pixbuf, right_pb, pb_x, pb_y, pb_w, pb_h); /* do not care about freeing spare_tile, it will be reused */ } @@ -1533,31 +1561,9 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it, cr = cairo_create(it->surface); cairo_rectangle (cr, x, y, w, h); - gdk_cairo_set_source_pixbuf(cr, it->pixbuf, 0, 0); - cairo_fill (cr); + rt_hidpi_aware_draw(rt, cr, it->pixbuf, 0, 0); cairo_destroy (cr); -#if 0 - gdk_draw_pixbuf(it->pixmap, -#if GTK_CHECK_VERSION(2,20,0) - box->style->fg_gc[gtk_widget_get_state(box)], -#else - box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - it->pixbuf, - x, y, - x, y, - w, h, - pr->dither_quality, it->x + x, it->y + y); -#endif } - -#if 0 - /* enable this line for debugging the edges of tiles */ - gdk_draw_rectangle(it->pixmap, box->style->white_gc, - FALSE, 0, 0, it->w, it->h); - gdk_draw_rectangle(it->pixmap, box->style->white_gc, - FALSE, x, y, w, h); -#endif } @@ -1578,7 +1584,7 @@ static void rt_tile_expose(RendererTiles *rt, ImageTile *it, } if (it->x + x + w > rt->x_scroll + pr->vis_width) { - w = rt->x_scroll + pr->vis_width - it->x - x; + w = rt->x_scroll + pr->vis_width - it->x - x; } if (w < 1) return; if (it->y + y < rt->y_scroll) @@ -1588,7 +1594,7 @@ static void rt_tile_expose(RendererTiles *rt, ImageTile *it, } if (it->y + y + h > rt->y_scroll + pr->vis_height) { - h = rt->y_scroll + pr->vis_height - it->y - y; + h = rt->y_scroll + pr->vis_height - it->y - y; } if (h < 1) return; @@ -1597,22 +1603,16 @@ static void rt_tile_expose(RendererTiles *rt, ImageTile *it, box = GTK_WIDGET(pr); window = gtk_widget_get_window(box); +#if GTK_CHECK_VERSION(3,0,0) + cr = cairo_create(rt->surface); +#else cr = gdk_cairo_create(window); +#endif cairo_set_source_surface(cr, it->surface, pr->x_offset + (it->x - rt->x_scroll) + rt->stereo_off_x, pr->y_offset + (it->y - rt->y_scroll) + rt->stereo_off_y); cairo_rectangle (cr, pr->x_offset + (it->x - rt->x_scroll) + x + rt->stereo_off_x, pr->y_offset + (it->y - rt->y_scroll) + y + rt->stereo_off_y, w, h); cairo_fill (cr); cairo_destroy (cr); -#if 0 -#if GTK_CHECK_VERSION(2,20,0) - gdk_draw_drawable(window, box->style->fg_gc[gtk_widget_get_state(box)], -#else - gdk_draw_drawable(window, box->style->fg_gc[GTK_WIDGET_STATE(box)], -#endif - it->pixmap, x, y, - pr->x_offset + (it->x - rt->x_scroll) + x + rt->stereo_off_x, pr->y_offset + (it->y - rt->y_scroll) + y + rt->stereo_off_y, w, h); -#endif - if (rt->overlay_list) { rt_overlay_draw(rt, pr->x_offset + (it->x - rt->x_scroll) + x, @@ -1620,6 +1620,10 @@ static void rt_tile_expose(RendererTiles *rt, ImageTile *it, w, h, it); } + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_queue_draw(GTK_WIDGET(rt->pr)); +#endif } @@ -1639,8 +1643,8 @@ static gboolean rt_tile_is_visible(RendererTiles *rt, ImageTile *it) static gint rt_get_queued_area(GList *work) { gint area = 0; - - while (work) + + while (work) { QueueData *qd = work->data; area += qd->w * qd->h; @@ -1655,15 +1659,15 @@ static gboolean rt_queue_schedule_next_draw(RendererTiles *rt, gboolean force_se PixbufRenderer *pr = rt->pr; gfloat percent; gint visible_area = pr->vis_width * pr->vis_height; - + if (!pr->loading) { - /* 2pass prio */ + /* 2pass prio */ DEBUG_2("redraw priority: 2pass"); rt->draw_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, rt_queue_draw_idle_cb, rt, NULL); return FALSE; } - + if (visible_area == 0) { /* not known yet */ @@ -1673,7 +1677,7 @@ static gboolean rt_queue_schedule_next_draw(RendererTiles *rt, gboolean force_se { percent = 100.0 * rt_get_queued_area(rt->draw_queue) / visible_area; } - + if (percent > 10.0) { /* we have enough data for starting intensive redrawing */ @@ -1681,7 +1685,7 @@ static gboolean rt_queue_schedule_next_draw(RendererTiles *rt, gboolean force_se rt->draw_idle_id = g_idle_add_full(GDK_PRIORITY_REDRAW, rt_queue_draw_idle_cb, rt, NULL); return FALSE; } - + if (percent < 1.0 || force_set) { /* queue is (almost) empty, wait 50 ms*/ @@ -1689,12 +1693,12 @@ static gboolean rt_queue_schedule_next_draw(RendererTiles *rt, gboolean force_se rt->draw_idle_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 50, rt_queue_draw_idle_cb, rt, NULL); return FALSE; } - + /* keep the same priority as before */ DEBUG_2("redraw priority: no change %.2f %%", percent); return TRUE; } - + static gboolean rt_queue_draw_idle_cb(gpointer data) { @@ -1732,11 +1736,7 @@ static gboolean rt_queue_draw_idle_cb(gpointer data) fast = FALSE; } -#if GTK_CHECK_VERSION(2,20,0) - if (gtk_widget_get_realized(pr)) -#else - if (GTK_WIDGET_REALIZED(pr)) -#endif + if (gtk_widget_get_realized(GTK_WIDGET(pr))) { if (rt_tile_is_visible(rt, qd->it)) { @@ -2000,13 +2000,14 @@ static void rt_queue(RendererTiles *rt, gint x, gint y, gint w, gint h, } } -static void rt_scroll(RendererTiles *rt, gint x_off, gint y_off) +static void rt_scroll(void *renderer, gint x_off, gint y_off) { + RendererTiles *rt = (RendererTiles *) renderer; PixbufRenderer *pr = rt->pr; rt_sync_scroll(rt); if (rt->stereo_mode & PR_STEREO_MIRROR) x_off = -x_off; - if (rt->stereo_mode & PR_STEREO_FLIP) y_off = -y_off; + if (rt->stereo_mode & PR_STEREO_FLIP) y_off = -y_off; gint w = pr->vis_width - abs(x_off); gint h = pr->vis_height - abs(y_off); @@ -2021,10 +2022,6 @@ static void rt_scroll(RendererTiles *rt, gint x_off, gint y_off) { gint x1, y1; gint x2, y2; - GtkWidget *box; - GdkWindow *window; -// GdkGC *gc; - GdkEvent *event; cairo_t *cr; cairo_surface_t *surface; @@ -2050,11 +2047,19 @@ static void rt_scroll(RendererTiles *rt, gint x_off, gint y_off) y2 = abs(y_off); } +#if GTK_CHECK_VERSION(3,0,0) + cr = cairo_create(rt->surface); + surface = rt->surface; +#else + GtkWidget *box; + GdkWindow *window; + box = GTK_WIDGET(pr); window = gtk_widget_get_window(box); cr = gdk_cairo_create(window); surface = cairo_get_target(cr); +#endif /* clipping restricts the intermediate surface's size, so it's a good idea * to use it. */ cairo_rectangle(cr, x1 + pr->x_offset + rt->stereo_off_x, y1 + pr->y_offset + rt->stereo_off_y, w, h); @@ -2067,15 +2072,6 @@ static void rt_scroll(RendererTiles *rt, gint x_off, gint y_off) cairo_pop_group_to_source(cr); cairo_paint(cr); cairo_destroy(cr); -#if 0 - gc = gdk_gc_new(window); - gdk_gc_set_exposures(gc, TRUE); - gdk_draw_drawable(window, gc, - window, - x2 + pr->x_offset + rt->stereo_off_x, y2 + pr->y_offset + rt->stereo_off_y, - x1 + pr->x_offset + rt->stereo_off_x, y1 + pr->y_offset + rt->stereo_off_y, w, h); - g_object_unref(gc); -#endif rt_overlay_queue_all(rt, x2, y2, x1, y1); @@ -2090,27 +2086,11 @@ static void rt_scroll(RendererTiles *rt, gint x_off, gint y_off) } if (h > 0) { - /* FIXME, to optimize this, remove overlap */ + /** @FIXME to optimize this, remove overlap */ rt_queue(rt, rt->x_scroll, y_off > 0 ? rt->y_scroll + (pr->vis_height - h) : rt->y_scroll, pr->vis_width, h, TRUE, TILE_RENDER_ALL, FALSE, FALSE); } - - /* process exposures here, "expose_event" seems to miss a few with obstructed windows */ -#if ! GTK_CHECK_VERSION(2,18,0) - while ((event = gdk_event_get_graphics_expose(window)) != NULL) - { - renderer_redraw((void *) rt, event->expose.area.x, event->expose.area.y, event->expose.area.width, event->expose.area.height, - FALSE, TILE_RENDER_ALL, FALSE, FALSE); - - if (event->expose.count == 0) - { - gdk_event_free(event); - break; - } - gdk_event_free(event); - } -#endif } } @@ -2143,15 +2123,14 @@ static void renderer_area_changed(void *renderer, gint src_x, gint src_y, gint s rt_queue(rt, x1, y1, x2 - x1, y2 - y1, FALSE, TILE_RENDER_AREA, TRUE, TRUE); } -static void renderer_redraw(void *renderer, gint x, gint y, gint w, gint h, +static void renderer_redraw(RendererTiles *rt, gint x, gint y, gint w, gint h, gint clamp, ImageRenderType render, gboolean new_data, gboolean only_existing) { - RendererTiles *rt = (RendererTiles *)renderer; PixbufRenderer *pr = rt->pr; x -= rt->stereo_off_x; y -= rt->stereo_off_y; - + rt_border_draw(rt, x, y, w, h); x = MAX(0, x - pr->x_offset + pr->x_scroll); @@ -2164,20 +2143,22 @@ static void renderer_redraw(void *renderer, gint x, gint y, gint w, gint h, clamp, render, new_data, only_existing); } -static void renderer_queue_clear(void *renderer) +static void renderer_update_pixbuf(void *renderer, gboolean lazy) { rt_queue_clear((RendererTiles *)renderer); } -static void renderer_border_clear(void *renderer) +static void renderer_update_zoom(void *renderer, gboolean lazy) { - rt_border_clear((RendererTiles *)renderer); -} - + RendererTiles *rt = (RendererTiles *)renderer; + PixbufRenderer *pr = rt->pr; -static void renderer_invalidate_all(void *renderer) -{ rt_tile_invalidate_all((RendererTiles *)renderer); + if (!lazy) + { + renderer_redraw(renderer, 0, 0, pr->width, pr->height, TRUE, TILE_RENDER_ALL, TRUE, FALSE); + } + rt_border_clear(rt); } static void renderer_invalidate_region(void *renderer, gint x, gint y, gint w, gint h) @@ -2185,29 +2166,24 @@ static void renderer_invalidate_region(void *renderer, gint x, gint y, gint w, g rt_tile_invalidate_region((RendererTiles *)renderer, x, y, w, h); } -static void renderer_overlay_draw(void *renderer, gint x, gint y, gint w, gint h) -{ - rt_overlay_draw((RendererTiles *)renderer, x, y, w, h, NULL); -} - -static void renderer_update_sizes(void *renderer) +static void renderer_update_viewport(void *renderer) { RendererTiles *rt = (RendererTiles *)renderer; rt->stereo_off_x = 0; rt->stereo_off_y = 0; - - if (rt->stereo_mode & PR_STEREO_RIGHT) + + if (rt->stereo_mode & PR_STEREO_RIGHT) { - if (rt->stereo_mode & PR_STEREO_HORIZ) + if (rt->stereo_mode & PR_STEREO_HORIZ) { rt->stereo_off_x = rt->pr->viewport_width; } - else if (rt->stereo_mode & PR_STEREO_VERT) + else if (rt->stereo_mode & PR_STEREO_VERT) { rt->stereo_off_y = rt->pr->viewport_height; } - else if (rt->stereo_mode & PR_STEREO_FIXED) + else if (rt->stereo_mode & PR_STEREO_FIXED) { rt->stereo_off_x = rt->pr->stereo_fixed_x_right; rt->stereo_off_y = rt->pr->stereo_fixed_y_right; @@ -2215,7 +2191,7 @@ static void renderer_update_sizes(void *renderer) } else { - if (rt->stereo_mode & PR_STEREO_FIXED) + if (rt->stereo_mode & PR_STEREO_FIXED) { rt->stereo_off_x = rt->pr->stereo_fixed_x_left; rt->stereo_off_y = rt->pr->stereo_fixed_y_left; @@ -2224,6 +2200,7 @@ static void renderer_update_sizes(void *renderer) DEBUG_1("update size: %p %d %d %d %d", rt, rt->stereo_off_x, rt->stereo_off_y, rt->pr->viewport_width, rt->pr->viewport_height); rt_sync_scroll(rt); rt_overlay_update_sizes(rt); + rt_border_clear(rt); } static void renderer_stereo_set(void *renderer, gint stereo_mode) @@ -2247,32 +2224,168 @@ static void renderer_free(void *renderer) g_free(rt); } +#if GTK_CHECK_VERSION(3,0,0) +static gboolean rt_realize_cb(GtkWidget *widget, gpointer data) +{ + RendererTiles *rt = (RendererTiles *)data; + cairo_t *cr; + + if (!rt->surface) + { + rt->surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR, gtk_widget_get_allocated_width(widget), gtk_widget_get_allocated_height(widget)); + + cr = cairo_create(rt->surface); + cairo_set_source_rgb(cr, (gdouble)options->image.border_color.red /65535, (gdouble)options->image.border_color.green / 65535, (gdouble)options->image.border_color.blue / 65535); + cairo_paint(cr); + cairo_destroy(cr); + } + + return FALSE; +} + +static gboolean rt_size_allocate_cb(GtkWidget *widget, GdkRectangle *allocation, gpointer data) +{ + RendererTiles *rt = data; + cairo_t *cr; + cairo_surface_t *old_surface; + + if (gtk_widget_get_realized(GTK_WIDGET(rt->pr))) + { + old_surface = rt->surface; + rt->surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget), CAIRO_CONTENT_COLOR, allocation->width, allocation->height); + + cr = cairo_create(rt->surface); + + cairo_set_source_rgb(cr, (gdouble)options->image.border_color.red / 65535, (gdouble)options->image.border_color.green / 65535, (gdouble)options->image.border_color.blue / 65535); + cairo_paint(cr); + cairo_set_source_surface(cr, old_surface, 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + cairo_surface_destroy(old_surface); + + renderer_redraw(rt, allocation->x, allocation->y, allocation->width, allocation->height, FALSE, TILE_RENDER_ALL, FALSE, FALSE); + } + + return FALSE; +} + +static gboolean rt_draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data) +{ + RendererTiles *rt = (RendererTiles *)data; + GList *work; + OverlayData *od; + + if (rt->stereo_mode & (PR_STEREO_HORIZ | PR_STEREO_VERT)) + { + cairo_push_group(cr); + cairo_set_source_rgb(cr, (double)rt->pr->color.red / 65535, (double)rt->pr->color.green / 65535, (double)rt->pr->color.blue / 65535); + + if (rt->stereo_mode & PR_STEREO_HORIZ) + { + cairo_rectangle(cr, rt->stereo_off_x, 0, rt->pr->viewport_width, rt->pr->viewport_height); + } + else + { + cairo_rectangle(cr, 0, rt->stereo_off_y, rt->pr->viewport_width, rt->pr->viewport_height); + } + cairo_clip(cr); + cairo_paint(cr); + + cairo_rectangle(cr, rt->pr->x_offset + rt->stereo_off_x, rt->pr->y_offset + rt->stereo_off_y, rt->pr->vis_width, rt->pr->vis_height); + cairo_clip(cr); + cairo_set_source_surface(cr, rt->surface, 0, 0); + cairo_paint(cr); + + cairo_pop_group_to_source(cr); + cairo_paint(cr); + } + else + { + cairo_set_source_surface(cr, rt->surface, 0, 0); + cairo_paint(cr); + } + + work = rt->overlay_list; + while (work) + { + od = work->data; + gint px, py, pw, ph; + pw = gdk_pixbuf_get_width(od->pixbuf); + ph = gdk_pixbuf_get_height(od->pixbuf); + px = od->x; + py = od->y; + + if (od->flags & OVL_RELATIVE) + { + if (px < 0) px = rt->pr->viewport_width - pw + px; + if (py < 0) py = rt->pr->viewport_height - ph + py; + } + + gdk_cairo_set_source_pixbuf(cr, od->pixbuf, px, py); + cairo_paint(cr); + work = work->next; + } + + return FALSE; +} + +#else +static gboolean rt_expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + RendererTiles *rt = (RendererTiles *)data; + if (gtk_widget_is_drawable(widget)) + { + if (gtk_widget_get_has_window(widget)) + { + if (event->window != gtk_widget_get_window(widget)) + { + GdkRectangle area; + + gdk_window_get_position(event->window, &area.x, &area.y); + area.x += event->area.x; + area.y += event->area.y; + area.width = event->area.width; + area.height = event->area.height; + renderer_redraw(rt, area.x, area.y, area.width, area.height, + FALSE, TILE_RENDER_ALL, FALSE, FALSE); + + } + else + { + renderer_redraw(rt, event->area.x, event->area.y, event->area.width, event->area.height, + FALSE, TILE_RENDER_ALL, FALSE, FALSE); + } + } + } + + return FALSE; +} +#endif + + RendererFuncs *renderer_tiles_new(PixbufRenderer *pr) { RendererTiles *rt = g_new0(RendererTiles, 1); - + rt->pr = pr; - - rt->f.redraw = renderer_redraw; + rt->f.area_changed = renderer_area_changed; - rt->f.queue_clear = renderer_queue_clear; - rt->f.border_clear = renderer_border_clear; + rt->f.update_pixbuf = renderer_update_pixbuf; rt->f.free = renderer_free; - rt->f.invalidate_all = renderer_invalidate_all; + rt->f.update_zoom = renderer_update_zoom; rt->f.invalidate_region = renderer_invalidate_region; rt->f.scroll = rt_scroll; - rt->f.update_sizes = renderer_update_sizes; + rt->f.update_viewport = renderer_update_viewport; rt->f.overlay_add = renderer_tiles_overlay_add; rt->f.overlay_set = renderer_tiles_overlay_set; rt->f.overlay_get = renderer_tiles_overlay_get; - rt->f.overlay_draw = renderer_overlay_draw; rt->f.stereo_set = renderer_stereo_set; - - rt->tile_width = PR_TILE_SIZE; - rt->tile_height = PR_TILE_SIZE; + + rt->tile_width = options->image.tile_size; + rt->tile_height = options->image.tile_size; rt->tiles = NULL; rt->tile_cache_size = 0; @@ -2280,14 +2393,30 @@ RendererFuncs *renderer_tiles_new(PixbufRenderer *pr) rt->tile_cache_max = PR_CACHE_SIZE_DEFAULT; rt->draw_idle_id = 0; - + rt->stereo_mode = 0; rt->stereo_off_x = 0; rt->stereo_off_y = 0; +#if GTK_CHECK_VERSION(3, 10, 0) + rt->hidpi_scale = gtk_widget_get_scale_factor(GTK_WIDGET(rt->pr)); +#else + rt->hidpi_scale = 1; +#endif + g_signal_connect(G_OBJECT(pr), "hierarchy-changed", G_CALLBACK(rt_hierarchy_changed_cb), rt); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(pr), "draw", + G_CALLBACK(rt_draw_cb), rt); + g_signal_connect(G_OBJECT(pr), "realize", G_CALLBACK(rt_realize_cb), rt); + g_signal_connect(G_OBJECT(pr), "size-allocate", G_CALLBACK(rt_size_allocate_cb), rt); +#else + g_signal_connect(G_OBJECT(pr), "expose_event", + G_CALLBACK(rt_expose_cb), rt); +#endif + return (RendererFuncs *) rt; }