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);
209 case ALTER_DESATURATE:
210 pixbuf_desaturate_rect(pr->pixbuf,
211 0, 0, pr->image_width, pr->image_height);
212 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
222 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
225 if (clamp && pr->zoom != 0.0)
227 pixbuf_renderer_scroll(pr, x - (pr->vis_width / 2), y - (pr->vis_height / 2));
231 static void image_post_process(ImageWindow *imd, gint clamp)
233 if (exif_rotate_enable && image_get_pixbuf(imd))
238 ed = exif_read(imd->image_path);
239 if (ed && exif_get_integer(ed, "Orientation", &orientation))
241 /* see http://jpegclub.org/exif_orientation.html
244 888888 888888 88 88 8888888888 88 88 8888888888
245 88 88 88 88 88 88 88 88 88 88 88 88
246 8888 8888 8888 8888 88 8888888888 8888888888 88
253 case EXIF_ORIENTATION_TOP_LEFT:
254 /* normal -- nothing to do */
256 case EXIF_ORIENTATION_TOP_RIGHT:
258 imd->delay_alter_type = ALTER_MIRROR;
260 case EXIF_ORIENTATION_BOTTOM_RIGHT:
262 imd->delay_alter_type = ALTER_ROTATE_180;
264 case EXIF_ORIENTATION_BOTTOM_LEFT:
266 imd->delay_alter_type = ALTER_FLIP;
268 case EXIF_ORIENTATION_LEFT_TOP:
269 /* not implemented -- too wacky to fix in one step */
271 case EXIF_ORIENTATION_RIGHT_TOP:
272 /* rotated -90 (270) */
273 imd->delay_alter_type = ALTER_ROTATE_90;
275 case EXIF_ORIENTATION_RIGHT_BOTTOM:
276 /* not implemented -- too wacky to fix in one step */
278 case EXIF_ORIENTATION_LEFT_BOTTOM:
280 imd->delay_alter_type = ALTER_ROTATE_90_CC;
283 /* The other values are out of range */
290 if (imd->delay_alter_type != ALTER_NONE)
292 image_alter_real(imd, imd->delay_alter_type, clamp);
297 *-------------------------------------------------------------------
298 * read ahead (prebuffer)
299 *-------------------------------------------------------------------
302 static void image_read_ahead_cancel(ImageWindow *imd)
304 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
306 image_loader_free(imd->read_ahead_il);
307 imd->read_ahead_il = NULL;
309 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
310 imd->read_ahead_pixbuf = NULL;
312 g_free(imd->read_ahead_path);
313 imd->read_ahead_path = NULL;
316 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
318 ImageWindow *imd = data;
320 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
322 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
323 if (imd->read_ahead_pixbuf)
325 g_object_ref(imd->read_ahead_pixbuf);
329 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
331 image_loader_free(imd->read_ahead_il);
332 imd->read_ahead_il = NULL;
334 image_complete_util(imd, TRUE);
337 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
339 /* we even treat errors as success, maybe at least some of the file was ok */
340 image_read_ahead_done_cb(il, data);
343 static void image_read_ahead_start(ImageWindow *imd)
345 /* already started ? */
346 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
348 /* still loading ?, do later */
351 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
353 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
355 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
356 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
358 image_read_ahead_cancel(imd);
359 image_complete_util(imd, TRUE);
363 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
365 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
367 image_read_ahead_cancel(imd);
369 imd->read_ahead_path = g_strdup(path);
371 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
373 image_read_ahead_start(imd);
377 *-------------------------------------------------------------------
379 *-------------------------------------------------------------------
382 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
384 g_free(imd->prev_path);
385 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
389 imd->prev_path = g_strdup(path);
391 g_object_ref(pixbuf);
392 imd->prev_pixbuf = pixbuf;
396 imd->prev_path = NULL;
397 imd->prev_pixbuf = NULL;
400 if (debug) printf("post buffer set: %s\n", path);
403 static gint image_post_buffer_get(ImageWindow *imd)
407 if (imd->prev_pixbuf &&
408 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
410 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
418 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
419 imd->prev_pixbuf = NULL;
421 g_free(imd->prev_path);
422 imd->prev_path = NULL;
428 *-------------------------------------------------------------------
430 *-------------------------------------------------------------------
433 static void image_load_pixbuf_ready(ImageWindow *imd)
435 if (image_get_pixbuf(imd) || !imd->il) return;
437 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
440 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
442 ImageWindow *imd = data;
445 pr = (PixbufRenderer *)imd->pr;
447 if (imd->delay_flip &&
448 pr->pixbuf != image_loader_get_pixbuf(il))
453 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
455 pixbuf_renderer_area_changed(pr, x, y, w, h);
458 static void image_load_done_cb(ImageLoader *il, gpointer data)
460 ImageWindow *imd = data;
462 if (debug) printf ("image done\n");
464 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
466 if (imd->delay_flip &&
467 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
469 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
470 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
473 image_loader_free(imd->il);
476 image_post_process(imd, TRUE);
478 image_read_ahead_start(imd);
481 static void image_load_error_cb(ImageLoader *il, gpointer data)
483 if (debug) printf ("image error\n");
485 /* even on error handle it like it was done,
486 * since we have a pixbuf with _something_ */
488 image_load_done_cb(il, data);
491 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
492 static void image_load_buffer_throttle(ImageLoader *il)
494 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
496 /* Larger image files usually have larger chunks of data per pixel...
497 * So increase the buffer read size so that the rendering chunks called
501 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
505 /* this read ahead is located here merely for the callbacks, above */
507 static gint image_read_ahead_check(ImageWindow *imd)
509 if (!imd->read_ahead_path) return FALSE;
510 if (imd->il) return FALSE;
512 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
514 image_read_ahead_cancel(imd);
518 if (imd->read_ahead_il)
520 imd->il = imd->read_ahead_il;
521 imd->read_ahead_il = NULL;
523 /* override the old signals */
524 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
525 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
526 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
528 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
529 image_load_buffer_throttle(imd->il);
532 /* do this one directly (probably should add a set func) */
533 imd->il->func_done = image_load_done_cb;
535 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
537 if (!imd->delay_flip)
539 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
542 image_read_ahead_cancel(imd);
545 else if (imd->read_ahead_pixbuf)
547 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
548 g_object_unref(imd->read_ahead_pixbuf);
549 imd->read_ahead_pixbuf = NULL;
551 image_read_ahead_cancel(imd);
553 image_post_process(imd, FALSE);
557 image_read_ahead_cancel(imd);
561 static gint image_load_begin(ImageWindow *imd, const gchar *path)
563 if (debug) printf ("image begin \n");
565 if (imd->il) return FALSE;
567 imd->completed = FALSE;
568 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
570 if (image_post_buffer_get(imd))
572 if (debug) printf("from post buffer: %s\n", imd->image_path);
576 if (image_read_ahead_check(imd))
578 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
582 if (!imd->delay_flip && image_get_pixbuf(imd))
586 pr = PIXBUF_RENDERER(imd->pr);
587 if (pr->pixbuf) g_object_unref(pr->pixbuf);
591 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
593 imd->il = image_loader_new(path);
595 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
596 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
597 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
599 if (!image_loader_start(imd->il, image_load_done_cb, imd))
601 if (debug) printf("image start error\n");
603 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
605 image_loader_free(imd->il);
608 image_complete_util(imd, FALSE);
613 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
614 image_load_buffer_throttle(imd->il);
617 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
622 static void image_reset(ImageWindow *imd)
624 /* stops anything currently being done */
626 if (debug) printf("image reset\n");
628 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
630 image_loader_free(imd->il);
633 imd->delay_alter_type = ALTER_NONE;
637 *-------------------------------------------------------------------
639 *-------------------------------------------------------------------
642 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
646 if (imd->image_path && isfile(imd->image_path))
650 pr = PIXBUF_RENDERER(imd->pr);
651 pr->zoom = zoom; /* store the zoom, needed by the loader */
653 if (image_load_begin(imd, imd->image_path))
655 imd->unknown = FALSE;
661 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
662 image_change_pixbuf(imd, pixbuf, zoom);
663 g_object_unref(pixbuf);
667 imd->size = filesize(imd->image_path);
668 imd->mtime = filetime(imd->image_path);
676 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
677 image_change_pixbuf(imd, pixbuf, zoom);
678 g_object_unref(pixbuf);
679 imd->mtime = filetime(imd->image_path);
683 image_change_pixbuf(imd, NULL, zoom);
690 image_update_util(imd);
693 static void image_change_real(ImageWindow *imd, const gchar *path,
694 CollectionData *cd, CollectInfo *info, gdouble zoom)
697 GdkPixbuf *prev_pixbuf = NULL;
698 gchar *prev_path = NULL;
699 gint prev_clear = FALSE;
701 imd->collection = cd;
702 imd->collection_info = info;
704 pixbuf = image_get_pixbuf(imd);
706 if (enable_read_ahead && imd->image_path && pixbuf)
710 /* current image is not finished */
715 prev_path = g_strdup(imd->image_path);
716 prev_pixbuf = pixbuf;
717 g_object_ref(prev_pixbuf);
721 g_free(imd->image_path);
722 imd->image_path = g_strdup(path);
723 imd->image_name = filename_from_path(imd->image_path);
725 image_change_complete(imd, zoom, TRUE);
729 image_post_buffer_set(imd, prev_path, prev_pixbuf);
731 g_object_unref(prev_pixbuf);
735 image_post_buffer_set(imd, NULL, NULL);
738 image_update_title(imd);
743 *-------------------------------------------------------------------
745 *-------------------------------------------------------------------
748 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
752 widget = imd->widget;
753 if (!widget->window) return;
757 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
758 area, widget, "image_window",
759 widget->allocation.x, widget->allocation.y,
760 widget->allocation.width - 1, widget->allocation.height - 1);
764 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
765 area, widget, "image_window",
766 widget->allocation.x, widget->allocation.y,
767 widget->allocation.width - 1, widget->allocation.height - 1);
771 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
773 ImageWindow *imd = data;
775 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
779 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
781 ImageWindow *imd = data;
783 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
784 image_focus_paint(imd, TRUE, NULL);
789 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
791 ImageWindow *imd = data;
793 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
794 image_focus_paint(imd, FALSE, NULL);
799 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
800 gint relative, gint always)
802 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
805 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
807 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
810 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
812 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
815 void image_overlay_remove(ImageWindow *imd, gint id)
817 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
820 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
822 ImageWindow *imd = data;
824 if (imd->func_scroll &&
825 event && event->type == GDK_SCROLL)
827 imd->func_scroll(imd, event->direction, event->time,
828 event->x, event->y, event->state, imd->data_scroll);
836 *-------------------------------------------------------------------
838 *-------------------------------------------------------------------
841 void image_attach_window(ImageWindow *imd, GtkWidget *window,
842 const gchar *title, const gchar *title_right, gint show_zoom)
844 imd->top_window = window;
846 imd->title = g_strdup(title);
847 g_free(imd->title_right);
848 imd->title_right = g_strdup(title_right);
849 imd->title_show_zoom = show_zoom;
851 if (!fit_window) window = NULL;
853 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
855 image_update_title(imd);
858 void image_set_update_func(ImageWindow *imd,
859 void (*func)(ImageWindow *imd, gpointer data),
862 imd->func_update = func;
863 imd->data_update = data;
866 void image_set_complete_func(ImageWindow *imd,
867 void (*func)(ImageWindow *, gint preload, gpointer),
870 imd->func_complete = func;
871 imd->data_complete = data;
874 void image_set_new_func(ImageWindow *imd,
875 void (*func)(ImageWindow *, gpointer),
878 imd->func_new = func;
879 imd->data_new = data;
883 void image_set_button_func(ImageWindow *imd,
884 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
887 imd->func_button = func;
888 imd->data_button = data;
891 void image_set_scroll_func(ImageWindow *imd,
892 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
895 imd->func_scroll = func;
896 imd->data_scroll = data;
899 void image_set_scroll_notify_func(ImageWindow *imd,
900 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
903 imd->func_scroll_notify = func;
904 imd->data_scroll_notify = data;
909 const gchar *image_get_path(ImageWindow *imd)
911 return imd->image_path;
914 const gchar *image_get_name(ImageWindow *imd)
916 return imd->image_name;
919 /* merely changes path string, does not change the image! */
920 void image_set_path(ImageWindow *imd, const gchar *newpath)
922 g_free(imd->image_path);
923 imd->image_path = g_strdup(newpath);
924 imd->image_name = filename_from_path(imd->image_path);
926 image_update_title(imd);
930 /* load a new image */
932 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
934 if (imd->image_path == path ||
935 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
937 image_change_real(imd, path, NULL, NULL, zoom);
940 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
942 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
945 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
947 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
951 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
953 if (!cd || !info || !g_list_find(cd->list, info)) return;
955 image_change_real(imd, info->path, cd, info, zoom);
958 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
960 if (collection_to_number(imd->collection) >= 0)
962 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
964 if (info) *info = imd->collection_info;
968 if (info) *info = NULL;
970 return imd->collection;
973 if (info) *info = NULL;
977 static void image_loader_sync_data(ImageLoader *il, gpointer data)
979 /* change data for the callbacks directly */
981 il->data_area_ready = data;
982 il->data_error = data;
983 il->data_done = data;
984 il->data_percent = data;
987 /* this is more like a move function
988 * it moves most data from source to imd
990 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
992 if (imd == source) return;
994 imd->unknown = source->unknown;
996 imd->collection = source->collection;
997 imd->collection_info = source->collection_info;
998 imd->size = source->size;
999 imd->mtime = source->mtime;
1001 image_set_path(imd, image_get_path(source));
1003 image_loader_free(imd->il);
1008 imd->il = source->il;
1011 image_loader_sync_data(imd->il, imd);
1013 imd->delay_alter_type = source->delay_alter_type;
1014 source->delay_alter_type = ALTER_NONE;
1017 image_loader_free(imd->read_ahead_il);
1018 imd->read_ahead_il = source->read_ahead_il;
1019 source->read_ahead_il = NULL;
1020 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1022 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1023 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1024 source->read_ahead_pixbuf = NULL;
1026 g_free(imd->read_ahead_path);
1027 imd->read_ahead_path = source->read_ahead_path;
1028 source->read_ahead_path = NULL;
1030 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1031 imd->prev_pixbuf = source->prev_pixbuf;
1032 source->prev_pixbuf = NULL;
1034 g_free(imd->prev_path);
1035 imd->prev_path = source->prev_path;
1036 source->prev_path = NULL;
1038 imd->completed = source->completed;
1040 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1045 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1047 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1050 void image_reload(ImageWindow *imd)
1052 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1054 image_change_complete(imd, image_zoom_get(imd), FALSE);
1057 void image_scroll(ImageWindow *imd, gint x, gint y)
1059 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1062 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1063 gdouble x_align, gdouble y_align)
1065 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1068 void image_alter(ImageWindow *imd, AlterType type)
1070 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1074 /* still loading, wait till done */
1075 imd->delay_alter_type = type;
1079 image_alter_real(imd, type, TRUE);
1082 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1084 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1087 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1089 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1092 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1094 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1097 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1099 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1102 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1108 pr = (PixbufRenderer *)imd->pr;
1110 if (!pixbuf_renderer_get_pixbuf(pr) ||
1111 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1115 zoom = (gdouble)pr->window_height / height;
1119 zoom = (gdouble)pr->window_width / width;
1124 zoom = 0.0 - 1.0 / zoom;
1127 pixbuf_renderer_zoom_set(pr, zoom);
1130 gdouble image_zoom_get(ImageWindow *imd)
1132 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1135 gdouble image_zoom_get_real(ImageWindow *imd)
1137 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1140 gchar *image_zoom_get_as_text(ImageWindow *imd)
1148 gchar *approx = " ";
1150 zoom = image_zoom_get(imd);
1151 scale = image_zoom_get_real(imd);
1157 else if (zoom < 0.0)
1161 else if (zoom == 0.0 && scale != 0.0)
1174 if (rint(l) != l) pl = 1;
1175 if (rint(r) != r) pr = 1;
1177 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1180 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1184 if (mode == ZOOM_RESET_ORIGINAL)
1188 else if (mode == ZOOM_RESET_FIT_WINDOW)
1196 zoom = image_zoom_get(imd);
1209 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1211 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1215 image_read_ahead_set(imd, path);
1219 image_read_ahead_cancel(imd);
1223 static gint image_auto_refresh_cb(gpointer data)
1225 ImageWindow *imd = data;
1228 if (!imd || !image_get_pixbuf(imd) ||
1229 imd->il || !imd->image_path ||
1230 !update_on_time_change) return TRUE;
1232 newtime = filetime(imd->image_path);
1233 if (newtime > 0 && newtime != imd->mtime)
1235 imd->mtime = newtime;
1242 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1244 void image_auto_refresh(ImageWindow *imd, gint interval)
1247 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1249 if (imd->auto_refresh_id > -1)
1251 g_source_remove(imd->auto_refresh_id);
1252 imd->auto_refresh_id = -1;
1253 imd->auto_refresh_interval = -1;
1256 if (interval < 0) return;
1258 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1260 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1261 imd->auto_refresh_interval = interval;
1264 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1266 imd->top_window_sync = allow_sync;
1268 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1271 void image_background_set_black(ImageWindow *imd, gint black)
1273 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1276 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1278 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1281 void image_set_delay_flip(ImageWindow *imd, gint delay)
1284 imd->delay_flip == delay) return;
1286 imd->delay_flip = delay;
1288 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1290 if (!imd->delay_flip && imd->il)
1294 pr = PIXBUF_RENDERER(imd->pr);
1295 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1298 image_load_pixbuf_ready(imd);
1302 void image_to_root_window(ImageWindow *imd, gint scaled)
1305 GdkWindow *rootwindow;
1313 pixbuf = image_get_pixbuf(imd);
1314 if (!pixbuf) return;
1316 screen = gtk_widget_get_screen(imd->widget);
1317 rootwindow = gdk_screen_get_root_window(screen);
1318 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1322 width = gdk_screen_width();
1323 height = gdk_screen_height();
1327 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1330 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1332 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1333 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1334 gdk_window_clear(rootwindow);
1336 g_object_unref(pixmap);
1342 *-------------------------------------------------------------------
1344 *-------------------------------------------------------------------
1347 static void image_options_set(ImageWindow *imd)
1349 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1350 "zoom_2pass", two_pass_zoom,
1351 "zoom_expand", zoom_to_fit_expands,
1352 "dither_quality", dither_quality,
1353 "scroll_reset", scroll_reset_method,
1354 "cache_display", tile_cache_max,
1355 "window_fit", (imd->top_window_sync && fit_window),
1356 "window_limit", limit_window_size,
1357 "window_limit_value", max_window_size,
1360 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1363 void image_options_sync(void)
1375 image_options_set(imd);
1380 *-------------------------------------------------------------------
1382 *-------------------------------------------------------------------
1385 static void image_free(ImageWindow *imd)
1387 image_list = g_list_remove(image_list, imd);
1391 image_read_ahead_cancel(imd);
1392 image_post_buffer_set(imd, NULL, NULL);
1393 image_auto_refresh(imd, -1);
1395 g_free(imd->image_path);
1397 g_free(imd->title_right);
1402 static void image_destroy_cb(GtkObject *widget, gpointer data)
1404 ImageWindow *imd = data;
1408 ImageWindow *image_new(gint frame)
1412 imd = g_new0(ImageWindow, 1);
1414 imd->top_window = NULL;
1416 imd->title_right = NULL;
1417 imd->title_show_zoom = FALSE;
1419 imd->unknown = TRUE;
1421 imd->has_frame = frame;
1422 imd->top_window_sync = FALSE;
1424 imd->delay_alter_type = ALTER_NONE;
1426 imd->read_ahead_il = NULL;
1427 imd->read_ahead_pixbuf = NULL;
1428 imd->read_ahead_path = NULL;
1430 imd->completed = FALSE;
1432 imd->auto_refresh_id = -1;
1433 imd->auto_refresh_interval = -1;
1435 imd->delay_flip = FALSE;
1437 imd->func_update = NULL;
1438 imd->func_complete = NULL;
1439 imd->func_tile_request = NULL;
1440 imd->func_tile_dispose = NULL;
1442 imd->func_button = NULL;
1443 imd->func_scroll = NULL;
1445 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1447 image_options_set(imd);
1451 imd->widget = gtk_frame_new(NULL);
1452 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1453 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1454 gtk_widget_show(imd->pr);
1456 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1457 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1458 G_CALLBACK(image_focus_in_cb), imd);
1459 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1460 G_CALLBACK(image_focus_out_cb), imd);
1462 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1463 G_CALLBACK(image_focus_expose), imd);
1467 imd->widget = imd->pr;
1470 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1471 G_CALLBACK(image_click_cb), imd);
1472 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1473 G_CALLBACK(image_scroll_notify_cb), imd);
1475 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1476 G_CALLBACK(image_scroll_cb), imd);
1478 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1479 G_CALLBACK(image_destroy_cb), imd);
1481 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1482 G_CALLBACK(image_zoom_cb), imd);
1483 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1484 G_CALLBACK(image_render_complete_cb), imd);
1486 image_list = g_list_append(image_list, imd);