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
43 *-------------------------------------------------------------------
45 *-------------------------------------------------------------------
48 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
50 ImageWindow *imd = data;
54 imd->func_button(imd, event->button, event->time,
55 event->x, event->y, event->state, imd->data_button);
59 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
61 ImageWindow *imd = data;
63 if (imd->func_scroll_notify && pr->scale)
65 imd->func_scroll_notify(imd,
66 (gint)((gdouble)pr->x_scroll / pr->scale),
67 (gint)((gdouble)pr->y_scroll / pr->scale),
68 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
69 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
70 imd->data_scroll_notify);
74 static void image_update_util(ImageWindow *imd)
76 if (imd->func_update) imd->func_update(imd, imd->data_update);
79 static void image_complete_util(ImageWindow *imd, gint preload)
81 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
83 if (debug) printf("image load completed \"%s\" (%s)\n",
84 (preload) ? imd->read_ahead_path : imd->image_path,
85 (preload) ? "preload" : "current");
87 if (!preload) imd->completed = TRUE;
88 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
91 static void image_new_util(ImageWindow *imd)
93 if (imd->func_new) imd->func_new(imd, imd->data_new);
97 *-------------------------------------------------------------------
99 *-------------------------------------------------------------------
102 static void image_update_title(ImageWindow *imd)
106 gchar *collection = NULL;
108 if (!imd->top_window) return;
110 if (imd->collection && collection_to_number(imd->collection) >= 0)
113 name = imd->collection->name;
114 if (!name) name = _("Untitled");
115 collection = g_strdup_printf(" (Collection %s)", name);
118 if (imd->title_show_zoom)
120 gchar *buf = image_zoom_get_as_text(imd);
121 zoom = g_strconcat(" [", buf, "]", NULL);
125 title = g_strdup_printf("%s%s%s%s%s%s",
126 imd->title ? imd->title : "",
127 imd->image_name ? imd->image_name : "",
129 collection ? collection : "",
130 imd->image_name ? " - " : "",
131 imd->title_right ? imd->title_right : "");
133 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
141 *-------------------------------------------------------------------
142 * rotation, flip, etc.
143 *-------------------------------------------------------------------
146 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
149 GdkPixbuf *new = NULL;
153 pr = (PixbufRenderer *)imd->pr;
155 imd->delay_alter_type = ALTER_NONE;
157 if (!pr->pixbuf) return;
159 x = pr->x_scroll + (pr->vis_width / 2);
160 y = pr->y_scroll + (pr->vis_height / 2);
164 case ALTER_ROTATE_90:
165 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
170 case ALTER_ROTATE_90_CC:
171 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
176 case ALTER_ROTATE_180:
177 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
182 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
186 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
197 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
200 if (clamp && pr->zoom != 0.0)
202 pixbuf_renderer_scroll(pr, x - (pr->vis_width / 2), y - (pr->vis_height / 2));
206 static void image_post_process(ImageWindow *imd, gint clamp)
208 if (exif_rotate_enable && image_get_pixbuf(imd))
213 ed = exif_read(imd->image_path);
214 if (ed && exif_get_integer(ed, "Orientation", &orientation))
216 /* see http://jpegclub.org/exif_orientation.html
219 888888 888888 88 88 8888888888 88 88 8888888888
220 88 88 88 88 88 88 88 88 88 88 88 88
221 8888 8888 8888 8888 88 8888888888 8888888888 88
228 case EXIF_ORIENTATION_TOP_LEFT:
229 /* normal -- nothing to do */
231 case EXIF_ORIENTATION_TOP_RIGHT:
233 imd->delay_alter_type = ALTER_MIRROR;
235 case EXIF_ORIENTATION_BOTTOM_RIGHT:
237 imd->delay_alter_type = ALTER_ROTATE_180;
239 case EXIF_ORIENTATION_BOTTOM_LEFT:
241 imd->delay_alter_type = ALTER_FLIP;
243 case EXIF_ORIENTATION_LEFT_TOP:
244 /* not implemented -- too wacky to fix in one step */
246 case EXIF_ORIENTATION_RIGHT_TOP:
247 /* rotated -90 (270) */
248 imd->delay_alter_type = ALTER_ROTATE_90;
250 case EXIF_ORIENTATION_RIGHT_BOTTOM:
251 /* not implemented -- too wacky to fix in one step */
253 case EXIF_ORIENTATION_LEFT_BOTTOM:
255 imd->delay_alter_type = ALTER_ROTATE_90_CC;
258 /* The other values are out of range */
265 if (imd->delay_alter_type != ALTER_NONE)
267 image_alter_real(imd, imd->delay_alter_type, clamp);
272 *-------------------------------------------------------------------
273 * read ahead (prebuffer)
274 *-------------------------------------------------------------------
277 static void image_read_ahead_cancel(ImageWindow *imd)
279 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
281 image_loader_free(imd->read_ahead_il);
282 imd->read_ahead_il = NULL;
284 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
285 imd->read_ahead_pixbuf = NULL;
287 g_free(imd->read_ahead_path);
288 imd->read_ahead_path = NULL;
291 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
293 ImageWindow *imd = data;
295 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
297 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
298 if (imd->read_ahead_pixbuf)
300 g_object_ref(imd->read_ahead_pixbuf);
304 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
306 image_loader_free(imd->read_ahead_il);
307 imd->read_ahead_il = NULL;
309 image_complete_util(imd, TRUE);
312 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
314 /* we even treat errors as success, maybe at least some of the file was ok */
315 image_read_ahead_done_cb(il, data);
318 static void image_read_ahead_start(ImageWindow *imd)
320 /* already started ? */
321 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
323 /* still loading ?, do later */
326 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
328 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
330 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
331 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
333 image_read_ahead_cancel(imd);
334 image_complete_util(imd, TRUE);
338 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
340 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
342 image_read_ahead_cancel(imd);
344 imd->read_ahead_path = g_strdup(path);
346 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
348 image_read_ahead_start(imd);
352 *-------------------------------------------------------------------
354 *-------------------------------------------------------------------
357 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
359 g_free(imd->prev_path);
360 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
364 imd->prev_path = g_strdup(path);
366 g_object_ref(pixbuf);
367 imd->prev_pixbuf = pixbuf;
371 imd->prev_path = NULL;
372 imd->prev_pixbuf = NULL;
375 if (debug) printf("post buffer set: %s\n", path);
378 static gint image_post_buffer_get(ImageWindow *imd)
382 if (imd->prev_pixbuf &&
383 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
385 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
393 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
394 imd->prev_pixbuf = NULL;
396 g_free(imd->prev_path);
397 imd->prev_path = NULL;
403 *-------------------------------------------------------------------
405 *-------------------------------------------------------------------
408 static void image_load_pixbuf_ready(ImageWindow *imd)
410 if (image_get_pixbuf(imd) || !imd->il) return;
412 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
415 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
417 ImageWindow *imd = data;
420 pr = (PixbufRenderer *)imd->pr;
422 if (imd->delay_flip &&
423 pr->pixbuf != image_loader_get_pixbuf(il))
428 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
430 pixbuf_renderer_area_changed(pr, x, y, w, h);
433 static void image_load_done_cb(ImageLoader *il, gpointer data)
435 ImageWindow *imd = data;
437 if (debug) printf ("image done\n");
439 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
441 if (imd->delay_flip &&
442 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
444 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
447 image_loader_free(imd->il);
450 image_post_process(imd, TRUE);
452 image_read_ahead_start(imd);
455 static void image_load_error_cb(ImageLoader *il, gpointer data)
457 if (debug) printf ("image error\n");
459 /* even on error handle it like it was done,
460 * since we have a pixbuf with _something_ */
462 image_load_done_cb(il, data);
465 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
466 static void image_load_buffer_throttle(ImageLoader *il)
468 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
470 /* Larger image files usually have larger chunks of data per pixel...
471 * So increase the buffer read size so that the rendering chunks called
475 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
479 /* this read ahead is located here merely for the callbacks, above */
481 static gint image_read_ahead_check(ImageWindow *imd)
483 if (!imd->read_ahead_path) return FALSE;
484 if (imd->il) return FALSE;
486 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
488 image_read_ahead_cancel(imd);
492 if (imd->read_ahead_il)
494 imd->il = imd->read_ahead_il;
495 imd->read_ahead_il = NULL;
497 /* override the old signals */
498 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
499 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
500 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
502 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
503 image_load_buffer_throttle(imd->il);
506 /* do this one directly (probably should add a set func) */
507 imd->il->func_done = image_load_done_cb;
509 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
511 if (!imd->delay_flip)
513 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
516 image_read_ahead_cancel(imd);
519 else if (imd->read_ahead_pixbuf)
521 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
522 g_object_unref(imd->read_ahead_pixbuf);
523 imd->read_ahead_pixbuf = NULL;
525 image_read_ahead_cancel(imd);
527 image_post_process(imd, FALSE);
531 image_read_ahead_cancel(imd);
535 static gint image_load_begin(ImageWindow *imd, const gchar *path)
537 if (debug) printf ("image begin \n");
539 if (imd->il) return FALSE;
541 imd->completed = FALSE;
543 if (image_post_buffer_get(imd))
545 if (debug) printf("from post buffer: %s\n", imd->image_path);
549 if (image_read_ahead_check(imd))
551 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
555 if (!imd->delay_flip && image_get_pixbuf(imd))
559 pr = PIXBUF_RENDERER(imd->pr);
560 if (pr->pixbuf) g_object_unref(pr->pixbuf);
564 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
566 imd->il = image_loader_new(path);
568 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
569 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
570 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
572 if (!image_loader_start(imd->il, image_load_done_cb, imd))
574 if (debug) printf("image start error\n");
576 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
578 image_loader_free(imd->il);
581 image_complete_util(imd, FALSE);
586 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
587 image_load_buffer_throttle(imd->il);
590 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
595 static void image_reset(ImageWindow *imd)
597 /* stops anything currently being done */
599 if (debug) printf("image reset\n");
601 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
603 image_loader_free(imd->il);
606 imd->delay_alter_type = ALTER_NONE;
610 *-------------------------------------------------------------------
612 *-------------------------------------------------------------------
615 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
619 if (imd->image_path && isfile(imd->image_path))
623 pr = PIXBUF_RENDERER(imd->pr);
624 pr->zoom = zoom; /* store the zoom, needed by the loader */
626 if (image_load_begin(imd, imd->image_path))
628 imd->unknown = FALSE;
634 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
635 image_change_pixbuf(imd, pixbuf, zoom);
636 g_object_unref(pixbuf);
640 imd->size = filesize(imd->image_path);
641 imd->mtime = filetime(imd->image_path);
649 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
650 image_change_pixbuf(imd, pixbuf, zoom);
651 g_object_unref(pixbuf);
652 imd->mtime = filetime(imd->image_path);
656 image_change_pixbuf(imd, NULL, zoom);
663 image_update_util(imd);
666 static void image_change_real(ImageWindow *imd, const gchar *path,
667 CollectionData *cd, CollectInfo *info, gdouble zoom)
670 GdkPixbuf *prev_pixbuf = NULL;
671 gchar *prev_path = NULL;
672 gint prev_clear = FALSE;
674 imd->collection = cd;
675 imd->collection_info = info;
677 pixbuf = image_get_pixbuf(imd);
679 if (enable_read_ahead && imd->image_path && pixbuf)
683 /* current image is not finished */
688 prev_path = g_strdup(imd->image_path);
689 prev_pixbuf = pixbuf;
690 g_object_ref(prev_pixbuf);
694 g_free(imd->image_path);
695 imd->image_path = g_strdup(path);
696 imd->image_name = filename_from_path(imd->image_path);
698 image_change_complete(imd, zoom, TRUE);
702 image_post_buffer_set(imd, prev_path, prev_pixbuf);
704 g_object_unref(prev_pixbuf);
708 image_post_buffer_set(imd, NULL, NULL);
711 image_update_title(imd);
716 *-------------------------------------------------------------------
718 *-------------------------------------------------------------------
721 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
725 widget = imd->widget;
726 if (!widget->window) return;
730 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
731 area, widget, "image_window",
732 widget->allocation.x, widget->allocation.y,
733 widget->allocation.width - 1, widget->allocation.height - 1);
737 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
738 area, widget, "image_window",
739 widget->allocation.x, widget->allocation.y,
740 widget->allocation.width - 1, widget->allocation.height - 1);
744 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
746 ImageWindow *imd = data;
748 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
752 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
754 ImageWindow *imd = data;
756 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
757 image_focus_paint(imd, TRUE, NULL);
762 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
764 ImageWindow *imd = data;
766 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
767 image_focus_paint(imd, FALSE, NULL);
772 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
773 gint relative, gint always)
775 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
778 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
780 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
783 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
785 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
788 void image_overlay_remove(ImageWindow *imd, gint id)
790 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
793 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
795 ImageWindow *imd = data;
797 if (imd->func_scroll &&
798 event && event->type == GDK_SCROLL)
800 imd->func_scroll(imd, event->direction, event->time,
801 event->x, event->y, event->state, imd->data_scroll);
809 *-------------------------------------------------------------------
811 *-------------------------------------------------------------------
814 void image_attach_window(ImageWindow *imd, GtkWidget *window,
815 const gchar *title, const gchar *title_right, gint show_zoom)
817 imd->top_window = window;
819 imd->title = g_strdup(title);
820 g_free(imd->title_right);
821 imd->title_right = g_strdup(title_right);
822 imd->title_show_zoom = show_zoom;
824 if (!fit_window) window = NULL;
826 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
828 image_update_title(imd);
831 void image_set_update_func(ImageWindow *imd,
832 void (*func)(ImageWindow *imd, gpointer data),
835 imd->func_update = func;
836 imd->data_update = data;
839 void image_set_complete_func(ImageWindow *imd,
840 void (*func)(ImageWindow *, gint preload, gpointer),
843 imd->func_complete = func;
844 imd->data_complete = data;
847 void image_set_new_func(ImageWindow *imd,
848 void (*func)(ImageWindow *, gpointer),
851 imd->func_new = func;
852 imd->data_new = data;
856 void image_set_button_func(ImageWindow *imd,
857 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
860 imd->func_button = func;
861 imd->data_button = data;
864 void image_set_scroll_func(ImageWindow *imd,
865 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
868 imd->func_scroll = func;
869 imd->data_scroll = data;
872 void image_set_scroll_notify_func(ImageWindow *imd,
873 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
876 imd->func_scroll_notify = func;
877 imd->data_scroll_notify = data;
882 const gchar *image_get_path(ImageWindow *imd)
884 return imd->image_path;
887 const gchar *image_get_name(ImageWindow *imd)
889 return imd->image_name;
892 /* merely changes path string, does not change the image! */
893 void image_set_path(ImageWindow *imd, const gchar *newpath)
895 g_free(imd->image_path);
896 imd->image_path = g_strdup(newpath);
897 imd->image_name = filename_from_path(imd->image_path);
899 image_update_title(imd);
903 /* load a new image */
905 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
907 if (imd->image_path == path ||
908 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
910 image_change_real(imd, path, NULL, NULL, zoom);
913 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
915 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
918 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
920 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
924 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
926 if (!cd || !info || !g_list_find(cd->list, info)) return;
928 image_change_real(imd, info->path, cd, info, zoom);
931 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
933 if (collection_to_number(imd->collection) >= 0)
935 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
937 if (info) *info = imd->collection_info;
941 if (info) *info = NULL;
943 return imd->collection;
946 if (info) *info = NULL;
950 static void image_loader_sync_data(ImageLoader *il, gpointer data)
952 /* change data for the callbacks directly */
954 il->data_area_ready = data;
955 il->data_error = data;
956 il->data_done = data;
957 il->data_percent = data;
960 /* this is more like a move function
961 * it moves most data from source to imd
963 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
965 if (imd == source) return;
967 imd->unknown = source->unknown;
969 imd->collection = source->collection;
970 imd->collection_info = source->collection_info;
971 imd->size = source->size;
972 imd->mtime = source->mtime;
974 image_set_path(imd, image_get_path(source));
976 image_loader_free(imd->il);
981 imd->il = source->il;
984 image_loader_sync_data(imd->il, imd);
986 imd->delay_alter_type = source->delay_alter_type;
987 source->delay_alter_type = ALTER_NONE;
990 image_loader_free(imd->read_ahead_il);
991 imd->read_ahead_il = source->read_ahead_il;
992 source->read_ahead_il = NULL;
993 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
995 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
996 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
997 source->read_ahead_pixbuf = NULL;
999 g_free(imd->read_ahead_path);
1000 imd->read_ahead_path = source->read_ahead_path;
1001 source->read_ahead_path = NULL;
1003 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1004 imd->prev_pixbuf = source->prev_pixbuf;
1005 source->prev_pixbuf = NULL;
1007 g_free(imd->prev_path);
1008 imd->prev_path = source->prev_path;
1009 source->prev_path = NULL;
1011 imd->completed = source->completed;
1013 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1018 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1020 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1023 void image_reload(ImageWindow *imd)
1025 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1027 image_change_complete(imd, image_zoom_get(imd), FALSE);
1030 void image_scroll(ImageWindow *imd, gint x, gint y)
1032 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1035 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1036 gdouble x_align, gdouble y_align)
1038 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1041 void image_alter(ImageWindow *imd, AlterType type)
1043 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1047 /* still loading, wait till done */
1048 imd->delay_alter_type = type;
1052 image_alter_real(imd, type, TRUE);
1055 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1057 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1060 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1062 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1065 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1067 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1070 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1072 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1075 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1081 pr = (PixbufRenderer *)imd->pr;
1083 if (!pixbuf_renderer_get_pixbuf(pr) ||
1084 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1088 zoom = (gdouble)pr->window_height / height;
1092 zoom = (gdouble)pr->window_width / width;
1097 zoom = 0.0 - 1.0 / zoom;
1100 pixbuf_renderer_zoom_set(pr, zoom);
1103 gdouble image_zoom_get(ImageWindow *imd)
1105 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1108 gdouble image_zoom_get_real(ImageWindow *imd)
1110 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1113 gchar *image_zoom_get_as_text(ImageWindow *imd)
1121 gchar *approx = " ";
1123 zoom = image_zoom_get(imd);
1124 scale = image_zoom_get_real(imd);
1130 else if (zoom < 0.0)
1134 else if (zoom == 0.0 && scale != 0.0)
1147 if (rint(l) != l) pl = 1;
1148 if (rint(r) != r) pr = 1;
1150 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1153 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1157 if (mode == ZOOM_RESET_ORIGINAL)
1161 else if (mode == ZOOM_RESET_FIT_WINDOW)
1169 zoom = image_zoom_get(imd);
1182 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1184 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1188 image_read_ahead_set(imd, path);
1192 image_read_ahead_cancel(imd);
1196 static gint image_auto_refresh_cb(gpointer data)
1198 ImageWindow *imd = data;
1201 if (!imd || !image_get_pixbuf(imd) ||
1202 imd->il || !imd->image_path ||
1203 !update_on_time_change) return TRUE;
1205 newtime = filetime(imd->image_path);
1206 if (newtime > 0 && newtime != imd->mtime)
1208 imd->mtime = newtime;
1215 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1217 void image_auto_refresh(ImageWindow *imd, gint interval)
1220 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1222 if (imd->auto_refresh_id > -1)
1224 g_source_remove(imd->auto_refresh_id);
1225 imd->auto_refresh_id = -1;
1226 imd->auto_refresh_interval = -1;
1229 if (interval < 0) return;
1231 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1233 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1234 imd->auto_refresh_interval = interval;
1237 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1239 imd->top_window_sync = allow_sync;
1241 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1244 void image_background_set_black(ImageWindow *imd, gint black)
1246 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1249 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1251 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1254 void image_set_delay_flip(ImageWindow *imd, gint delay)
1257 imd->delay_flip == delay) return;
1259 imd->delay_flip = delay;
1261 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1263 if (!imd->delay_flip && imd->il)
1267 pr = PIXBUF_RENDERER(imd->pr);
1268 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1271 image_load_pixbuf_ready(imd);
1275 void image_to_root_window(ImageWindow *imd, gint scaled)
1278 GdkWindow *rootwindow;
1286 pixbuf = image_get_pixbuf(imd);
1287 if (!pixbuf) return;
1289 screen = gtk_widget_get_screen(imd->widget);
1290 rootwindow = gdk_screen_get_root_window(screen);
1291 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1295 width = gdk_screen_width();
1296 height = gdk_screen_height();
1300 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1303 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1305 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1306 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1307 gdk_window_clear(rootwindow);
1309 g_object_unref(pixmap);
1315 *-------------------------------------------------------------------
1317 *-------------------------------------------------------------------
1320 static void image_free(ImageWindow *imd)
1324 image_read_ahead_cancel(imd);
1325 image_post_buffer_set(imd, NULL, NULL);
1326 image_auto_refresh(imd, -1);
1328 g_free(imd->image_path);
1330 g_free(imd->title_right);
1335 static void image_destroy_cb(GtkObject *widget, gpointer data)
1337 ImageWindow *imd = data;
1341 ImageWindow *image_new(gint frame)
1345 imd = g_new0(ImageWindow, 1);
1347 imd->top_window = NULL;
1349 imd->title_right = NULL;
1350 imd->title_show_zoom = FALSE;
1352 imd->unknown = TRUE;
1354 imd->has_frame = frame;
1355 imd->top_window_sync = FALSE;
1357 imd->delay_alter_type = ALTER_NONE;
1359 imd->read_ahead_il = NULL;
1360 imd->read_ahead_pixbuf = NULL;
1361 imd->read_ahead_path = NULL;
1363 imd->completed = FALSE;
1365 imd->auto_refresh_id = -1;
1366 imd->auto_refresh_interval = -1;
1368 imd->delay_flip = FALSE;
1370 imd->func_update = NULL;
1371 imd->func_complete = NULL;
1372 imd->func_tile_request = NULL;
1373 imd->func_tile_dispose = NULL;
1375 imd->func_button = NULL;
1376 imd->func_scroll = NULL;
1378 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1380 g_object_set(G_OBJECT(imd->pr), "zoom_2pass", TRUE, NULL);
1384 imd->widget = gtk_frame_new(NULL);
1385 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1386 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1387 gtk_widget_show(imd->pr);
1389 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1390 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1391 G_CALLBACK(image_focus_in_cb), imd);
1392 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1393 G_CALLBACK(image_focus_out_cb), imd);
1395 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1396 G_CALLBACK(image_focus_expose), imd);
1400 imd->widget = imd->pr;
1403 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1404 G_CALLBACK(image_click_cb), imd);
1405 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1406 G_CALLBACK(image_scroll_notify_cb), imd);
1408 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1409 G_CALLBACK(image_scroll_cb), imd);
1411 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1412 G_CALLBACK(image_destroy_cb), imd);