7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
17 #include "image-load.h"
20 #include "pixbuf-renderer.h"
21 #include "pixbuf_util.h"
22 #include "ui_fileops.h"
27 /* size of the image loader buffer (512 bytes x defined number) */
28 #define IMAGE_LOAD_BUFFER_COUNT 8
30 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
31 #define IMAGE_THROTTLE_LARGER_IMAGES 1
33 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
34 #define IMAGE_THROTTLE_FACTOR 4
36 /* the file size at which throttling take place */
37 #define IMAGE_THROTTLE_THRESHOLD 1048576
39 #define IMAGE_AUTO_REFRESH_TIME 3000
42 static GList *image_list = NULL;
45 static void image_update_title(ImageWindow *imd);
48 *-------------------------------------------------------------------
50 *-------------------------------------------------------------------
53 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
55 ImageWindow *imd = data;
59 imd->func_button(imd, event->button, event->time,
60 event->x, event->y, event->state, imd->data_button);
64 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
66 ImageWindow *imd = data;
68 if (imd->func_scroll_notify && pr->scale)
70 imd->func_scroll_notify(imd,
71 (gint)((gdouble)pr->x_scroll / pr->scale),
72 (gint)((gdouble)pr->y_scroll / pr->scale),
73 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
74 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
75 imd->data_scroll_notify);
79 static void image_update_util(ImageWindow *imd)
81 if (imd->func_update) imd->func_update(imd, imd->data_update);
84 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
86 ImageWindow *imd = data;
88 if (imd->title_show_zoom) image_update_title(imd);
89 image_update_util(imd);
92 static void image_complete_util(ImageWindow *imd, gint preload)
94 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
96 if (debug) printf("image load completed \"%s\" (%s)\n",
97 (preload) ? imd->read_ahead_path : imd->image_path,
98 (preload) ? "preload" : "current");
100 if (!preload) imd->completed = TRUE;
101 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
104 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
106 ImageWindow *imd = data;
108 image_complete_util(imd, FALSE);
111 static void image_new_util(ImageWindow *imd)
113 if (imd->func_new) imd->func_new(imd, imd->data_new);
117 *-------------------------------------------------------------------
119 *-------------------------------------------------------------------
122 static void image_update_title(ImageWindow *imd)
126 gchar *collection = NULL;
128 if (!imd->top_window) return;
130 if (imd->collection && collection_to_number(imd->collection) >= 0)
133 name = imd->collection->name;
134 if (!name) name = _("Untitled");
135 collection = g_strdup_printf(" (Collection %s)", name);
138 if (imd->title_show_zoom)
140 gchar *buf = image_zoom_get_as_text(imd);
141 zoom = g_strconcat(" [", buf, "]", NULL);
145 title = g_strdup_printf("%s%s%s%s%s%s",
146 imd->title ? imd->title : "",
147 imd->image_name ? imd->image_name : "",
149 collection ? collection : "",
150 imd->image_name ? " - " : "",
151 imd->title_right ? imd->title_right : "");
153 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
161 *-------------------------------------------------------------------
162 * rotation, flip, etc.
163 *-------------------------------------------------------------------
166 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
169 GdkPixbuf *new = NULL;
173 pr = (PixbufRenderer *)imd->pr;
175 imd->delay_alter_type = ALTER_NONE;
177 if (!pr->pixbuf) return;
179 x = pr->x_scroll + (pr->vis_width / 2);
180 y = pr->y_scroll + (pr->vis_height / 2);
184 case ALTER_ROTATE_90:
185 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
190 case ALTER_ROTATE_90_CC:
191 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
196 case ALTER_ROTATE_180:
197 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
202 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
206 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
217 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
220 if (clamp && pr->zoom != 0.0)
222 pixbuf_renderer_scroll(pr, x - (pr->vis_width / 2), y - (pr->vis_height / 2));
226 static void image_post_process(ImageWindow *imd, gint clamp)
228 if (exif_rotate_enable && image_get_pixbuf(imd))
233 ed = exif_read(imd->image_path);
234 if (ed && exif_get_integer(ed, "Orientation", &orientation))
236 /* see http://jpegclub.org/exif_orientation.html
239 888888 888888 88 88 8888888888 88 88 8888888888
240 88 88 88 88 88 88 88 88 88 88 88 88
241 8888 8888 8888 8888 88 8888888888 8888888888 88
248 case EXIF_ORIENTATION_TOP_LEFT:
249 /* normal -- nothing to do */
251 case EXIF_ORIENTATION_TOP_RIGHT:
253 imd->delay_alter_type = ALTER_MIRROR;
255 case EXIF_ORIENTATION_BOTTOM_RIGHT:
257 imd->delay_alter_type = ALTER_ROTATE_180;
259 case EXIF_ORIENTATION_BOTTOM_LEFT:
261 imd->delay_alter_type = ALTER_FLIP;
263 case EXIF_ORIENTATION_LEFT_TOP:
264 /* not implemented -- too wacky to fix in one step */
266 case EXIF_ORIENTATION_RIGHT_TOP:
267 /* rotated -90 (270) */
268 imd->delay_alter_type = ALTER_ROTATE_90;
270 case EXIF_ORIENTATION_RIGHT_BOTTOM:
271 /* not implemented -- too wacky to fix in one step */
273 case EXIF_ORIENTATION_LEFT_BOTTOM:
275 imd->delay_alter_type = ALTER_ROTATE_90_CC;
278 /* The other values are out of range */
285 if (imd->delay_alter_type != ALTER_NONE)
287 image_alter_real(imd, imd->delay_alter_type, clamp);
292 *-------------------------------------------------------------------
293 * read ahead (prebuffer)
294 *-------------------------------------------------------------------
297 static void image_read_ahead_cancel(ImageWindow *imd)
299 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
301 image_loader_free(imd->read_ahead_il);
302 imd->read_ahead_il = NULL;
304 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
305 imd->read_ahead_pixbuf = NULL;
307 g_free(imd->read_ahead_path);
308 imd->read_ahead_path = NULL;
311 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
313 ImageWindow *imd = data;
315 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
317 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
318 if (imd->read_ahead_pixbuf)
320 g_object_ref(imd->read_ahead_pixbuf);
324 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
326 image_loader_free(imd->read_ahead_il);
327 imd->read_ahead_il = NULL;
329 image_complete_util(imd, TRUE);
332 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
334 /* we even treat errors as success, maybe at least some of the file was ok */
335 image_read_ahead_done_cb(il, data);
338 static void image_read_ahead_start(ImageWindow *imd)
340 /* already started ? */
341 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
343 /* still loading ?, do later */
346 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
348 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
350 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
351 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
353 image_read_ahead_cancel(imd);
354 image_complete_util(imd, TRUE);
358 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
360 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
362 image_read_ahead_cancel(imd);
364 imd->read_ahead_path = g_strdup(path);
366 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
368 image_read_ahead_start(imd);
372 *-------------------------------------------------------------------
374 *-------------------------------------------------------------------
377 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
379 g_free(imd->prev_path);
380 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
384 imd->prev_path = g_strdup(path);
386 g_object_ref(pixbuf);
387 imd->prev_pixbuf = pixbuf;
391 imd->prev_path = NULL;
392 imd->prev_pixbuf = NULL;
395 if (debug) printf("post buffer set: %s\n", path);
398 static gint image_post_buffer_get(ImageWindow *imd)
402 if (imd->prev_pixbuf &&
403 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
405 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
413 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
414 imd->prev_pixbuf = NULL;
416 g_free(imd->prev_path);
417 imd->prev_path = NULL;
423 *-------------------------------------------------------------------
425 *-------------------------------------------------------------------
428 static void image_load_pixbuf_ready(ImageWindow *imd)
430 if (image_get_pixbuf(imd) || !imd->il) return;
432 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
435 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
437 ImageWindow *imd = data;
440 pr = (PixbufRenderer *)imd->pr;
442 if (imd->delay_flip &&
443 pr->pixbuf != image_loader_get_pixbuf(il))
448 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
450 pixbuf_renderer_area_changed(pr, x, y, w, h);
453 static void image_load_done_cb(ImageLoader *il, gpointer data)
455 ImageWindow *imd = data;
457 if (debug) printf ("image done\n");
459 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
461 if (imd->delay_flip &&
462 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
464 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
465 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
468 image_loader_free(imd->il);
471 image_post_process(imd, TRUE);
473 image_read_ahead_start(imd);
476 static void image_load_error_cb(ImageLoader *il, gpointer data)
478 if (debug) printf ("image error\n");
480 /* even on error handle it like it was done,
481 * since we have a pixbuf with _something_ */
483 image_load_done_cb(il, data);
486 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
487 static void image_load_buffer_throttle(ImageLoader *il)
489 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
491 /* Larger image files usually have larger chunks of data per pixel...
492 * So increase the buffer read size so that the rendering chunks called
496 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
500 /* this read ahead is located here merely for the callbacks, above */
502 static gint image_read_ahead_check(ImageWindow *imd)
504 if (!imd->read_ahead_path) return FALSE;
505 if (imd->il) return FALSE;
507 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
509 image_read_ahead_cancel(imd);
513 if (imd->read_ahead_il)
515 imd->il = imd->read_ahead_il;
516 imd->read_ahead_il = NULL;
518 /* override the old signals */
519 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
520 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
521 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
523 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
524 image_load_buffer_throttle(imd->il);
527 /* do this one directly (probably should add a set func) */
528 imd->il->func_done = image_load_done_cb;
530 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
532 if (!imd->delay_flip)
534 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
537 image_read_ahead_cancel(imd);
540 else if (imd->read_ahead_pixbuf)
542 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
543 g_object_unref(imd->read_ahead_pixbuf);
544 imd->read_ahead_pixbuf = NULL;
546 image_read_ahead_cancel(imd);
548 image_post_process(imd, FALSE);
552 image_read_ahead_cancel(imd);
556 static gint image_load_begin(ImageWindow *imd, const gchar *path)
558 if (debug) printf ("image begin \n");
560 if (imd->il) return FALSE;
562 imd->completed = FALSE;
563 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
565 if (image_post_buffer_get(imd))
567 if (debug) printf("from post buffer: %s\n", imd->image_path);
571 if (image_read_ahead_check(imd))
573 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
577 if (!imd->delay_flip && image_get_pixbuf(imd))
581 pr = PIXBUF_RENDERER(imd->pr);
582 if (pr->pixbuf) g_object_unref(pr->pixbuf);
586 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
588 imd->il = image_loader_new(path);
590 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
591 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
592 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
594 if (!image_loader_start(imd->il, image_load_done_cb, imd))
596 if (debug) printf("image start error\n");
598 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
600 image_loader_free(imd->il);
603 image_complete_util(imd, FALSE);
608 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
609 image_load_buffer_throttle(imd->il);
612 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
617 static void image_reset(ImageWindow *imd)
619 /* stops anything currently being done */
621 if (debug) printf("image reset\n");
623 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
625 image_loader_free(imd->il);
628 imd->delay_alter_type = ALTER_NONE;
632 *-------------------------------------------------------------------
634 *-------------------------------------------------------------------
637 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
641 if (imd->image_path && isfile(imd->image_path))
645 pr = PIXBUF_RENDERER(imd->pr);
646 pr->zoom = zoom; /* store the zoom, needed by the loader */
648 if (image_load_begin(imd, imd->image_path))
650 imd->unknown = FALSE;
656 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
657 image_change_pixbuf(imd, pixbuf, zoom);
658 g_object_unref(pixbuf);
662 imd->size = filesize(imd->image_path);
663 imd->mtime = filetime(imd->image_path);
671 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
672 image_change_pixbuf(imd, pixbuf, zoom);
673 g_object_unref(pixbuf);
674 imd->mtime = filetime(imd->image_path);
678 image_change_pixbuf(imd, NULL, zoom);
685 image_update_util(imd);
688 static void image_change_real(ImageWindow *imd, const gchar *path,
689 CollectionData *cd, CollectInfo *info, gdouble zoom)
692 GdkPixbuf *prev_pixbuf = NULL;
693 gchar *prev_path = NULL;
694 gint prev_clear = FALSE;
696 imd->collection = cd;
697 imd->collection_info = info;
699 pixbuf = image_get_pixbuf(imd);
701 if (enable_read_ahead && imd->image_path && pixbuf)
705 /* current image is not finished */
710 prev_path = g_strdup(imd->image_path);
711 prev_pixbuf = pixbuf;
712 g_object_ref(prev_pixbuf);
716 g_free(imd->image_path);
717 imd->image_path = g_strdup(path);
718 imd->image_name = filename_from_path(imd->image_path);
720 image_change_complete(imd, zoom, TRUE);
724 image_post_buffer_set(imd, prev_path, prev_pixbuf);
726 g_object_unref(prev_pixbuf);
730 image_post_buffer_set(imd, NULL, NULL);
733 image_update_title(imd);
738 *-------------------------------------------------------------------
740 *-------------------------------------------------------------------
743 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
747 widget = imd->widget;
748 if (!widget->window) return;
752 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
753 area, widget, "image_window",
754 widget->allocation.x, widget->allocation.y,
755 widget->allocation.width - 1, widget->allocation.height - 1);
759 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
760 area, widget, "image_window",
761 widget->allocation.x, widget->allocation.y,
762 widget->allocation.width - 1, widget->allocation.height - 1);
766 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
768 ImageWindow *imd = data;
770 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
774 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
776 ImageWindow *imd = data;
778 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
779 image_focus_paint(imd, TRUE, NULL);
784 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
786 ImageWindow *imd = data;
788 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
789 image_focus_paint(imd, FALSE, NULL);
794 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
795 gint relative, gint always)
797 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
800 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
802 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
805 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
807 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
810 void image_overlay_remove(ImageWindow *imd, gint id)
812 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
815 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
817 ImageWindow *imd = data;
819 if (imd->func_scroll &&
820 event && event->type == GDK_SCROLL)
822 imd->func_scroll(imd, event->direction, event->time,
823 event->x, event->y, event->state, imd->data_scroll);
831 *-------------------------------------------------------------------
833 *-------------------------------------------------------------------
836 void image_attach_window(ImageWindow *imd, GtkWidget *window,
837 const gchar *title, const gchar *title_right, gint show_zoom)
839 imd->top_window = window;
841 imd->title = g_strdup(title);
842 g_free(imd->title_right);
843 imd->title_right = g_strdup(title_right);
844 imd->title_show_zoom = show_zoom;
846 if (!fit_window) window = NULL;
848 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
850 image_update_title(imd);
853 void image_set_update_func(ImageWindow *imd,
854 void (*func)(ImageWindow *imd, gpointer data),
857 imd->func_update = func;
858 imd->data_update = data;
861 void image_set_complete_func(ImageWindow *imd,
862 void (*func)(ImageWindow *, gint preload, gpointer),
865 imd->func_complete = func;
866 imd->data_complete = data;
869 void image_set_new_func(ImageWindow *imd,
870 void (*func)(ImageWindow *, gpointer),
873 imd->func_new = func;
874 imd->data_new = data;
878 void image_set_button_func(ImageWindow *imd,
879 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
882 imd->func_button = func;
883 imd->data_button = data;
886 void image_set_scroll_func(ImageWindow *imd,
887 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
890 imd->func_scroll = func;
891 imd->data_scroll = data;
894 void image_set_scroll_notify_func(ImageWindow *imd,
895 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
898 imd->func_scroll_notify = func;
899 imd->data_scroll_notify = data;
904 const gchar *image_get_path(ImageWindow *imd)
906 return imd->image_path;
909 const gchar *image_get_name(ImageWindow *imd)
911 return imd->image_name;
914 /* merely changes path string, does not change the image! */
915 void image_set_path(ImageWindow *imd, const gchar *newpath)
917 g_free(imd->image_path);
918 imd->image_path = g_strdup(newpath);
919 imd->image_name = filename_from_path(imd->image_path);
921 image_update_title(imd);
925 /* load a new image */
927 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
929 if (imd->image_path == path ||
930 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
932 image_change_real(imd, path, NULL, NULL, zoom);
935 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
937 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
940 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
942 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
946 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
948 if (!cd || !info || !g_list_find(cd->list, info)) return;
950 image_change_real(imd, info->path, cd, info, zoom);
953 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
955 if (collection_to_number(imd->collection) >= 0)
957 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
959 if (info) *info = imd->collection_info;
963 if (info) *info = NULL;
965 return imd->collection;
968 if (info) *info = NULL;
972 static void image_loader_sync_data(ImageLoader *il, gpointer data)
974 /* change data for the callbacks directly */
976 il->data_area_ready = data;
977 il->data_error = data;
978 il->data_done = data;
979 il->data_percent = data;
982 /* this is more like a move function
983 * it moves most data from source to imd
985 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
987 if (imd == source) return;
989 imd->unknown = source->unknown;
991 imd->collection = source->collection;
992 imd->collection_info = source->collection_info;
993 imd->size = source->size;
994 imd->mtime = source->mtime;
996 image_set_path(imd, image_get_path(source));
998 image_loader_free(imd->il);
1003 imd->il = source->il;
1006 image_loader_sync_data(imd->il, imd);
1008 imd->delay_alter_type = source->delay_alter_type;
1009 source->delay_alter_type = ALTER_NONE;
1012 image_loader_free(imd->read_ahead_il);
1013 imd->read_ahead_il = source->read_ahead_il;
1014 source->read_ahead_il = NULL;
1015 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1017 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1018 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1019 source->read_ahead_pixbuf = NULL;
1021 g_free(imd->read_ahead_path);
1022 imd->read_ahead_path = source->read_ahead_path;
1023 source->read_ahead_path = NULL;
1025 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1026 imd->prev_pixbuf = source->prev_pixbuf;
1027 source->prev_pixbuf = NULL;
1029 g_free(imd->prev_path);
1030 imd->prev_path = source->prev_path;
1031 source->prev_path = NULL;
1033 imd->completed = source->completed;
1035 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1040 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1042 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1045 void image_reload(ImageWindow *imd)
1047 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1049 image_change_complete(imd, image_zoom_get(imd), FALSE);
1052 void image_scroll(ImageWindow *imd, gint x, gint y)
1054 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1057 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1058 gdouble x_align, gdouble y_align)
1060 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1063 void image_alter(ImageWindow *imd, AlterType type)
1065 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1069 /* still loading, wait till done */
1070 imd->delay_alter_type = type;
1074 image_alter_real(imd, type, TRUE);
1077 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1079 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1082 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1084 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1087 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1089 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1092 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1094 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1097 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1103 pr = (PixbufRenderer *)imd->pr;
1105 if (!pixbuf_renderer_get_pixbuf(pr) ||
1106 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1110 zoom = (gdouble)pr->window_height / height;
1114 zoom = (gdouble)pr->window_width / width;
1119 zoom = 0.0 - 1.0 / zoom;
1122 pixbuf_renderer_zoom_set(pr, zoom);
1125 gdouble image_zoom_get(ImageWindow *imd)
1127 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1130 gdouble image_zoom_get_real(ImageWindow *imd)
1132 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1135 gchar *image_zoom_get_as_text(ImageWindow *imd)
1143 gchar *approx = " ";
1145 zoom = image_zoom_get(imd);
1146 scale = image_zoom_get_real(imd);
1152 else if (zoom < 0.0)
1156 else if (zoom == 0.0 && scale != 0.0)
1169 if (rint(l) != l) pl = 1;
1170 if (rint(r) != r) pr = 1;
1172 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1175 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1179 if (mode == ZOOM_RESET_ORIGINAL)
1183 else if (mode == ZOOM_RESET_FIT_WINDOW)
1191 zoom = image_zoom_get(imd);
1204 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1206 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1210 image_read_ahead_set(imd, path);
1214 image_read_ahead_cancel(imd);
1218 static gint image_auto_refresh_cb(gpointer data)
1220 ImageWindow *imd = data;
1223 if (!imd || !image_get_pixbuf(imd) ||
1224 imd->il || !imd->image_path ||
1225 !update_on_time_change) return TRUE;
1227 newtime = filetime(imd->image_path);
1228 if (newtime > 0 && newtime != imd->mtime)
1230 imd->mtime = newtime;
1237 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1239 void image_auto_refresh(ImageWindow *imd, gint interval)
1242 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1244 if (imd->auto_refresh_id > -1)
1246 g_source_remove(imd->auto_refresh_id);
1247 imd->auto_refresh_id = -1;
1248 imd->auto_refresh_interval = -1;
1251 if (interval < 0) return;
1253 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1255 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1256 imd->auto_refresh_interval = interval;
1259 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1261 imd->top_window_sync = allow_sync;
1263 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1266 void image_background_set_black(ImageWindow *imd, gint black)
1268 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1271 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1273 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1276 void image_set_delay_flip(ImageWindow *imd, gint delay)
1279 imd->delay_flip == delay) return;
1281 imd->delay_flip = delay;
1283 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1285 if (!imd->delay_flip && imd->il)
1289 pr = PIXBUF_RENDERER(imd->pr);
1290 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1293 image_load_pixbuf_ready(imd);
1297 void image_to_root_window(ImageWindow *imd, gint scaled)
1300 GdkWindow *rootwindow;
1308 pixbuf = image_get_pixbuf(imd);
1309 if (!pixbuf) return;
1311 screen = gtk_widget_get_screen(imd->widget);
1312 rootwindow = gdk_screen_get_root_window(screen);
1313 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1317 width = gdk_screen_width();
1318 height = gdk_screen_height();
1322 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1325 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1327 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1328 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1329 gdk_window_clear(rootwindow);
1331 g_object_unref(pixmap);
1337 *-------------------------------------------------------------------
1339 *-------------------------------------------------------------------
1342 static void image_options_set(ImageWindow *imd)
1344 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1345 "zoom_2pass", two_pass_zoom,
1346 "zoom_expand", zoom_to_fit_expands,
1347 "dither_quality", dither_quality,
1348 "scroll_reset", scroll_reset_method,
1349 "cache_display", tile_cache_max,
1350 "window_fit", (imd->top_window_sync && fit_window),
1351 "window_limit", limit_window_size,
1352 "window_limit_value", max_window_size,
1355 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1358 void image_options_sync(void)
1370 image_options_set(imd);
1375 *-------------------------------------------------------------------
1377 *-------------------------------------------------------------------
1380 static void image_free(ImageWindow *imd)
1382 image_list = g_list_remove(image_list, imd);
1386 image_read_ahead_cancel(imd);
1387 image_post_buffer_set(imd, NULL, NULL);
1388 image_auto_refresh(imd, -1);
1390 g_free(imd->image_path);
1392 g_free(imd->title_right);
1397 static void image_destroy_cb(GtkObject *widget, gpointer data)
1399 ImageWindow *imd = data;
1403 ImageWindow *image_new(gint frame)
1407 imd = g_new0(ImageWindow, 1);
1409 imd->top_window = NULL;
1411 imd->title_right = NULL;
1412 imd->title_show_zoom = FALSE;
1414 imd->unknown = TRUE;
1416 imd->has_frame = frame;
1417 imd->top_window_sync = FALSE;
1419 imd->delay_alter_type = ALTER_NONE;
1421 imd->read_ahead_il = NULL;
1422 imd->read_ahead_pixbuf = NULL;
1423 imd->read_ahead_path = NULL;
1425 imd->completed = FALSE;
1427 imd->auto_refresh_id = -1;
1428 imd->auto_refresh_interval = -1;
1430 imd->delay_flip = FALSE;
1432 imd->func_update = NULL;
1433 imd->func_complete = NULL;
1434 imd->func_tile_request = NULL;
1435 imd->func_tile_dispose = NULL;
1437 imd->func_button = NULL;
1438 imd->func_scroll = NULL;
1440 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1442 image_options_set(imd);
1446 imd->widget = gtk_frame_new(NULL);
1447 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1448 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1449 gtk_widget_show(imd->pr);
1451 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1452 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1453 G_CALLBACK(image_focus_in_cb), imd);
1454 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1455 G_CALLBACK(image_focus_out_cb), imd);
1457 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1458 G_CALLBACK(image_focus_expose), imd);
1462 imd->widget = imd->pr;
1465 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1466 G_CALLBACK(image_click_cb), imd);
1467 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1468 G_CALLBACK(image_scroll_notify_cb), imd);
1470 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1471 G_CALLBACK(image_scroll_cb), imd);
1473 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1474 G_CALLBACK(image_destroy_cb), imd);
1476 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1477 G_CALLBACK(image_zoom_cb), imd);
1478 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1479 G_CALLBACK(image_render_complete_cb), imd);
1481 image_list = g_list_append(image_list, imd);