Mercurial > geeqie.yaz
diff src/image.c @ 23:17acca639a86
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
##### an offical release when making enhancements and translation updates. #####
Fri Mar 18 19:52:38 2005 John Ellis <johne@verizon.net>
* pixbuf-renderer.c: Fix broken 2pass queueing so it merges a single
queue item for each tile, and now that a tile holds a queue pointer
there is no need to walk the tile list to find a possible merge victim.
Thu Mar 17 19:23:56 2005 John Ellis <johne@verizon.net>
* image.c, pixbuf-renderer.[ch]: More progress, and 2 pass zoom now
works again (mostly).
Tue Mar 15 23:17:41 2005 John Ellis <johne@verizon.net>
* image.[ch]: Start conversion to use of PixbufRenderer.
* pixbuf-renderer.[ch]: Additions and fixes for use by ImageWindow.
* fullscreen.c, image-overlay.c, img-view.c, info.c, layout.c,
layout_image.c, print.c: Changes for above ImageWindow conversion.
* typedefs.h: Remove unused ImageWindow variables.
Mon Mar 14 20:45:50 2005 John Ellis <johne@verizon.net>
* pan-view.c: Convert to using new PixbufRenderer.
* pixbuf-renderer.[ch]: Clean up and fixes.
Sun Mar 13 10:21:35 2005 John Ellis <johne@verizon.net>
* image.c (image_scroller_start): Unref scroller pixbuf after adding it
as an overlay to avoid leaking it.
* pixbuf-renderer.[ch]: All functions defined in header file are now
implemented.
Fri Mar 11 17:05:36 2005 John Ellis <johne@verizon.net>
* pixbuf-renderer.[ch]: Set up object properties and additional.
Mar 10 19:22:18 2005 John Ellis <johne@verizon.net>
* pixbuf-renderer.[ch]: FIx scrolling to use old method of gdk_draw and
not gdk_scroll, as scroll often invalidates the entire window (!). Also
merged in source tiles code from image.c.
* pan-view.c: Change picked up when testing PixbufRender zoom.
Tue Mar 8 23:26:00 2005 John Ellis <johne@verizon.net>
* pixbuf-renderer.[ch]: Start of turning image drawing portion of
ImageWindow into an actual GtkWidget.
* src/Makefile.am: Add pixbuf-renderer.[ch].
* pan-view.c: Added temporary hack button and callback for testing
PixbufRenderer widget.
author | gqview |
---|---|
date | Sat, 19 Mar 2005 01:15:17 +0000 |
parents | 25335c62cd9b |
children | 104e34f9ab1f |
line wrap: on
line diff
--- a/src/image.c Sat Mar 05 21:40:46 2005 +0000 +++ b/src/image.c Sat Mar 19 01:15:17 2005 +0000 @@ -1,6 +1,6 @@ /* * GQview - * (C) 2004 John Ellis + * (C) 2005 John Ellis * * Author: John Ellis * @@ -17,19 +17,13 @@ #include "image-load.h" #include "collect.h" #include "exif.h" +#include "pixbuf-renderer.h" #include "pixbuf_util.h" #include "ui_fileops.h" #include <math.h> -/* size to use when breaking up image pane for rendering */ -#define IMAGE_TILE_SIZE 512 - -/* default min and max zoom */ -#define IMAGE_ZOOM_MIN -32.0 -#define IMAGE_ZOOM_MAX 32.0 - /* size of the image loader buffer (512 bytes x defined number) */ #define IMAGE_LOAD_BUFFER_COUNT 8 @@ -42,1615 +36,61 @@ /* the file size at which throttling take place */ #define IMAGE_THROTTLE_THRESHOLD 1048576 -/* distance to drag mouse to disable image flip */ -#define IMAGE_DRAG_SCROLL_THRESHHOLD 4 - -/* increase pan rate when holding down shift */ -#define IMAGE_PAN_SHIFT_MULTIPLIER 6 - -/* alpha channel checkerboard background (same as gimp) */ -#define IMAGE_ALPHA_CHECK1 0x00999999 -#define IMAGE_ALPHA_CHECK2 0x00666666 -#define IMAGE_ALPHA_CHECK_SIZE 16 - #define IMAGE_AUTO_REFRESH_TIME 3000 -/* when scaling image to below this size, use nearest pixel for scaling - * (below about 4, the other scale types become slow generating their conversion tables) - */ -#define IMAGE_MIN_SCALE_SIZE 8 - - -typedef enum { - TILE_RENDER_NONE = 0, /* do nothing */ - TILE_RENDER_AREA, /* render an area of the tile */ - TILE_RENDER_ALL /* render the whole tile */ -} TileRenderType; - -typedef struct _ImageTile ImageTile; -struct _ImageTile -{ - GdkPixmap *pixmap; /* off screen buffer */ - GdkPixbuf *pixbuf; /* pixbuf area for zooming */ - gint x; /* x offset into image */ - gint y; /* y offset into image */ - gint w; /* width that is visible (may be less if at edge of image) */ - gint h; /* height '' */ - - gint blank; - -/* render_todo: (explanation) - NONE do nothing - AREA render area of tile, usually only used when loading an image - note: will jump to an ALL if render_done is not ALL. - ALL render entire tile, if never done before w/ ALL, for expose events *only* -*/ - - TileRenderType render_todo; /* what to do (see above) */ - TileRenderType render_done; /* highest that has been done before on tile */ -}; - -typedef struct _QueueData QueueData; -struct _QueueData -{ - ImageTile *it; - gint x; - gint y; - gint w; - gint h; - gint new_data; -}; - -typedef struct _CacheData CacheData; -struct _CacheData -{ - GdkPixmap *pixmap; - GdkPixbuf *pixbuf; - ImageTile *it; - guint size; -}; - -typedef struct _OverlayData OverlayData; -struct _OverlayData -{ - gint id; - - GdkPixbuf *pixbuf; - - gint x; - gint y; - gint relative; /* x,y coordinates are relative, negative values start bottom right */ - - gint visible; - gint always; /* hide temporarily when scrolling */ -}; - -/* needed to be declared before the source_tile stuff */ -static void image_pixbuf_sync(ImageWindow *imd, gdouble zoom, gint blank, gint new); -static void image_zoom_sync(ImageWindow *imd, gdouble zoom, - gint force, gint blank, gint new, - gint center_point, gint px, gint py); -static void image_queue(ImageWindow *imd, gint x, gint y, gint w, gint h, - gint clamp, TileRenderType render, gint new_data); - -static gint util_clip_region(gint x, gint y, gint w, gint h, - gint clip_x, gint clip_y, gint clip_w, gint clip_h, - gint *rx, gint *ry, gint *rw, gint *rh); - -/* - *------------------------------------------------------------------- - * source tiles - *------------------------------------------------------------------- - */ - -typedef struct _SourceTile SourceTile; -struct _SourceTile -{ - gint x; - gint y; - GdkPixbuf *pixbuf; - gint blank; -}; - -static void source_tile_free(SourceTile *st) -{ - if (!st) return; - - if (st->pixbuf) gdk_pixbuf_unref(st->pixbuf); - g_free(st); -} - -static void source_tile_free_all(ImageWindow *imd) -{ - GList *work; - - work = imd->source_tiles; - while (work) - { - SourceTile *st = work->data; - work = work->next; - - source_tile_free(st); - } - - g_list_free(imd->source_tiles); - imd->source_tiles = NULL; -} - -static gint source_tile_visible(ImageWindow *imd, SourceTile *st) -{ - gint x, y, w, h; - - if (!st) return FALSE; - - x = (imd->x_scroll / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE; - y = (imd->y_scroll / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE; - w = ((imd->x_scroll + imd->vis_width) / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE + IMAGE_TILE_SIZE; - h = ((imd->y_scroll + imd->vis_height) / IMAGE_TILE_SIZE) * IMAGE_TILE_SIZE + IMAGE_TILE_SIZE; - - return !((double)st->x * imd->scale < (double)x || - (double)(st->x + imd->source_tile_width) * imd->scale > (double)w || - (double)st->y * imd->scale < (double)y || - (double)(st->y + imd->source_tile_height) * imd->scale > (double)h); -} - -static SourceTile *source_tile_new(ImageWindow *imd, gint x, gint y) -{ - SourceTile *st = NULL; - gint count; - - if (imd->source_tiles_cache_size < 4) imd->source_tiles_cache_size = 4; - - if (imd->source_tile_width < 1 || imd->source_tile_height < 1) - { - printf("warning: source tile size too small %d x %d\n", imd->source_tile_width, imd->source_tile_height); - return NULL; - } - - count = g_list_length(imd->source_tiles); - if (count >= imd->source_tiles_cache_size) - { - GList *work; - - work = g_list_last(imd->source_tiles); - while (work && count >= imd->source_tiles_cache_size) - { - SourceTile *needle; - - needle = work->data; - work = work->prev; - - if (!source_tile_visible(imd, needle)) - { - imd->source_tiles = g_list_remove(imd->source_tiles, needle); - - if (imd->func_tile_dispose) - { - if (debug) printf("tile dispose: %d x %d @ %d x %d\n", - needle->x, needle->y, imd->x_scroll, imd->y_scroll); - imd->func_tile_dispose(imd, needle->x, needle->y, - imd->source_tile_width, imd->source_tile_height, - needle->pixbuf, imd->data_tile); - } - - if (!st) - { - st = needle; - } - else - { - source_tile_free(needle); - } - - count--; - } - else if (debug) - { - printf("we still think %d x %d is visble\n", needle->x, needle->y); - } - } - - if (debug) - { - printf("cache count %d, max is %d\n", count, imd->source_tiles_cache_size); - } - } - - if (!st) - { - st = g_new0(SourceTile, 1); - st->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, - imd->source_tile_width, imd->source_tile_height); - } - - st->x = (x / imd->source_tile_width) * imd->source_tile_width; - st->y = (y / imd->source_tile_height) * imd->source_tile_height; - st->blank = TRUE; - - imd->source_tiles = g_list_prepend(imd->source_tiles, st); - - if (debug) - { - printf("tile request: %d x %d\n", st->x, st->y); - if (!source_tile_visible(imd, st)) printf("tile request for invisible tile!\n"); - } - - return st; -} - -static void image_tile_invalidate(ImageWindow *imd, gint x, gint y, gint w, gint h) -{ - gint i, j; - gint x1, x2; - gint y1, y2; - GList *work; - - x1 = (gint)floor(x / imd->tile_width) * imd->tile_width; - x2 = (gint)ceil((x + w) / imd->tile_width) * imd->tile_width; - - y1 = (gint)floor(y / imd->tile_height) * imd->tile_height; - y2 = (gint)ceil((y + h) / imd->tile_height) * imd->tile_height; - - work = g_list_nth(imd->tiles, y1 / imd->tile_height * imd->tile_cols + (x1 / imd->tile_width)); - for (j = y1; j <= y2; j += imd->tile_height) - { - GList *tmp; - tmp = work; - for (i = x1; i <= x2; i += imd->tile_width) - { - if (tmp) - { - ImageTile *it = tmp->data; - - it->render_done = TILE_RENDER_NONE; - it->render_todo = TILE_RENDER_ALL; - - tmp = tmp->next; - } - } - work = g_list_nth(work, imd->tile_cols); /* step 1 row */ - } -} - -static SourceTile *source_tile_request(ImageWindow *imd, gint x, gint y) -{ - SourceTile *st; - - st = source_tile_new(imd, x, y); - - if (imd->func_tile_request && - imd->func_tile_request(imd, st->x, st->y, - imd->source_tile_width, imd->source_tile_height, st->pixbuf, imd->data_tile)) - { - st->blank = FALSE; - } -#if 0 - /* fixme: somehow invalidate the new st region */ - image_queue(imd, st->x, st->y, imd->source_tile_width, imd->source_tile_height, FALSE, TILE_RENDER_AREA, TRUE); -#endif - image_tile_invalidate(imd, st->x * imd->scale, st->y * imd->scale, - imd->source_tile_width * imd->scale, imd->source_tile_height * imd->scale); - - return st; -} - -static SourceTile *source_tile_find(ImageWindow *imd, gint x, gint y) -{ - GList *work; - - work = imd->source_tiles; - while (work) - { - SourceTile *st = work->data; - - if (x >= st->x && x < st->x + imd->source_tile_width && - y >= st->y && y < st->y + imd->source_tile_height) - { - if (work != imd->source_tiles) - { - imd->source_tiles = g_list_remove_link(imd->source_tiles, work); - imd->source_tiles = g_list_concat(work, imd->source_tiles); - } - return st; - } - - work = work->next; - } - - return NULL; -} - -static GList *source_tile_compute_region(ImageWindow *imd, gint x, gint y, gint w, gint h, gint request) -{ - gint x1, y1; - GList *list = NULL; - gint sx, sy; - - if (x < 0) x = 0; - if (y < 0) y = 0; - if (w > imd->image_width) w = imd->image_width; - if (h > imd->image_height) h = imd->image_height; - - sx = (x / imd->source_tile_width) * imd->source_tile_width; - sy = (y / imd->source_tile_height) * imd->source_tile_height; - - for (x1 = sx; x1 < x + w; x1+= imd->source_tile_width) - { - for (y1 = sy; y1 < y + h; y1 += imd->source_tile_height) - { - SourceTile *st; - - st = source_tile_find(imd, x1, y1); - if (!st && request) st = source_tile_request(imd, x1, y1); - - if (st) list = g_list_prepend(list, st); - } - } - - return g_list_reverse(list); -} - -static void source_tile_changed(ImageWindow *imd, gint x, gint y, gint width, gint height) -{ - GList *work; - - work = imd->source_tiles; - while (work) - { - SourceTile *st; - gint rx, ry, rw, rh; - - st = work->data; - work = work->next; - - if (util_clip_region(st->x, st->y, imd->source_tile_width, imd->source_tile_height, - x, y, width, height, - &rx, &ry, &rw, &rh)) - { - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new_subpixbuf(st->pixbuf, rx - st->x, ry - st->y, rw, rh); - if (imd->func_tile_request && - imd->func_tile_request(imd, rx, ry, rw, rh, pixbuf, imd->data_tile)) - { - image_tile_invalidate(imd, rx * imd->scale, ry * imd->scale, rw * imd->scale, rh * imd->scale); - } - g_object_unref(pixbuf); - } - } -} - - -static gint source_tile_render(ImageWindow *imd, ImageTile *it, - gint x, gint y, gint w, gint h, - gint new_data, gint fast) -{ - GList *list; - GList *work; - gint draw = FALSE; - - if (imd->zoom == 1.0 || imd->scale == 1.0) - { - list = source_tile_compute_region(imd, it->x + x, it->y + y, w, h, TRUE); - work = list; - while (work) - { - SourceTile *st; - gint rx, ry, rw, rh; - - st = work->data; - work = work->next; - - if (util_clip_region(st->x, st->y, imd->source_tile_width, imd->source_tile_height, - it->x + x, it->y + y, w, h, - &rx, &ry, &rw, &rh)) - { - if (st->blank) - { - gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, - rx - st->x, ry - st->y, rw, rh); - } - else /* (imd->zoom == 1.0 || imd->scale == 1.0) */ - { - gdk_draw_pixbuf(it->pixmap, - imd->image->style->fg_gc[GTK_WIDGET_STATE(imd->image)], - st->pixbuf, - rx - st->x, ry - st->y, - rx - it->x, ry - it->y, - rw, rh, - (GdkRgbDither)dither_quality, rx, ry); - } - } - } - } - else - { - double scale_x, scale_y; - gint sx, sy, sw, sh; - - if (imd->image_width == 0 || imd->image_height == 0) return FALSE; - scale_x = (double)imd->width / imd->image_width; - scale_y = (double)imd->height / imd->image_height; - - sx = (double)(it->x + x) / scale_x; - sy = (double)(it->y + y) / scale_y; - sw = (double)w / scale_x; - sh = (double)h / scale_y; - - if (imd->width < IMAGE_MIN_SCALE_SIZE || imd->height < IMAGE_MIN_SCALE_SIZE) fast = TRUE; - -#if 0 - /* draws red over draw region, to check for leaks (regions not filled) */ - pixbuf_draw_rect(it->pixbuf, x, y, w, h, 255, 0, 0, 255, FALSE); -#endif - - list = source_tile_compute_region(imd, sx, sy, sw, sh, TRUE); - work = list; - while (work) - { - SourceTile *st; - gint rx, ry, rw, rh; - gint stx, sty, stw, sth; - - st = work->data; - work = work->next; - - stx = floor((double)st->x * scale_x); - sty = floor((double)st->y * scale_y); - stw = ceil ((double)(st->x + imd->source_tile_width) * scale_x) - stx; - sth = ceil ((double)(st->y + imd->source_tile_height) * scale_y) - sty; - - if (util_clip_region(stx, sty, stw, sth, - it->x + x, it->y + y, w, h, - &rx, &ry, &rw, &rh)) - { - if (st->blank) - { - gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, - rx - st->x, ry - st->y, rw, rh); - } - else - { - double offset_x; - double offset_y; - - /* may need to use unfloored stx,sty values here */ - offset_x = ((double)stx < (double)it->x) ? - (double)stx - (double)it->x : 0.0; - offset_y = ((double)sty < (double)it->y) ? - (double)sty - (double)it->y : 0.0; - - gdk_pixbuf_scale(st->pixbuf, it->pixbuf, rx - it->x, ry - it->y, rw, rh, - (double) 0.0 + rx - it->x + offset_x, - (double) 0.0 + ry - it->y + offset_y, - scale_x, scale_y, - (fast) ? GDK_INTERP_NEAREST : (GdkInterpType)zoom_quality); - draw = TRUE; - } - } - } - } - - g_list_free(list); - - return draw; -} - -static void image_source_tile_unset(ImageWindow *imd) -{ - source_tile_free_all(imd); - - imd->source_tiles_enabled = FALSE; -} - -void image_set_image_as_tiles(ImageWindow *imd, gint width, gint height, - gint tile_width, gint tile_height, gint cache_size, - ImageTileRequestFunc func_tile_request, - ImageTileDisposeFunc func_tile_dispose, - gpointer data, - gdouble zoom) -{ - /* FIXME: unset any current image */ - image_source_tile_unset(imd); - - if (tile_width < 32 || tile_height < 32) - { - printf("warning: tile size too small %d x %d (min 32x32)\n", tile_width, tile_height); - return; - } - if (width < 32 || height < 32) - { - printf("warning: tile canvas too small %d x %d (min 32x32)\n", width, height); - return; - } - if (!func_tile_request) - { - printf("warning: tile request function is null\n"); - } - - printf("Setting source tiles to size %d x %d, grid is %d x %d\n", tile_width, tile_height, width, height); - - if (cache_size < 4) cache_size = 4; - - imd->source_tiles_enabled = TRUE; - imd->source_tiles_cache_size = cache_size; - imd->source_tile_width = tile_width; - imd->source_tile_height = tile_height; - - imd->image_width = width; - imd->image_height = height; - - imd->func_tile_request = func_tile_request; - imd->func_tile_dispose = func_tile_dispose; - imd->data_tile = data; - - image_zoom_sync(imd, zoom, TRUE, FALSE, TRUE, FALSE, 0, 0); -} - - -static void image_queue_clear(ImageWindow *imd); - -static void image_update_title(ImageWindow *imd); -static void image_update_util(ImageWindow *imd); -static void image_complete_util(ImageWindow *imd, gint preload); - -static void image_button_do(ImageWindow *imd, GdkEventButton *bevent); - -static void image_overlay_draw(ImageWindow *imd, gint x, gint y, gint w, gint h); -static void image_overlay_queue_all(ImageWindow *imd); - -static void image_scroller_timer_set(ImageWindow *imd, gint start); - - -static gint util_clip_region(gint x, gint y, gint w, gint h, - gint clip_x, gint clip_y, gint clip_w, gint clip_h, - gint *rx, gint *ry, gint *rw, gint *rh) -{ - if (clip_x + clip_w <= x || - clip_x >= x + w || - clip_y + clip_h <= y || - clip_y >= y + h) - { - return FALSE; - } - - *rx = MAX(x, clip_x); - *rw = MIN((x + w), (clip_x + clip_w)) - *rx; - - *ry = MAX(y, clip_y); - *rh = MIN((y + h), (clip_y + clip_h)) - *ry; - - return TRUE; -} - /* *------------------------------------------------------------------- - * tile cache - *------------------------------------------------------------------- - */ - -static gint pixmap_calc_size(GdkPixmap *pixmap) -{ - gint w, h, d; - - d = gdk_drawable_get_depth(pixmap); - gdk_drawable_get_size(pixmap, &w, &h); - return w * h * (d / 8); -} - -static void image_tile_cache_remove(ImageWindow *imd, ImageTile *it) -{ - GList *work; - - work = imd->tile_cache; - while(work) - { - CacheData *cd = work->data; - work = work->next; - - if (cd->it == it) - { - imd->tile_cache = g_list_remove(imd->tile_cache, cd); - imd->tile_cache_size -= cd->size; - g_free(cd); - } - } -} - -static void image_tile_cache_free(ImageWindow *imd, CacheData *cd) -{ - imd->tile_cache = g_list_remove(imd->tile_cache, cd); - if (cd->pixmap) - { - g_object_unref(cd->it->pixmap); - cd->it->pixmap = NULL; - cd->it->render_done = TILE_RENDER_NONE; - } - if (cd->pixbuf) - { - gdk_pixbuf_unref(cd->it->pixbuf); - cd->it->pixbuf = NULL; - } - imd->tile_cache_size -= cd->size; - g_free(cd); -} - -static void image_tile_cache_free_space(ImageWindow *imd, gint space, ImageTile *it) -{ - GList *work; - gint tile_max; - - work = g_list_last(imd->tile_cache); - - if (imd->source_tiles_enabled && imd->scale < 1.0) - { - gint tiles; - - tiles = (imd->vis_width / IMAGE_TILE_SIZE + 1) * (imd->vis_width / IMAGE_TILE_SIZE + 1); - tile_max = MAX(tiles * IMAGE_TILE_SIZE * IMAGE_TILE_SIZE * 3, - (gint)((double)tile_cache_max * 1048576.0 * imd->scale)); - } - else - { - tile_max = tile_cache_max * 1048576; - } - - while (work && imd->tile_cache_size > 0 && imd->tile_cache_size + space > tile_max) - { - CacheData *cd = work->data; - work = work->prev; - if (cd->it != it) image_tile_cache_free(imd, cd); - } -} - -static void image_tile_cache_add(ImageWindow *imd, ImageTile *it, - GdkPixmap *pixmap, GdkPixbuf *pixbuf, guint size) -{ - CacheData *cd; - - cd = g_new(CacheData, 1); - cd->pixmap = pixmap; - cd->pixbuf = pixbuf; - cd->it = it; - cd->size = size; - - imd->tile_cache = g_list_prepend(imd->tile_cache, cd); - - imd->tile_cache_size += cd->size; -} - -static void image_tile_prepare(ImageWindow *imd, ImageTile *it) -{ - if (!it->pixmap) - { - GdkPixmap *pixmap; - guint size; - - pixmap = gdk_pixmap_new(imd->image->window, imd->tile_width, imd->tile_height, -1); - - size = pixmap_calc_size(pixmap); - image_tile_cache_free_space(imd, size, it); - - it->pixmap = pixmap; - image_tile_cache_add(imd, it, pixmap, NULL, size); - } - - if ((imd->zoom != 1.0 || imd->source_tiles_enabled || (imd->pixbuf && gdk_pixbuf_get_has_alpha(imd->pixbuf)) ) && - !it->pixbuf) - { - GdkPixbuf *pixbuf; - guint size; - - if (imd->pixbuf) - { - pixbuf = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(imd->pixbuf), - gdk_pixbuf_get_has_alpha(imd->pixbuf), - gdk_pixbuf_get_bits_per_sample(imd->pixbuf), - imd->tile_width, imd->tile_height); - } - else - { - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, imd->tile_width, imd->tile_height); - } - - size = gdk_pixbuf_get_rowstride(pixbuf) * imd->tile_height; - image_tile_cache_free_space(imd, size, it); - - it->pixbuf = pixbuf; - image_tile_cache_add(imd, it, NULL, pixbuf, size); - } -} - -/* - *------------------------------------------------------------------- - * tiles - *------------------------------------------------------------------- - */ - -static ImageTile *image_tile_new(gint w, gint h) -{ - ImageTile *it; - - it = g_new0(ImageTile, 1); - it->w = w; - it->h = h; - it->pixmap = NULL; - it->pixbuf = NULL; - it->blank = TRUE; - it->render_todo = TILE_RENDER_NONE; - it->render_done = TILE_RENDER_NONE; - - return it; -} - -static void image_tile_free(ImageTile *it) -{ - if (!it) return; - - if (it->pixbuf) gdk_pixbuf_unref(it->pixbuf); - if (it->pixmap) g_object_unref(it->pixmap); - - g_free(it); -} - -static void image_tile_sync_count(ImageWindow *imd, gint n) -{ - gint l; - - l = g_list_length(imd->tiles); - - if (l == n) return; - - if (l < n) - { - while (l < n) - { - imd->tiles = g_list_prepend(imd->tiles, image_tile_new(imd->tile_width, imd->tile_height)); - l++; - } - } - else - { - /* This should remove from the tail of the GList, but with large images there are many tiles, - * making this significantly faster for those cases. - */ - while (l > n && imd->tiles) - { - ImageTile *it = imd->tiles->data; - imd->tiles = g_list_remove(imd->tiles, it); - image_tile_cache_remove(imd, it); - image_tile_free(it); - l--; - } - } -} - -static void image_tile_sync(ImageWindow *imd, gint width, gint height, gint blank) -{ - gint rows; - gint x, y; - GList *work; - - imd->tile_cols = (width + imd->tile_width - 1) / imd->tile_width; - - rows = (height + imd->tile_height - 1) / imd->tile_height; - - image_tile_sync_count(imd, imd->tile_cols * rows); - - x = y = 0; - work = imd->tiles; - while(work) - { - ImageTile *it = work->data; - work = work->next; - - it->x = x; - it->y = y; - if (x + imd->tile_width > width) - { - it->w = width - x; - } - else - { - it->w = imd->tile_width; - } - if (y + imd->tile_height > height) - { - it->h = height - y; - } - else - { - it->h = imd->tile_height; - } - - it->blank = blank; - it->render_todo = TILE_RENDER_NONE; - it->render_done = TILE_RENDER_NONE; - - x += imd->tile_width; - if (x >= width) - { - x = 0; - y += imd->tile_height; - } - } - - /* all it's are now useless in queue */ - image_queue_clear(imd); -} - -static void image_tile_render(ImageWindow *imd, ImageTile *it, - gint x, gint y, gint w, gint h, - gint new_data, gint fast) -{ - gint has_alpha; - gint draw = FALSE; - - if (it->render_todo == TILE_RENDER_NONE && it->pixmap && !new_data) return; - - if (it->render_done != TILE_RENDER_ALL) - { - x = 0; - y = 0; - w = it->w; - h = it->h; - if (!fast) it->render_done = TILE_RENDER_ALL; - } - else if (it->render_todo != TILE_RENDER_AREA) - { - if (!fast) it->render_todo = TILE_RENDER_NONE; - return; - } - - if (!fast) it->render_todo = TILE_RENDER_NONE; - - if (new_data) it->blank = FALSE; - - image_tile_prepare(imd, it); - has_alpha = (imd->pixbuf && gdk_pixbuf_get_has_alpha(imd->pixbuf)); - - /* FIXME checker colors for alpha should be configurable, - * also should be drawn for blank = TRUE - */ - - if (it->blank) - { - /* no data, do fast rect fill */ - gdk_draw_rectangle(it->pixmap, imd->image->style->black_gc, TRUE, - 0, 0, it->w, it->h); - } - else if (imd->source_tiles_enabled) - { - draw = source_tile_render(imd, it, x, y, w, h, new_data, fast); - } - else if (imd->zoom == 1.0 || imd->scale == 1.0) - { - if (has_alpha) - { - gdk_pixbuf_composite_color(imd->pixbuf, it->pixbuf, x, y, w, h, - (double) 0.0 - it->x, - (double) 0.0 - it->y, - 1.0, 1.0, GDK_INTERP_NEAREST, - 255, it->x + x, it->y + y, - IMAGE_ALPHA_CHECK_SIZE, IMAGE_ALPHA_CHECK1, IMAGE_ALPHA_CHECK2); - draw = TRUE; - } - else - { - /* faster, simple */ - gdk_draw_pixbuf(it->pixmap, - imd->image->style->fg_gc[GTK_WIDGET_STATE(imd->image)], - imd->pixbuf, - it->x + x, it->y + y, - x, y, - w, h, - (GdkRgbDither)dither_quality, it->x + x, it->y + y); - } - } - else - { - double scale_x, scale_y; - - if (imd->image_width == 0 || imd->image_height == 0) return; - scale_x = (double)imd->width / imd->image_width; - scale_y = (double)imd->height / imd->image_height; - - /* HACK: The pixbuf scalers get kinda buggy(crash) with extremely - * small sizes for anything but GDK_INTERP_NEAREST - */ - if (imd->width < IMAGE_MIN_SCALE_SIZE || imd->height < IMAGE_MIN_SCALE_SIZE) fast = TRUE; - - if (!has_alpha) - { - gdk_pixbuf_scale(imd->pixbuf, it->pixbuf, x, y, w, h, - (double) 0.0 - it->x, - (double) 0.0 - it->y, - scale_x, scale_y, - (fast) ? GDK_INTERP_NEAREST : (GdkInterpType)zoom_quality); - } - else - { - gdk_pixbuf_composite_color(imd->pixbuf, it->pixbuf, x, y, w, h, - (double) 0.0 - it->x, - (double) 0.0 - it->y, - scale_x, scale_y, - (fast) ? GDK_INTERP_NEAREST : (GdkInterpType)zoom_quality, - 255, it->x + x, it->y + y, - IMAGE_ALPHA_CHECK_SIZE, IMAGE_ALPHA_CHECK1, IMAGE_ALPHA_CHECK2); - } - draw = TRUE; - } - - if (draw && it->pixbuf && !it->blank) - { - gdk_draw_pixbuf(it->pixmap, - imd->image->style->fg_gc[GTK_WIDGET_STATE(imd->image)], - it->pixbuf, - x, y, - x, y, - w, h, - (GdkRgbDither)dither_quality, it->x + x, it->y + y); - } -} - -static void image_tile_expose(ImageWindow *imd, ImageTile *it, - gint x, gint y, gint w, gint h, - gint new_data, gint fast) -{ - image_tile_render(imd, it, x, y, w, h, new_data, fast); - - gdk_draw_drawable(imd->image->window, imd->image->style->fg_gc[GTK_WIDGET_STATE(imd->image)], - it->pixmap, x, y, - imd->x_offset + (it->x - imd->x_scroll) + x, imd->y_offset + (it->y - imd->y_scroll) + y, w, h); - - if (imd->overlay_list) - { - image_overlay_draw(imd, imd->x_offset + (it->x - imd->x_scroll) + x, - imd->y_offset + (it->y - imd->y_scroll) + y, - w, h); - } -} - -static gint image_tile_is_visible(ImageWindow *imd, ImageTile *it) -{ - return (it->x + it->w >= imd->x_scroll && it->x <= imd->x_scroll + imd->window_width - imd->x_offset * 2 && - it->y + it->h >= imd->y_scroll && it->y <= imd->y_scroll + imd->window_height - imd->y_offset * 2); -} - -/* - *------------------------------------------------------------------- - * render queue + * 'signals' *------------------------------------------------------------------- */ - -static gint image_queue_draw_idle_cb(gpointer data) +static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data) { ImageWindow *imd = data; - QueueData *qd; - gint fast; - if ((!imd->pixbuf && !imd->source_tiles_enabled) || (!imd->draw_queue && !imd->draw_queue_2pass) || imd->draw_idle_id == -1) - { - if (!imd->completed) image_complete_util(imd, FALSE); - - imd->draw_idle_id = -1; - return FALSE; - } - - if (imd->draw_queue) - { - qd = imd->draw_queue->data; - fast = (two_pass_zoom && (GdkInterpType)zoom_quality != GDK_INTERP_NEAREST && imd->scale != 1.0); - } - else - { - if (imd->il) - { - /* still loading, wait till done (also drops the higher priority) */ - - imd->draw_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, - image_queue_draw_idle_cb, imd, NULL); - imd->draw_idle_high = FALSE; - return FALSE; - } - qd = imd->draw_queue_2pass->data; - fast = FALSE; - } - - if (GTK_WIDGET_REALIZED(imd->image)) - { - if (image_tile_is_visible(imd, qd->it)) - { - image_tile_expose(imd, qd->it, qd->x, qd->y, qd->w, qd->h, qd->new_data, fast); - } - else if (qd->new_data) - { - /* if new pixel data, and we already have a pixmap, update the tile */ - qd->it->blank = FALSE; - if (qd->it->pixmap && qd->it->render_done == TILE_RENDER_ALL) - { - image_tile_render(imd, qd->it, qd->x, qd->y, qd->w, qd->h, qd->new_data, fast); - } - } - } - - if (imd->draw_queue) - { - imd->draw_queue = g_list_remove(imd->draw_queue, qd); - if (fast) - { - imd->draw_queue_2pass = g_list_append(imd->draw_queue_2pass, qd); - } - else - { - g_free(qd); - } - } - else - { - imd->draw_queue_2pass = g_list_remove(imd->draw_queue_2pass, qd); - g_free(qd); - } - - if (!imd->draw_queue && !imd->draw_queue_2pass) - { - if (!imd->completed) image_complete_util(imd, FALSE); - - imd->draw_idle_id = -1; - return FALSE; - } - - return TRUE; -} - -static QueueData *image_queue_combine(ImageWindow *imd, QueueData *qd) -{ - QueueData *found = NULL; - GList *work; - - work = imd->draw_queue; - while (work && !found) - { - found = work->data; - work = work->next; - - if (found->it != qd->it) found = NULL; - } - - if (found) + if (imd->func_button) { - if (found->x + found->w < qd->x + qd->w) found->w += (qd->x + qd->w) - (found->x + found->w); - if (found->x > qd->x) - { - found->w += found->x - qd->x; - found->x = qd->x; - } - - if (found->y + found->h < qd->y + qd->h) found->h += (qd->y + qd->h) - (found->y + found->h); - if (found->y > qd->y) - { - found->h += found->y - qd->y; - found->y = qd->y; - } - found->new_data |= qd->new_data; - } - - return found; -} - -static gint image_clamp_to_visible(ImageWindow *imd, gint *x, gint *y, gint *w, gint *h) -{ - gint nx, ny; - gint nw, nh; - gint vx, vy; - gint vw, vh; - - vw = imd->vis_width; - vh = imd->vis_height; - - vx = imd->x_scroll; - vy = imd->y_scroll; - - if (*x + *w < vx || *x > vx + vw || *y + *h < vy || *y > vy + vh) return FALSE; - - /* now clamp it */ - nx = CLAMP(*x, vx, vx + vw); - nw = CLAMP(*w - (nx - *x), 1, vw); - - ny = CLAMP(*y, vy, vy + vh); - nh = CLAMP(*h - (ny - *y), 1, vh); - - *x = nx; - *y = ny; - *w = nw; - *h = nh; - - return TRUE; -} - -static gint image_queue_to_tiles(ImageWindow *imd, gint x, gint y, gint w, gint h, - gint clamp, TileRenderType render, gint new_data) -{ - gint i, j; - gint x1, x2; - gint y1, y2; - GList *work; - - if (clamp && !image_clamp_to_visible(imd, &x, &y, &w, &h)) return FALSE; - - x1 = (gint)floor(x / imd->tile_width) * imd->tile_width; - x2 = (gint)ceil((x + w) / imd->tile_width) * imd->tile_width; - - y1 = (gint)floor(y / imd->tile_height) * imd->tile_height; - y2 = (gint)ceil((y + h) / imd->tile_height) * imd->tile_height; - - work = g_list_nth(imd->tiles, y1 / imd->tile_height * imd->tile_cols + (x1 / imd->tile_width)); - for (j = y1; j <= y2; j += imd->tile_height) - { - GList *tmp; - tmp = work; - for (i = x1; i <= x2; i += imd->tile_width) - { - if (tmp) - { - ImageTile *it = tmp->data; - QueueData *qd; - - if ((render == TILE_RENDER_ALL && it->render_done != TILE_RENDER_ALL) || - (render == TILE_RENDER_AREA && it->render_todo != TILE_RENDER_ALL)) - { - it->render_todo = render; - } - - qd = g_new(QueueData, 1); - qd->it = it; - qd->new_data = new_data; - - if (i < x) - { - qd->x = x - i; - } - else - { - qd->x = 0; - } - qd->w = x + w - i - qd->x; - if (qd->x + qd->w > imd->tile_width) qd->w = imd->tile_width - qd->x; - - - if (j < y) - { - qd->y = y - j; - } - else - { - qd->y = 0; - } - qd->h = y + h - j - qd->y; - if (qd->y + qd->h > imd->tile_height) qd->h = imd->tile_height - qd->y; - - if (qd->w < 1 || qd->h < 1 || /* <--- sanity checks, rare cases cause this */ - image_queue_combine(imd, qd)) - { - g_free(qd); - } - else - { - imd->draw_queue = g_list_append(imd->draw_queue, qd); - } - - tmp = tmp->next; - } - } - work = g_list_nth(work, imd->tile_cols); /* step 1 row */ - } - - return TRUE; -} - -static void image_queue(ImageWindow *imd, gint x, gint y, gint w, gint h, - gint clamp, TileRenderType render, gint new_data) -{ - gint nx, ny; - - nx = CLAMP(x, 0, imd->width - 1); - ny = CLAMP(y, 0, imd->height - 1); - w -= (nx - x); - h -= (ny - y); - w = CLAMP(w, 0, imd->width - nx); - h = CLAMP(h, 0, imd->height - ny); - if (w < 1 || h < 1) return; - - if (image_queue_to_tiles(imd, nx, ny, w, h, clamp, render, new_data) && - ((!imd->draw_queue && !imd->draw_queue_2pass) || imd->draw_idle_id == -1 || !imd->draw_idle_high)) - { - if (imd->draw_idle_id != -1) g_source_remove(imd->draw_idle_id); - imd->draw_idle_id = g_idle_add_full(GDK_PRIORITY_REDRAW, - image_queue_draw_idle_cb, imd, NULL); - imd->draw_idle_high = TRUE; + imd->func_button(imd, event->button, event->time, + event->x, event->y, event->state, imd->data_button); } } -static void image_queue_list_free(GList *list) -{ - GList *work; - - work = list; - while (work) - { - QueueData *qd; - - qd = work->data; - work = work->next; - g_free(qd); - } - - g_list_free(list); -} - -static void image_queue_clear(ImageWindow *imd) -{ - image_queue_list_free(imd->draw_queue); - imd->draw_queue = NULL; - - image_queue_list_free(imd->draw_queue_2pass); - imd->draw_queue_2pass = NULL; - - if (imd->draw_idle_id != -1) g_source_remove(imd->draw_idle_id); - imd->draw_idle_id = -1; -} - -/* - *------------------------------------------------------------------- - * core calculations - *------------------------------------------------------------------- - */ - -static gint image_top_window_sizable(ImageWindow *imd) -{ - if (!imd->top_window) return FALSE; - if (!fit_window) return FALSE; - if (!imd->top_window_sync) return FALSE; - if (!imd->image->window) return FALSE; - if (window_maximized(imd->top_window)) return FALSE; - - return TRUE; -} - -static gint image_size_top_window(ImageWindow *imd, gint w, gint h) -{ - gint ww, wh; - - if (!image_top_window_sizable(imd)) return FALSE; - - if (limit_window_size) - { - gint sw = gdk_screen_width() * max_window_size / 100; - gint sh = gdk_screen_height() * max_window_size / 100; - - if (w > sw) w = sw; - if (h > sh) h = sh; - } - - w += (imd->top_window->allocation.width - imd->image->allocation.width); - h += (imd->top_window->allocation.height - imd->image->allocation.height); - - gdk_drawable_get_size(imd->top_window->window, &ww, &wh); - if (w == ww && h == wh) return FALSE; - - gdk_window_resize(imd->top_window->window, w, h); - - return TRUE; -} - -static void image_redraw(ImageWindow *imd, gint new_data) +static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data) { - image_queue_clear(imd); - image_queue(imd, 0, 0, imd->width, imd->height, TRUE, TILE_RENDER_ALL, new_data); -} - -static void image_border_draw(ImageWindow *imd, gint x, gint y, gint w, gint h) -{ - gint rx, ry, rw, rh; - - if (!imd->image->window) return; - - if (!imd->pixbuf && !imd->source_tiles_enabled) - { - if (util_clip_region(x, y, w, h, - 0, 0, - imd->window_width, imd->window_height, - &rx, &ry, &rw, &rh)) - { - gdk_window_clear_area(imd->image->window, rx, ry, rw, rh); - image_overlay_draw(imd, rx, ry, rw, rh); - } - return; - } + ImageWindow *imd = data; - if (imd->vis_width < imd->window_width) - { - if (imd->x_offset > 0 && - util_clip_region(x, y, w, h, - 0, 0, - imd->x_offset, imd->window_height, - &rx, &ry, &rw, &rh)) - { - gdk_window_clear_area(imd->image->window, rx, ry, rw, rh); - image_overlay_draw(imd, rx, ry, rw, rh); - } - if (imd->window_width - imd->vis_width - imd->x_offset > 0 && - util_clip_region(x, y, w, h, - imd->x_offset + imd->vis_width, 0, - imd->window_width - imd->vis_width - imd->x_offset, imd->window_height, - &rx, &ry, &rw, &rh)) - { - gdk_window_clear_area(imd->image->window, rx, ry, rw, rh); - image_overlay_draw(imd, rx, ry, rw, rh); - } - } - if (imd->vis_height < imd->window_height) - { - if (imd->y_offset > 0 && - util_clip_region(x, y, w, h, - imd->x_offset, 0, - imd->vis_width, imd->y_offset, - &rx, &ry, &rw, &rh)) - { - gdk_window_clear_area(imd->image->window, rx, ry, rw, rh); - image_overlay_draw(imd, rx, ry, rw, rh); - } - if (imd->window_height - imd->vis_height - imd->y_offset > 0 && - util_clip_region(x, y, w, h, - imd->x_offset, imd->y_offset + imd->vis_height, - imd->vis_width, imd->window_height - imd->vis_height - imd->y_offset, - &rx, &ry, &rw, &rh)) - { - gdk_window_clear_area(imd->image->window, rx, ry, rw, rh); - image_overlay_draw(imd, rx, ry, rw, rh); - } - } -} - -static void image_border_clear(ImageWindow *imd) -{ - image_border_draw(imd, 0, 0, imd->window_width, imd->window_height); -} - -static void image_scroll_notify(ImageWindow *imd) -{ - if (imd->func_scroll_notify && imd->scale) + if (imd->func_scroll_notify && pr->scale) { imd->func_scroll_notify(imd, - (gint)((gdouble)imd->x_scroll / imd->scale), - (gint)((gdouble)imd->y_scroll / imd->scale), - (gint)((gdouble)imd->image_width - imd->vis_width / imd->scale), - (gint)((gdouble)imd->image_height - imd->vis_height / imd->scale), + (gint)((gdouble)pr->x_scroll / pr->scale), + (gint)((gdouble)pr->y_scroll / pr->scale), + (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale), + (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale), imd->data_scroll_notify); } } -static gint image_scroll_clamp(ImageWindow *imd) +static void image_update_util(ImageWindow *imd) { - gint old_xs; - gint old_ys; - - if (imd->zoom == 0.0) - { - imd->x_scroll = 0; - imd->y_scroll = 0; - - image_scroll_notify(imd); - return FALSE; - } - - old_xs = imd->x_scroll; - old_ys = imd->y_scroll; - - if (imd->x_offset > 0) - { - imd->x_scroll = 0; - } - else - { - imd->x_scroll = CLAMP(imd->x_scroll, 0, imd->width - imd->vis_width); - } - - if (imd->y_offset > 0) - { - imd->y_scroll = 0; - } - else - { - imd->y_scroll = CLAMP(imd->y_scroll, 0, imd->height - imd->vis_height); - } - - image_scroll_notify(imd); - - return (old_xs != imd->x_scroll || old_ys != imd->y_scroll); + if (imd->func_update) imd->func_update(imd, imd->data_update); } -static gint image_zoom_clamp(ImageWindow *imd, gdouble zoom, gint force, gint new) +static void image_complete_util(ImageWindow *imd, gint preload) { - gint w, h; - gdouble scale; - - zoom = CLAMP(zoom, imd->zoom_min, imd->zoom_max); - - if (imd->zoom == zoom && !force) return FALSE; - - w = imd->image_width; - h = imd->image_height; - - if (zoom == 0.0 && !imd->pixbuf) - { - scale = 1.0; - } - else if (zoom == 0.0) - { - gint max_w; - gint max_h; - gint sizeable; - - sizeable = (new && image_top_window_sizable(imd)); - - if (sizeable) - { - max_w = gdk_screen_width(); - max_h = gdk_screen_height(); - - if (limit_window_size) - { - max_w = max_w * max_window_size / 100; - max_h = max_h * max_window_size / 100; - } - } - else - { - max_w = imd->window_width; - max_h = imd->window_height; - } + if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return; - if ((zoom_to_fit_expands && !sizeable) || w > max_w || h > max_h) - { - if ((gdouble)max_w / w > (gdouble)max_h / h) - { - scale = (gdouble)max_h / h; - h = max_h; - w = w * scale + 0.5; - if (w > max_w) w = max_w; - } - else - { - scale = (gdouble)max_w / w; - w = max_w; - h = h * scale + 0.5; - if (h > max_h) h = max_h; - } - if (w < 1) w = 1; - if (h < 1) h = 1; - } - else - { - scale = 1.0; - } - } - else if (zoom > 0.0) /* zoom orig, in */ - { - scale = zoom; - w = w * scale; - h = h * scale; - } - else /* zoom out */ - { - scale = 1.0 / (0.0 - zoom); - w = w * scale; - h = h * scale; - } + if (debug) printf("image load completed \"%s\" (%s)\n", + (preload) ? imd->read_ahead_path : imd->image_path, + (preload) ? "preload" : "current"); - imd->zoom = zoom; - imd->width = w; - imd->height = h; - imd->scale = scale; - - return TRUE; + if (!preload) imd->completed = TRUE; + if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete); } -static gint image_size_clamp(ImageWindow *imd) -{ - gint old_vw, old_vh; - - old_vw = imd->vis_width; - old_vh = imd->vis_height; - - if (imd->width < imd->window_width) - { - imd->vis_width = imd->width; - imd->x_offset = (imd->window_width - imd->width) / 2; - } - else - { - imd->vis_width = imd->window_width; - imd->x_offset = 0; - } - - if (imd->height < imd->window_height) - { - imd->vis_height = imd->height; - imd->y_offset = (imd->window_height - imd->height) / 2; - } - else - { - imd->vis_height = imd->window_height; - imd->y_offset = 0; - } - - return (old_vw != imd->vis_width || old_vh != imd->vis_height); -} - -static void image_size_sync(ImageWindow *imd, gint new_width, gint new_height) +static void image_new_util(ImageWindow *imd) { - if (imd->window_width == new_width && imd->window_height == new_height) return; - - imd->window_width = new_width; - imd->window_height = new_height; - - if (imd->zoom == 0.0) image_zoom_clamp(imd, 0.0, TRUE, FALSE); - - image_size_clamp(imd); - image_scroll_clamp(imd); - -#if 0 - gtk_widget_set_size_request(imd->image, imd->window_width, imd->window_height); -#endif - - /* ensure scroller remains visible */ - if (imd->scroller_overlay != -1) - { - gint update = FALSE; - - if (imd->scroller_x > new_width) - { - imd->scroller_x = new_width; - imd->scroller_xpos = new_width; - update = TRUE; - } - if (imd->scroller_y > new_height) - { - imd->scroller_y = new_height; - imd->scroller_ypos = new_height; - update = TRUE; - } - - if (update) - { - GdkPixbuf *pixbuf; - - if (image_overlay_get(imd, imd->scroller_overlay, &pixbuf, NULL, NULL)) - { - gint w, h; - - w = gdk_pixbuf_get_width(pixbuf); - h = gdk_pixbuf_get_height(pixbuf); - image_overlay_set(imd, imd->scroller_overlay, pixbuf, - imd->scroller_x - w / 2, imd->scroller_y - h / 2); - } - } - } - - /* clear any borders */ - image_border_clear(imd); - - image_tile_sync(imd, imd->width, imd->height, FALSE); -#if 0 - /* no longer needed? (expose event should be doing this for us) */ - image_redraw(imd, FALSE); -#endif - - if (imd->title_show_zoom) image_update_title(imd); - image_update_util(imd); + if (imd->func_new) imd->func_new(imd, imd->data_new); } /* @@ -1697,315 +137,54 @@ g_free(collection); } -static void image_update_util(ImageWindow *imd) -{ - if (imd->func_update) imd->func_update(imd, imd->data_update); -} - -static void image_complete_util(ImageWindow *imd, gint preload) -{ - if (imd->il && imd->pixbuf != image_loader_get_pixbuf(imd->il)) return; - - if (debug) printf("image load completed \"%s\" (%s)\n", - (preload) ? imd->read_ahead_path : imd->image_path, - (preload) ? "preload" : "current"); - - if (!preload) imd->completed = TRUE; - if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete); -} - -static void image_new_util(ImageWindow *imd) -{ - if (imd->func_new) imd->func_new(imd, imd->data_new); -} - -static void image_scroll_real(ImageWindow *imd, gint x, gint y) -{ - gint old_x, old_y; - gint x_off, y_off; - gint w, h; - - if (!imd->pixbuf && !imd->source_tiles_enabled) return; - - old_x = imd->x_scroll; - old_y = imd->y_scroll; - - imd->x_scroll += x; - imd->y_scroll += y; - - image_scroll_clamp(imd); - if (imd->x_scroll == old_x && imd->y_scroll == old_y) return; - - if (imd->overlay_list) - { - gint new_x, new_y; - - new_x = imd->x_scroll; - new_y = imd->y_scroll; - imd->x_scroll = old_x; - imd->y_scroll = old_y; - image_overlay_queue_all(imd); - imd->x_scroll = new_x; - imd->y_scroll = new_y; - } - - x_off = imd->x_scroll - old_x; - y_off = imd->y_scroll - old_y; - - w = imd->vis_width - abs(x_off); - h = imd->vis_height - abs(y_off); - - if (w < 1 || h < 1) - { - /* scrolled completely to new material */ - image_queue(imd, 0, 0, imd->width, imd->height, TRUE, TILE_RENDER_ALL, FALSE); - return; - } - else - { - gint x1, y1; - gint x2, y2; - GdkGC *gc; - - if (x_off < 0) - { - x1 = abs(x_off); - x2 = 0; - } - else - { - x1 = 0; - x2 = abs(x_off); - } - - if (y_off < 0) - { - y1 = abs(y_off); - y2 = 0; - } - else - { - y1 = 0; - y2 = abs(y_off); - } - - gc = gdk_gc_new(imd->image->window); - gdk_gc_set_exposures(gc, TRUE); - gdk_draw_drawable(imd->image->window, gc, - imd->image->window, - x2 + imd->x_offset, y2 + imd->y_offset, - x1 + imd->x_offset, y1 + imd->y_offset, w, h); - g_object_unref(gc); - - if (imd->overlay_list) - { - image_overlay_queue_all(imd); - } - - w = imd->vis_width - w; - h = imd->vis_height - h; - - if (w > 0) - { - image_queue(imd, - x_off > 0 ? imd->x_scroll + (imd->vis_width - w) : imd->x_scroll, imd->y_scroll, - w, imd->vis_height, TRUE, TILE_RENDER_ALL, FALSE); - } - if (h > 0) - { - /* FIXME, to optimize this, remove overlap */ - image_queue(imd, - imd->x_scroll, y_off > 0 ? imd->y_scroll + (imd->vis_height - h) : imd->y_scroll, - imd->vis_width, h, TRUE, TILE_RENDER_ALL, FALSE); - } - } -} - -static void widget_set_cursor(GtkWidget *widget, gint icon) -{ - GdkCursor *cursor; - - if (!widget->window) return; - - if (icon == -1) - { - cursor = NULL; - } - else - { - cursor = gdk_cursor_new (icon); - } - - gdk_window_set_cursor(widget->window, cursor); - - if (cursor) gdk_cursor_unref(cursor); -} - /* *------------------------------------------------------------------- - * image pixbuf handling + * rotation, flip, etc. *------------------------------------------------------------------- */ -static void image_zoom_sync(ImageWindow *imd, gdouble zoom, - gint force, gint blank, gint new, - gint center_point, gint px, gint py) -{ - gdouble old_scale; - gint old_cx, old_cy; - gint clamped; - gint sized; - - old_scale = imd->scale; - if (center_point) - { - px = CLAMP(px, 0, imd->width); - py = CLAMP(py, 0, imd->height); - old_cx = imd->x_scroll + (px - imd->x_offset); - old_cy = imd->y_scroll + (py - imd->y_offset); - } - else - { - px = py = 0; - old_cx = imd->x_scroll + imd->vis_width / 2; - old_cy = imd->y_scroll + imd->vis_height / 2; - } - - if (!image_zoom_clamp(imd, zoom, force, new)) return; - - clamped = image_size_clamp(imd); - sized = image_size_top_window(imd, imd->width, imd->height); - - if (force) - { - /* force means new image, so update scroll offset per options */ - switch (scroll_reset_method) - { - case SCROLL_RESET_NOCHANGE: - /* maintain old scroll position, do nothing */ - break; - case SCROLL_RESET_CENTER: - /* center new image */ - imd->x_scroll = ((double)imd->image_width / 2.0 * imd->scale) - imd->vis_width / 2; - imd->y_scroll = ((double)imd->image_height / 2.0 * imd->scale) - imd->vis_height / 2; - break; - case SCROLL_RESET_TOPLEFT: - default: - /* reset to upper left */ - imd->x_scroll = 0; - imd->y_scroll = 0; - break; - } - } - else - { - /* user zoom does not force, so keep visible center point */ - if (center_point) - { - imd->x_scroll = old_cx / old_scale * imd->scale - (px - imd->x_offset); - imd->y_scroll = old_cy / old_scale * imd->scale - (py - imd->y_offset); - } - else - { - imd->x_scroll = old_cx / old_scale * imd->scale - (imd->vis_width / 2); - imd->y_scroll = old_cy / old_scale * imd->scale - (imd->vis_height / 2); - } - } - image_scroll_clamp(imd); - - image_tile_sync(imd, imd->width, imd->height, blank); - - /* If the window was not sized, redraw the image - we know there will be no size/expose signal. - * But even if a size is claimed, there is no guarantee that the window manager will allow it, - * so redraw the window anyway :/ - */ - if (sized || clamped) image_border_clear(imd); - image_redraw(imd, FALSE); - - if (imd->title_show_zoom) image_update_title(imd); - image_update_util(imd); -} - -static void image_pixbuf_sync(ImageWindow *imd, gdouble zoom, gint blank, gint new) -{ - if (!imd->pixbuf) - { - /* no pixbuf so just clear the window */ - imd->image_width = 0; - imd->image_height = 0; - imd->scale = 1.0; - - if (imd->image->window) - { - gdk_window_clear(imd->image->window); - image_overlay_draw(imd, 0, 0, imd->window_width, imd->window_height); - } - - image_update_util(imd); - - return; - } - - imd->image_width = gdk_pixbuf_get_width(imd->pixbuf); - imd->image_height = gdk_pixbuf_get_height(imd->pixbuf); - -#if 0 - /* reset scrolling */ - imd->x_scroll = 0; - imd->y_scroll = 0; -#endif - - image_zoom_sync(imd, zoom, TRUE, blank, new, FALSE, 0, 0); -} - -static void image_set_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom, gint new) -{ - if (pixbuf) g_object_ref(pixbuf); - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = pixbuf; - - image_pixbuf_sync(imd, zoom, FALSE, new); -} - static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp) { + PixbufRenderer *pr; GdkPixbuf *new = NULL; gint x, y; gint t; + pr = (PixbufRenderer *)imd->pr; + imd->delay_alter_type = ALTER_NONE; - if (!imd->pixbuf) return; + if (!pr->pixbuf) return; - x = imd->x_scroll + (imd->vis_width / 2); - y = imd->y_scroll + (imd->vis_height / 2); + x = pr->x_scroll + (pr->vis_width / 2); + y = pr->y_scroll + (pr->vis_height / 2); switch (type) { case ALTER_ROTATE_90: - new = pixbuf_copy_rotate_90(imd->pixbuf, FALSE); + new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE); t = x; - x = imd->height - y; + x = pr->height - y; y = t; break; case ALTER_ROTATE_90_CC: - new = pixbuf_copy_rotate_90(imd->pixbuf, TRUE); + new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE); t = x; x = y; - y = imd->width - t; + y = pr->width - t; break; case ALTER_ROTATE_180: - new = pixbuf_copy_mirror(imd->pixbuf, TRUE, TRUE); - x = imd->width - x; - y = imd->height - y; + new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE); + x = pr->width - x; + y = pr->height - y; break; case ALTER_MIRROR: - new = pixbuf_copy_mirror(imd->pixbuf, TRUE, FALSE); - x = imd->width - x; + new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE); + x = pr->width - x; break; case ALTER_FLIP: - new = pixbuf_copy_mirror(imd->pixbuf, FALSE, TRUE); - y = imd->height - y; + new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE); + y = pr->height - y; break; case ALTER_NONE: default: @@ -2015,26 +194,18 @@ if (!new) return; - if (clamp) - { - image_set_pixbuf(imd, new, imd->zoom, TRUE); - g_object_unref(new); + pixbuf_renderer_set_pixbuf(pr, new, pr->zoom); + g_object_unref(new); - if (imd->zoom != 0.0) - { - image_scroll(imd, x - (imd->vis_width / 2), y - (imd->vis_height / 2)); - } - } - else + if (clamp && pr->zoom != 0.0) { - g_object_unref(imd->pixbuf); - imd->pixbuf = new; + pixbuf_renderer_scroll(pr, x - (pr->vis_width / 2), y - (pr->vis_height / 2)); } } static void image_post_process(ImageWindow *imd, gint clamp) { - if (exif_rotate_enable && imd->pixbuf) + if (exif_rotate_enable && image_get_pixbuf(imd)) { ExifData *ed; gint orientation; @@ -2211,16 +382,15 @@ if (imd->prev_pixbuf && imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0) { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = imd->prev_pixbuf; + image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd)); success = TRUE; } else { - if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf); success = FALSE; } + if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf); imd->prev_pixbuf = NULL; g_free(imd->prev_path); @@ -2237,50 +407,27 @@ static void image_load_pixbuf_ready(ImageWindow *imd) { - if (imd->pixbuf || !imd->il) return; - - imd->pixbuf = image_loader_get_pixbuf(imd->il); + if (image_get_pixbuf(imd) || !imd->il) return; - if (imd->pixbuf) g_object_ref(imd->pixbuf); - - image_pixbuf_sync(imd, imd->zoom, TRUE, TRUE); + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd)); } static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data) { ImageWindow *imd = data; + PixbufRenderer *pr; + + pr = (PixbufRenderer *)imd->pr; if (imd->delay_flip && - imd->pixbuf != image_loader_get_pixbuf(il)) + pr->pixbuf != image_loader_get_pixbuf(il)) { return; } - if (!imd->pixbuf) image_load_pixbuf_ready(imd); - - if (imd->scale != 1.0) - { - x = (guint) floor((double)x * imd->scale); - y = (guint) floor((double)y * imd->scale); - w = (guint) ceil((double)w * imd->scale); - h = (guint) ceil((double)h * imd->scale); - - if (w == 0) w = 1; - if (h == 0) h = 1; + if (!pr->pixbuf) image_load_pixbuf_ready(imd); - if ((GdkInterpType)zoom_quality != GDK_INTERP_NEAREST) - { - /* some scaling types use surrounding pixels to smooth the image, - * this will expand the new area to cover up for faint black - * lines caused by previous renders with non-complete image - */ - y -= 1; - h += 2; - } - - } - - image_queue(imd, (gint) x, (gint) y, (gint) w, (gint) h, FALSE, TILE_RENDER_AREA, TRUE); + pixbuf_renderer_area_changed(pr, x, y, w, h); } static void image_load_done_cb(ImageLoader *il, gpointer data) @@ -2289,13 +436,12 @@ if (debug) printf ("image done\n"); + g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL); + if (imd->delay_flip && - imd->pixbuf != image_loader_get_pixbuf(imd->il)) + image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = image_loader_get_pixbuf(imd->il); - if (imd->pixbuf) g_object_ref(imd->pixbuf); - image_pixbuf_sync(imd, imd->zoom, FALSE, TRUE); + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd)); } image_loader_free(imd->il); @@ -2360,11 +506,11 @@ /* do this one directly (probably should add a set func) */ imd->il->func_done = image_load_done_cb; + g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL); + if (!imd->delay_flip) { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = image_loader_get_pixbuf(imd->il); - if (imd->pixbuf) g_object_ref(imd->pixbuf); + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd)); } image_read_ahead_cancel(imd); @@ -2372,8 +518,8 @@ } else if (imd->read_ahead_pixbuf) { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = imd->read_ahead_pixbuf; + image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd)); + g_object_unref(imd->read_ahead_pixbuf); imd->read_ahead_pixbuf = NULL; image_read_ahead_cancel(imd); @@ -2397,25 +543,26 @@ if (image_post_buffer_get(imd)) { if (debug) printf("from post buffer: %s\n", imd->image_path); - - image_pixbuf_sync(imd, imd->zoom, FALSE, TRUE); return TRUE; } if (image_read_ahead_check(imd)) { if (debug) printf("from read ahead buffer: %s\n", imd->image_path); - - if (!imd->delay_flip || !imd->il) image_pixbuf_sync(imd, imd->zoom, FALSE, TRUE); return TRUE; } - if (!imd->delay_flip && imd->pixbuf) + if (!imd->delay_flip && image_get_pixbuf(imd)) { - g_object_unref(imd->pixbuf); - imd->pixbuf = NULL; + PixbufRenderer *pr; + + pr = PIXBUF_RENDERER(imd->pr); + if (pr->pixbuf) g_object_unref(pr->pixbuf); + pr->pixbuf = NULL; } + g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL); + imd->il = image_loader_new(path); image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd); @@ -2426,6 +573,8 @@ { if (debug) printf("image start error\n"); + g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL); + image_loader_free(imd->il); imd->il = NULL; @@ -2438,7 +587,7 @@ image_load_buffer_throttle(imd->il); #endif - if (!imd->delay_flip && !imd->pixbuf) image_load_pixbuf_ready(imd); + if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd); return TRUE; } @@ -2449,10 +598,11 @@ if (debug) printf("image reset\n"); + g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL); + image_loader_free(imd->il); imd->il = NULL; - image_queue_clear(imd); imd->delay_alter_type = ALTER_NONE; } @@ -2464,25 +614,27 @@ static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new) { - gint sync = TRUE; - - image_source_tile_unset(imd); - - imd->zoom = zoom; /* store the zoom, needed by the loader */ - image_reset(imd); if (imd->image_path && isfile(imd->image_path)) { + PixbufRenderer *pr; + + pr = PIXBUF_RENDERER(imd->pr); + pr->zoom = zoom; /* store the zoom, needed by the loader */ + if (image_load_begin(imd, imd->image_path)) { imd->unknown = FALSE; - sync = FALSE; } else { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); + GdkPixbuf *pixbuf; + + pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); + image_change_pixbuf(imd, pixbuf, zoom); + g_object_unref(pixbuf); + imd->unknown = TRUE; } imd->size = filesize(imd->image_path); @@ -2490,36 +642,31 @@ } else { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = NULL; - if (imd->image_path) { - imd->pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); + GdkPixbuf *pixbuf; + + pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); + image_change_pixbuf(imd, pixbuf, zoom); + g_object_unref(pixbuf); imd->mtime = filetime(imd->image_path); } else { - imd->pixbuf = NULL; + image_change_pixbuf(imd, NULL, zoom); imd->mtime = 0; } imd->unknown = TRUE; imd->size = 0; } - if (sync) - { - image_pixbuf_sync(imd, zoom, FALSE, new); - } - else - { - image_update_util(imd); - } + image_update_util(imd); } static void image_change_real(ImageWindow *imd, const gchar *path, CollectionData *cd, CollectInfo *info, gdouble zoom) { + GdkPixbuf *pixbuf; GdkPixbuf *prev_pixbuf = NULL; gchar *prev_path = NULL; gint prev_clear = FALSE; @@ -2527,7 +674,9 @@ imd->collection = cd; imd->collection_info = info; - if (enable_read_ahead && imd->image_path && imd->pixbuf) + pixbuf = image_get_pixbuf(imd); + + if (enable_read_ahead && imd->image_path && pixbuf) { if (imd->il) { @@ -2537,7 +686,7 @@ else { prev_path = g_strdup(imd->image_path); - prev_pixbuf = imd->pixbuf; + prev_pixbuf = pixbuf; g_object_ref(prev_pixbuf); } } @@ -2565,40 +714,6 @@ /* *------------------------------------------------------------------- - * callbacks - *------------------------------------------------------------------- - */ - -static gint image_expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - gint x, y; - - ImageWindow *imd = data; - - image_border_draw(imd, event->area.x, event->area.y, - event->area.width, event->area.height); - - /* image */ - x = MAX(0, (gint)event->area.x - imd->x_offset + imd->x_scroll); - y = MAX(0, (gint)event->area.y - imd->y_offset + imd->y_scroll); - - image_queue(imd, x, y, - MIN((gint)event->area.width, imd->width - x), - MIN((gint)event->area.height, imd->height - y), - FALSE, TILE_RENDER_ALL, FALSE); - - return TRUE; -} - -static void image_size_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data) -{ - ImageWindow *imd = data; - - image_size_sync(imd, allocation->width, allocation->height); -} - -/* - *------------------------------------------------------------------- * focus stuff *------------------------------------------------------------------- */ @@ -2654,477 +769,25 @@ return TRUE; } - -/* - *------------------------------------------------------------------- - * overlays - *------------------------------------------------------------------- - */ - -static void image_overlay_draw(ImageWindow *imd, gint x, gint y, gint w, gint h) -{ - GList *work; - - work = imd->overlay_list; - while (work) - { - OverlayData *od; - gint px, py, pw, ph; - gint rx, ry, rw, rh; - - od = work->data; - work = work->next; - - if (!od->visible) continue; - - pw = gdk_pixbuf_get_width(od->pixbuf); - ph = gdk_pixbuf_get_height(od->pixbuf); - px = od->x; - py = od->y; - - if (od->relative) - { - if (px < 0) px = imd->window_width - pw + px; - if (py < 0) py = imd->window_height - ph + py; - } - - if (util_clip_region(x, y, w, h, px, py, pw, ph, &rx, &ry, &rw, &rh)) - { - gdk_draw_pixbuf(imd->image->window, - imd->image->style->fg_gc[GTK_WIDGET_STATE(imd->image)], - od->pixbuf, - rx - px, ry - py, - rx, ry, rw, rh, - (GdkRgbDither)dither_quality, rx, ry); - } - } -} - -static void image_overlay_queue_draw(ImageWindow *imd, OverlayData *od, gint hidden) -{ - gint x, y, w, h; - gint old_vis; - - w = gdk_pixbuf_get_width(od->pixbuf); - h = gdk_pixbuf_get_height(od->pixbuf); - x = od->x; - y = od->y; - - if (od->relative) - { - if (x < 0) x = imd->window_width - w + x; - if (y < 0) y = imd->window_height - h + y; - } - - image_queue(imd, imd->x_scroll - imd->x_offset + x, - imd->y_scroll - imd->y_offset + y, - w, h, - FALSE, TILE_RENDER_ALL, FALSE); - - old_vis = od->visible; - if (hidden) od->visible = FALSE; - image_border_draw(imd, x, y, w, h); - od->visible = old_vis; -} - -static void image_overlay_queue_all(ImageWindow *imd) -{ - GList *work; - - work = imd->overlay_list; - while (work) - { - OverlayData *od = work->data; - work = work->next; - - image_overlay_queue_draw(imd, od, FALSE); - } -} - -static OverlayData *image_overlay_find(ImageWindow *imd, gint id) -{ - GList *work; - - work = imd->overlay_list; - while (work) - { - OverlayData *od = work->data; - work = work->next; - - if (od->id == id) return od; - } - - return NULL; -} - gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y, gint relative, gint always) { - OverlayData *od; - gint id; - - if (!imd || !pixbuf) return -1; - - id = 1; - while (image_overlay_find(imd, id)) id++; - - od = g_new0(OverlayData, 1); - od->id = id; - od->pixbuf = pixbuf; - g_object_ref(G_OBJECT(od->pixbuf)); - od->x = x; - od->y = y; - od->relative = relative; - od->visible = TRUE; - od->always = always; - - imd->overlay_list = g_list_append(imd->overlay_list, od); - - image_overlay_queue_draw(imd, od, FALSE); - - return od->id; -} - -static void image_overlay_free(ImageWindow *imd, OverlayData *od) -{ - imd->overlay_list = g_list_remove(imd->overlay_list, od); - - if (od->pixbuf) g_object_unref(G_OBJECT(od->pixbuf)); - g_free(od); -} - -static void image_overlay_list_clear(ImageWindow *imd) -{ - while (imd->overlay_list) - { - OverlayData *od; - - od = imd->overlay_list->data; - image_overlay_free(imd, od); - } + return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always); } void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y) { - OverlayData *od; - - if (!imd) return; - - od = image_overlay_find(imd, id); - if (!od) return; - - if (pixbuf) - { - image_overlay_queue_draw(imd, od, TRUE); - - g_object_ref(G_OBJECT(pixbuf)); - g_object_unref(G_OBJECT(od->pixbuf)); - od->pixbuf = pixbuf; - - od->x = x; - od->y = y; - - image_overlay_queue_draw(imd, od, FALSE); - } - else - { - image_overlay_queue_draw(imd, od, TRUE); - image_overlay_free(imd, od); - } + pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y); } gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y) { - OverlayData *od; - - if (!imd) return FALSE; - - od = image_overlay_find(imd, id); - if (!od) return FALSE; - - if (pixbuf) *pixbuf = od->pixbuf; - if (x) *x = od->x; - if (y) *y = od->y; - - return TRUE; + return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y); } void image_overlay_remove(ImageWindow *imd, gint id) { - image_overlay_set(imd, id, NULL, 0, 0); -} - -/* - *------------------------------------------------------------------- - * scroller - *------------------------------------------------------------------- - */ - -#define SCROLLER_UPDATES_PER_SEC 30 -#define SCROLLER_DEAD_ZONE 6 - - -static gboolean image_scroller_update_cb(gpointer data) -{ - ImageWindow *imd = data; - gint x, y; - gint xinc, yinc; - - /* this was a simple scroll by difference between scroller and mouse position, - * but all this math results in a smoother result and accounts for a dead zone. - */ - - if (abs(imd->scroller_xpos - imd->scroller_x) < SCROLLER_DEAD_ZONE) - { - x = 0; - } - else - { - gint shift = SCROLLER_DEAD_ZONE / 2 * SCROLLER_UPDATES_PER_SEC; - x = (imd->scroller_xpos - imd->scroller_x) / 2 * SCROLLER_UPDATES_PER_SEC; - x += (x > 0) ? -shift : shift; - } - - if (abs(imd->scroller_ypos - imd->scroller_y) < SCROLLER_DEAD_ZONE) - { - y = 0; - } - else - { - gint shift = SCROLLER_DEAD_ZONE / 2 * SCROLLER_UPDATES_PER_SEC; - y = (imd->scroller_ypos - imd->scroller_y) / 2 * SCROLLER_UPDATES_PER_SEC; - y += (y > 0) ? -shift : shift; - } - - if (abs(x) < SCROLLER_DEAD_ZONE * SCROLLER_UPDATES_PER_SEC) - { - xinc = x; - } - else - { - xinc = imd->scroller_xinc; - - if (x >= 0) - { - if (xinc < 0) xinc = 0; - if (x < xinc) xinc = x; - if (x > xinc) xinc = MIN(xinc + x / SCROLLER_UPDATES_PER_SEC, x); - } - else - { - if (xinc > 0) xinc = 0; - if (x > xinc) xinc = x; - if (x < xinc) xinc = MAX(xinc + x / SCROLLER_UPDATES_PER_SEC, x); - } - } - - if (abs(y) < SCROLLER_DEAD_ZONE * SCROLLER_UPDATES_PER_SEC) - { - yinc = y; - } - else - { - yinc = imd->scroller_yinc; - - if (y >= 0) - { - if (yinc < 0) yinc = 0; - if (y < yinc) yinc = y; - if (y > yinc) yinc = MIN(yinc + y / SCROLLER_UPDATES_PER_SEC, y); - } - else - { - if (yinc > 0) yinc = 0; - if (y > yinc) yinc = y; - if (y < yinc) yinc = MAX(yinc + y / SCROLLER_UPDATES_PER_SEC, y); - } - } - - imd->scroller_xinc = xinc; - imd->scroller_yinc = yinc; - - xinc = xinc / SCROLLER_UPDATES_PER_SEC; - yinc = yinc / SCROLLER_UPDATES_PER_SEC; - - image_scroll(imd, xinc, yinc); - - return TRUE; -} - -static void image_scroller_timer_set(ImageWindow *imd, gint start) -{ - if (imd->scroller_id != -1) - { - g_source_remove(imd->scroller_id); - imd->scroller_id = -1; - } - - if (start) - { - imd->scroller_id = g_timeout_add(1000 / SCROLLER_UPDATES_PER_SEC, - image_scroller_update_cb, imd); - } -} - -static void image_scroller_start(ImageWindow *imd, gint x, gint y) -{ - if (imd->scroller_overlay == -1) - { - GdkPixbuf *pixbuf; - gint w, h; - - pixbuf = pixbuf_inline(PIXBUF_INLINE_SCROLLER); - w = gdk_pixbuf_get_width(pixbuf); - h = gdk_pixbuf_get_height(pixbuf); - - imd->scroller_overlay = image_overlay_add(imd, pixbuf, x - w / 2, y - h / 2, FALSE, TRUE); - } - - imd->scroller_x = x; - imd->scroller_y = y; - imd->scroller_xpos = x; - imd->scroller_ypos = y; - - image_scroller_timer_set(imd, TRUE); -} - -static void image_scroller_stop(ImageWindow *imd) -{ - if (imd->scroller_id == -1) return; - - image_overlay_remove(imd, imd->scroller_overlay); - imd->scroller_overlay = -1; - - image_scroller_timer_set(imd, FALSE); -} - -/* - *------------------------------------------------------------------- - * mouse stuff - *------------------------------------------------------------------- - */ - -static gint image_mouse_motion_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) -{ - ImageWindow *imd = data; - gint accel; - - if (imd->scroller_id != -1) - { - imd->scroller_xpos = bevent->x; - imd->scroller_ypos = bevent->y; - } - - if (!imd->in_drag || !gdk_pointer_is_grabbed()) return FALSE; - - if (imd->drag_moved < IMAGE_DRAG_SCROLL_THRESHHOLD) - { - imd->drag_moved++; - } - else - { - widget_set_cursor (imd->image, GDK_FLEUR); - } - - if (bevent->state & GDK_SHIFT_MASK) - { - accel = IMAGE_PAN_SHIFT_MULTIPLIER; - } - else - { - accel = 1; - } - - /* do the scroll */ - image_scroll_real(imd, (imd->drag_last_x - bevent->x) * accel, - (imd->drag_last_y - bevent->y) * accel); - - imd->drag_last_x = bevent->x; - imd->drag_last_y = bevent->y; - - return FALSE; -} - -static gint image_mouse_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) -{ - ImageWindow *imd = data; - - if (imd->scroller_id != -1) return TRUE; - - switch (bevent->button) - { - case 1: - imd->in_drag = TRUE; - imd->drag_last_x = bevent->x; - imd->drag_last_y = bevent->y; - imd->drag_moved = 0; - gdk_pointer_grab(imd->image->window, FALSE, - GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, - NULL, NULL, bevent->time); - gtk_grab_add(imd->image); - break; - case 2: - imd->drag_moved = 0; - break; - case 3: - image_button_do(imd, bevent); - break; - default: - break; - } - - gtk_widget_grab_focus(imd->widget); - - return FALSE; -} - -static gint image_mouse_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) -{ - ImageWindow *imd = data; - - if (imd->scroller_id != -1) - { - image_scroller_stop(imd); - return TRUE; - } - - if (gdk_pointer_is_grabbed() && GTK_WIDGET_HAS_GRAB(imd->image)) - { - gtk_grab_remove(imd->image); - gdk_pointer_ungrab(bevent->time); - widget_set_cursor(imd->image, -1); - } - - if (imd->drag_moved < IMAGE_DRAG_SCROLL_THRESHHOLD) - { - if (bevent->button == 1 && (bevent->state & GDK_SHIFT_MASK)) - { - image_scroller_start(imd, bevent->x, bevent->y); - } - else if (bevent->button == 1 || bevent->button == 2) - { - image_button_do(imd, bevent); - } - } - - imd->in_drag = FALSE; - - return FALSE; -} - -static gint image_mouse_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data) -{ - ImageWindow *imd = data; - - if (imd->scroller_id != -1) - { - imd->scroller_xpos = imd->scroller_x; - imd->scroller_ypos = imd->scroller_y; - imd->scroller_xinc = 0; - imd->scroller_yinc = 0; - } - - return FALSE; + pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id); } static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data) @@ -3142,19 +805,6 @@ return FALSE; } -static void image_mouse_drag_cb(GtkWidget *widget, GdkDragContext *context, gpointer data) -{ - ImageWindow *imd = data; - - imd->drag_moved = IMAGE_DRAG_SCROLL_THRESHHOLD; -} - -/* - *------------------------------------------------------------------- - * drag and drop - *------------------------------------------------------------------- - */ - /* *------------------------------------------------------------------- * public interface @@ -3171,6 +821,10 @@ imd->title_right = g_strdup(title_right); imd->title_show_zoom = show_zoom; + if (!fit_window) window = NULL; + + pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window); + image_update_title(imd); } @@ -3199,17 +853,6 @@ } -static void image_button_do(ImageWindow *imd, GdkEventButton *bevent) -{ - if (imd->func_button && - bevent && - (bevent->type == GDK_BUTTON_PRESS || bevent->type == GDK_BUTTON_RELEASE)) - { - imd->func_button(imd, bevent->button, bevent->time, - bevent->x, bevent->y, bevent->state, imd->data_button); - } -} - void image_set_button_func(ImageWindow *imd, void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer), gpointer data) @@ -3264,16 +907,17 @@ if (imd->image_path == path || (path && imd->image_path && !strcmp(path, imd->image_path)) ) return; - image_source_tile_unset(imd); + image_change_real(imd, path, NULL, NULL, zoom); +} - image_change_real(imd, path, NULL, NULL, zoom); +GdkPixbuf *image_get_pixbuf(ImageWindow *imd) +{ + return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr); } void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom) { - image_source_tile_unset(imd); - - image_set_pixbuf(imd, pixbuf, zoom, TRUE); + pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom); image_new_util(imd); } @@ -3281,8 +925,6 @@ { if (!cd || !info || !g_list_find(cd->list, info)) return; - image_source_tile_unset(imd); - image_change_real(imd, info->path, cd, info, zoom); } @@ -3305,6 +947,7 @@ return NULL; } +#if 0 static void image_loader_sync_data(ImageLoader *il, gpointer data) { /* change data for the callbacks directly */ @@ -3314,6 +957,7 @@ il->data_done = data; il->data_percent = data; } +#endif /* this is more like a move function * it moves most data from source to imd, source does keep a ref on the pixbuf @@ -3322,6 +966,8 @@ { if (imd == source) return; + printf("FIXME: enable set from image\n"); +#if 0 imd->zoom_min = source->zoom_min; imd->zoom_max = source->zoom_max; @@ -3414,60 +1060,37 @@ } image_scroll_clamp(imd); +#endif } /* manipulation */ void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height) { - gint sx, sy, sw, sh; - - sx = (gint)floor((double)x * imd->scale); - sy = (gint)floor((double)y * imd->scale); - sw = (gint)ceil((double)width * imd->scale); - sh = (gint)ceil((double)height * imd->scale); - - if (imd->source_tiles_enabled) - { - source_tile_changed(imd, x, y, width, height); - } - - image_queue(imd, sx, sy, sw, sh, FALSE, TILE_RENDER_AREA, TRUE); + pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height); } void image_reload(ImageWindow *imd) { - if (imd->source_tiles_enabled) return; + if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; - image_change_complete(imd, imd->zoom, FALSE); + image_change_complete(imd, image_zoom_get(imd), FALSE); } void image_scroll(ImageWindow *imd, gint x, gint y) { - image_scroll_real(imd, x, y); + pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y); } void image_scroll_to_point(ImageWindow *imd, gint x, gint y, gdouble x_align, gdouble y_align) { - gint px, py; - gint ax, ay; - - x_align = CLAMP(x_align, 0.0, 1.0); - y_align = CLAMP(y_align, 0.0, 1.0); - - ax = (gdouble)imd->vis_width * x_align; - ay = (gdouble)imd->vis_height * y_align; - - px = (gdouble)x * imd->scale - (imd->x_scroll + ax); - py = (gdouble)y * imd->scale - (imd->y_scroll + ay); - - image_scroll(imd, px, py); + pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align); } void image_alter(ImageWindow *imd, AlterType type) { - if (imd->source_tiles_enabled) return; + if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; if (imd->il) { @@ -3479,91 +1102,44 @@ image_alter_real(imd, type, TRUE); } -/* zoom */ - -static void image_zoom_adjust_real(ImageWindow *imd, gdouble increment, - gint center_point, gint x, gint y) -{ - gdouble zoom = imd->zoom; - - if (increment == 0.0) return; /* avoid possible div by zero, a no-op anyway... */ - - if (zoom == 0.0) - { - if (imd->scale < 1.0) - { - zoom = 0.0 - 1.0 / imd->scale; - } - else - { - zoom = imd->scale; - } - } - - if (increment < 0.0) - { - if (zoom >= 1.0 && zoom + increment < 1.0) - { - zoom = zoom + increment - 2.0; - } - else - { - zoom = zoom + increment; - } - } - else - { - if (zoom <= -1.0 && zoom + increment > -1.0) - { - zoom = zoom + increment + 2.0; - } - else - { - zoom = zoom + increment; - } - } - - image_zoom_sync(imd, zoom, FALSE, FALSE, FALSE, center_point, x, y); -} - void image_zoom_adjust(ImageWindow *imd, gdouble increment) { - image_zoom_adjust_real(imd, increment, FALSE, 0, 0); + pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment); } void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y) { - image_zoom_adjust_real(imd, increment, TRUE, x, y); + pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y); } void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max) { - if (min > 1.0 || max < 1.0) return; - if (min < 1.0 && min > -1.0) return; - if (min < -200.0 || max > 200.0) return; - - imd->zoom_min = min; - imd->zoom_max = max; + pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max); } void image_zoom_set(ImageWindow *imd, gdouble zoom) { - image_zoom_sync(imd, zoom, FALSE, FALSE, FALSE, FALSE, 0, 0); + pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom); } void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical) { + PixbufRenderer *pr; gdouble zoom; + gint width, height; - if (!imd->pixbuf || imd->image_width < 1 || imd->image_height < 1) return; + pr = (PixbufRenderer *)imd->pr; + + if (!pixbuf_renderer_get_pixbuf(pr) || + !pixbuf_renderer_get_image_size(pr, &width, &height)) return; if (vertical) { - zoom = (gdouble)imd->window_height / imd->image_height; + zoom = (gdouble)pr->window_height / height; } else { - zoom = (gdouble)imd->window_width / imd->image_width; + zoom = (gdouble)pr->window_width / width; } if (zoom < 1.0) @@ -3571,44 +1147,49 @@ zoom = 0.0 - 1.0 / zoom; } - image_zoom_set(imd, zoom); + pixbuf_renderer_zoom_set(pr, zoom); } gdouble image_zoom_get(ImageWindow *imd) { - return imd->zoom; + return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr); } gdouble image_zoom_get_real(ImageWindow *imd) { - return imd->scale; + return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr); } gchar *image_zoom_get_as_text(ImageWindow *imd) { + gdouble zoom; + gdouble scale; gdouble l = 1.0; gdouble r = 1.0; gint pl = 0; gint pr = 0; gchar *approx = " "; - if (imd->zoom > 0.0) - { - l = imd->zoom; - } - else if (imd->zoom < 0.0) + zoom = image_zoom_get(imd); + scale = image_zoom_get_real(imd); + + if (zoom > 0.0) { - r = 0.0 - imd->zoom; + l = zoom; } - else if (imd->zoom == 0.0 && imd->scale != 0.0) + else if (zoom < 0.0) { - if (imd->scale >= 1.0) + r = 0.0 - zoom; + } + else if (zoom == 0.0 && scale != 0.0) + { + if (scale >= 1.0) { - l = imd->scale; + l = scale; } else { - r = 1.0 / imd->scale; + r = 1.0 / scale; } approx = " ~"; } @@ -3650,7 +1231,7 @@ void image_prebuffer_set(ImageWindow *imd, const gchar *path) { - if (imd->source_tiles_enabled) return; + if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; if (path) { @@ -3667,7 +1248,7 @@ ImageWindow *imd = data; time_t newtime; - if (!imd || !imd->pixbuf || + if (!imd || !image_get_pixbuf(imd) || imd->il || !imd->image_path || !update_on_time_change) return TRUE; @@ -3686,7 +1267,7 @@ void image_auto_refresh(ImageWindow *imd, gint interval) { if (!imd) return; - if (imd->source_tiles_enabled) return; + if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; if (imd->auto_refresh_id > -1) { @@ -3703,59 +1284,21 @@ imd->auto_refresh_interval = interval; } -/* allow top window to be resized ? */ - void image_top_window_set_sync(ImageWindow *imd, gint allow_sync) { imd->top_window_sync = allow_sync; + + g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL); } -/* background colors */ - void image_background_set_black(ImageWindow *imd, gint black) { - GtkStyle *style; - - if (!imd) return; - - style = gtk_style_copy(gtk_widget_get_style(imd->widget)); - g_object_ref(G_OBJECT(style)); - - if (black) - { - style->bg[GTK_STATE_NORMAL] = style->black; - } - - gtk_widget_set_style(imd->image, style); - g_object_unref(G_OBJECT(style)); - - if (GTK_WIDGET_VISIBLE(imd->widget)) image_border_clear(imd); + pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black); } void image_background_set_color(ImageWindow *imd, GdkColor *color) { - GtkStyle *style; - - if (!imd) return; - - style = gtk_style_copy(gtk_widget_get_style(imd->widget)); - g_object_ref(G_OBJECT(style)); - - if (color) - { - GdkColor *slot; - - slot = &style->bg[GTK_STATE_NORMAL]; - - slot->red = color->red; - slot->green = color->green; - slot->blue = color->blue; - } - - gtk_widget_set_style(imd->image, style); - g_object_unref(G_OBJECT(style)); - - if (GTK_WIDGET_VISIBLE(imd->widget)) image_border_clear(imd); + pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color); } void image_set_delay_flip(ImageWindow *imd, gint delay) @@ -3764,41 +1307,51 @@ imd->delay_flip == delay) return; imd->delay_flip = delay; + + g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL); + if (!imd->delay_flip && imd->il) { - if (imd->pixbuf) g_object_unref(imd->pixbuf); - imd->pixbuf = NULL; + PixbufRenderer *pr; + + pr = PIXBUF_RENDERER(imd->pr); + if (pr->pixbuf) g_object_unref(pr->pixbuf); + pr->pixbuf = NULL; + image_load_pixbuf_ready(imd); - - image_queue_clear(imd); - image_queue(imd, 0, 0, imd->width, imd->height, FALSE, TILE_RENDER_AREA, TRUE); } } -/* wallpaper util */ - void image_to_root_window(ImageWindow *imd, gint scaled) { GdkScreen *screen; GdkWindow *rootwindow; GdkPixmap *pixmap; + GdkPixbuf *pixbuf; GdkPixbuf *pb; + gint width, height; - if (!imd || !imd->pixbuf) return; + if (!imd) return; - screen = gtk_widget_get_screen(imd->image); + pixbuf = image_get_pixbuf(imd); + if (!pixbuf) return; + + screen = gtk_widget_get_screen(imd->widget); rootwindow = gdk_screen_get_root_window(screen); if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return; if (scaled) { - pb = gdk_pixbuf_scale_simple(imd->pixbuf, gdk_screen_width(), gdk_screen_height(), (GdkInterpType)zoom_quality); + width = gdk_screen_width(); + height = gdk_screen_height(); } else { - pb = gdk_pixbuf_scale_simple(imd->pixbuf, imd->width, imd->height, (GdkInterpType)zoom_quality); + pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height); } + pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality); + gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128); gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE); gdk_window_clear(rootwindow); @@ -3808,7 +1361,6 @@ gdk_flush(); } - /* *------------------------------------------------------------------- * init / destroy @@ -3817,6 +1369,8 @@ static void image_free(ImageWindow *imd) { + image_reset(imd); + image_read_ahead_cancel(imd); image_post_buffer_set(imd, NULL, NULL); image_auto_refresh(imd, -1); @@ -3825,16 +1379,6 @@ g_free(imd->title); g_free(imd->title_right); - image_reset(imd); - image_tile_sync_count(imd, 0); - if (imd->pixbuf) g_object_unref(imd->pixbuf); - - image_scroller_timer_set(imd, FALSE); - - image_overlay_list_clear(imd); - - source_tile_free_all(imd); - g_free(imd); } @@ -3850,16 +1394,6 @@ imd = g_new0(ImageWindow, 1); - imd->zoom_min = IMAGE_ZOOM_MIN; - imd->zoom_max = IMAGE_ZOOM_MAX; - imd->zoom = 1.0; - imd->scale = 1.0; - - imd->draw_idle_id = -1; - - imd->tile_width = IMAGE_TILE_SIZE; - imd->tile_height = IMAGE_TILE_SIZE; - imd->top_window = NULL; imd->title = NULL; imd->title_right = NULL; @@ -3867,14 +1401,9 @@ imd->unknown = TRUE; - imd->pixbuf = NULL; - imd->has_frame = frame; imd->top_window_sync = FALSE; - imd->tile_cache = NULL; - imd->tile_cache_size = 0; - imd->delay_alter_type = ALTER_NONE; imd->read_ahead_il = NULL; @@ -3896,21 +1425,16 @@ imd->func_button = NULL; imd->func_scroll = NULL; - imd->scroller_id = -1; - imd->scroller_overlay = -1; + imd->pr = GTK_WIDGET(pixbuf_renderer_new()); - imd->source_tiles_enabled = FALSE; - imd->source_tiles = NULL; - - imd->image = gtk_drawing_area_new(); - gtk_widget_set_double_buffered(imd->image, FALSE); + g_object_set(G_OBJECT(imd->pr), "zoom_2pass", TRUE, NULL); if (imd->has_frame) { imd->widget = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(imd->widget), imd->image); - gtk_widget_show(imd->image); + gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr); + gtk_widget_show(imd->pr); GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS); g_signal_connect(G_OBJECT(imd->widget), "focus_in_event", @@ -3923,32 +1447,18 @@ } else { - imd->widget = imd->image; + imd->widget = imd->pr; } - g_signal_connect(G_OBJECT(imd->image), "motion_notify_event", - G_CALLBACK(image_mouse_motion_cb), imd); - g_signal_connect(G_OBJECT(imd->image), "button_press_event", - G_CALLBACK(image_mouse_press_cb), imd); - g_signal_connect(G_OBJECT(imd->image), "button_release_event", - G_CALLBACK(image_mouse_release_cb), imd); - g_signal_connect(G_OBJECT(imd->image), "leave_notify_event", - G_CALLBACK(image_mouse_leave_cb), imd); - gtk_widget_set_events(imd->image, GDK_POINTER_MOTION_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_LEAVE_NOTIFY_MASK); + g_signal_connect(G_OBJECT(imd->pr), "clicked", + G_CALLBACK(image_click_cb), imd); + g_signal_connect(G_OBJECT(imd->pr), "scroll_notify", + G_CALLBACK(image_scroll_notify_cb), imd); - g_signal_connect(G_OBJECT(imd->image), "expose_event", - G_CALLBACK(image_expose_cb), imd); - g_signal_connect_after(G_OBJECT(imd->image), "size_allocate", - G_CALLBACK(image_size_cb), imd); - - g_signal_connect(G_OBJECT(imd->image), "drag_begin", - G_CALLBACK(image_mouse_drag_cb), imd); - g_signal_connect(G_OBJECT(imd->image), "scroll_event", + g_signal_connect(G_OBJECT(imd->pr), "scroll_event", G_CALLBACK(image_scroll_cb), imd); - g_signal_connect(G_OBJECT(imd->widget), "destroy", + g_signal_connect(G_OBJECT(imd->pr), "destroy", G_CALLBACK(image_destroy_cb), imd); return imd;