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;
951 static void image_loader_sync_data(ImageLoader *il, gpointer data)
953 /* change data for the callbacks directly */
955 il->data_area_ready = data;
956 il->data_error = data;
957 il->data_done = data;
958 il->data_percent = data;
962 /* this is more like a move function
963 * it moves most data from source to imd, source does keep a ref on the pixbuf
965 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
967 if (imd == source) return;
969 printf("FIXME: enable set from image\n");
971 imd->zoom_min = source->zoom_min;
972 imd->zoom_max = source->zoom_max;
974 imd->unknown = source->unknown;
976 image_set_pixbuf(imd, source->pixbuf, image_zoom_get(source), TRUE);
978 imd->collection = source->collection;
979 imd->collection_info = source->collection_info;
980 imd->size = source->size;
981 imd->mtime = source->mtime;
983 image_set_path(imd, image_get_path(source));
985 image_loader_free(imd->il);
988 if (imd->pixbuf && source->il)
990 imd->il = source->il;
993 image_loader_sync_data(imd->il, imd);
995 imd->delay_alter_type = source->delay_alter_type;
996 source->delay_alter_type = ALTER_NONE;
999 image_loader_free(imd->read_ahead_il);
1000 imd->read_ahead_il = source->read_ahead_il;
1001 source->read_ahead_il = NULL;
1002 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1004 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1005 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1006 source->read_ahead_pixbuf = NULL;
1008 g_free(imd->read_ahead_path);
1009 imd->read_ahead_path = source->read_ahead_path;
1010 source->read_ahead_path = NULL;
1012 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1013 imd->prev_pixbuf = source->prev_pixbuf;
1014 source->prev_pixbuf = NULL;
1016 g_free(imd->prev_path);
1017 imd->prev_path = source->prev_path;
1018 source->prev_path = NULL;
1020 imd->completed = source->completed;
1022 imd->x_scroll = source->x_scroll;
1023 imd->y_scroll = source->y_scroll;
1025 if (imd->source_tiles_enabled)
1027 image_source_tile_unset(imd);
1030 if (source->source_tiles_enabled)
1032 imd->source_tiles_enabled = source->source_tiles_enabled;
1033 imd->source_tiles_cache_size = source->source_tiles_cache_size;
1034 imd->source_tiles = source->source_tiles;
1035 imd->source_tile_width = source->source_tile_width;
1036 imd->source_tile_height = source->source_tile_height;
1038 source->source_tiles_enabled = FALSE;
1039 source->source_tiles = NULL;
1041 imd->func_tile_request = source->func_tile_request;
1042 imd->func_tile_dispose = source->func_tile_dispose;
1043 imd->data_tile = source->data_tile;
1045 source->func_tile_request = NULL;
1046 source->func_tile_dispose = NULL;
1047 source->data_tile = NULL;
1049 imd->image_width = source->image_width;
1050 imd->image_height = source->image_height;
1052 if (image_zoom_clamp(imd, source->zoom, TRUE, TRUE))
1054 image_size_clamp(imd);
1055 image_scroll_clamp(imd);
1056 image_tile_sync(imd, imd->width, imd->height, FALSE);
1057 image_redraw(imd, FALSE);
1062 image_scroll_clamp(imd);
1068 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1070 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1073 void image_reload(ImageWindow *imd)
1075 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1077 image_change_complete(imd, image_zoom_get(imd), FALSE);
1080 void image_scroll(ImageWindow *imd, gint x, gint y)
1082 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1085 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1086 gdouble x_align, gdouble y_align)
1088 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1091 void image_alter(ImageWindow *imd, AlterType type)
1093 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1097 /* still loading, wait till done */
1098 imd->delay_alter_type = type;
1102 image_alter_real(imd, type, TRUE);
1105 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1107 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1110 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1112 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1115 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1117 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1120 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1122 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1125 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1131 pr = (PixbufRenderer *)imd->pr;
1133 if (!pixbuf_renderer_get_pixbuf(pr) ||
1134 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1138 zoom = (gdouble)pr->window_height / height;
1142 zoom = (gdouble)pr->window_width / width;
1147 zoom = 0.0 - 1.0 / zoom;
1150 pixbuf_renderer_zoom_set(pr, zoom);
1153 gdouble image_zoom_get(ImageWindow *imd)
1155 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1158 gdouble image_zoom_get_real(ImageWindow *imd)
1160 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1163 gchar *image_zoom_get_as_text(ImageWindow *imd)
1171 gchar *approx = " ";
1173 zoom = image_zoom_get(imd);
1174 scale = image_zoom_get_real(imd);
1180 else if (zoom < 0.0)
1184 else if (zoom == 0.0 && scale != 0.0)
1197 if (rint(l) != l) pl = 1;
1198 if (rint(r) != r) pr = 1;
1200 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1203 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1207 if (mode == ZOOM_RESET_ORIGINAL)
1211 else if (mode == ZOOM_RESET_FIT_WINDOW)
1219 zoom = image_zoom_get(imd);
1232 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1234 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1238 image_read_ahead_set(imd, path);
1242 image_read_ahead_cancel(imd);
1246 static gint image_auto_refresh_cb(gpointer data)
1248 ImageWindow *imd = data;
1251 if (!imd || !image_get_pixbuf(imd) ||
1252 imd->il || !imd->image_path ||
1253 !update_on_time_change) return TRUE;
1255 newtime = filetime(imd->image_path);
1256 if (newtime > 0 && newtime != imd->mtime)
1258 imd->mtime = newtime;
1265 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1267 void image_auto_refresh(ImageWindow *imd, gint interval)
1270 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1272 if (imd->auto_refresh_id > -1)
1274 g_source_remove(imd->auto_refresh_id);
1275 imd->auto_refresh_id = -1;
1276 imd->auto_refresh_interval = -1;
1279 if (interval < 0) return;
1281 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1283 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1284 imd->auto_refresh_interval = interval;
1287 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1289 imd->top_window_sync = allow_sync;
1291 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1294 void image_background_set_black(ImageWindow *imd, gint black)
1296 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1299 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1301 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1304 void image_set_delay_flip(ImageWindow *imd, gint delay)
1307 imd->delay_flip == delay) return;
1309 imd->delay_flip = delay;
1311 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1313 if (!imd->delay_flip && imd->il)
1317 pr = PIXBUF_RENDERER(imd->pr);
1318 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1321 image_load_pixbuf_ready(imd);
1325 void image_to_root_window(ImageWindow *imd, gint scaled)
1328 GdkWindow *rootwindow;
1336 pixbuf = image_get_pixbuf(imd);
1337 if (!pixbuf) return;
1339 screen = gtk_widget_get_screen(imd->widget);
1340 rootwindow = gdk_screen_get_root_window(screen);
1341 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1345 width = gdk_screen_width();
1346 height = gdk_screen_height();
1350 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1353 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1355 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1356 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1357 gdk_window_clear(rootwindow);
1359 g_object_unref(pixmap);
1365 *-------------------------------------------------------------------
1367 *-------------------------------------------------------------------
1370 static void image_free(ImageWindow *imd)
1374 image_read_ahead_cancel(imd);
1375 image_post_buffer_set(imd, NULL, NULL);
1376 image_auto_refresh(imd, -1);
1378 g_free(imd->image_path);
1380 g_free(imd->title_right);
1385 static void image_destroy_cb(GtkObject *widget, gpointer data)
1387 ImageWindow *imd = data;
1391 ImageWindow *image_new(gint frame)
1395 imd = g_new0(ImageWindow, 1);
1397 imd->top_window = NULL;
1399 imd->title_right = NULL;
1400 imd->title_show_zoom = FALSE;
1402 imd->unknown = TRUE;
1404 imd->has_frame = frame;
1405 imd->top_window_sync = FALSE;
1407 imd->delay_alter_type = ALTER_NONE;
1409 imd->read_ahead_il = NULL;
1410 imd->read_ahead_pixbuf = NULL;
1411 imd->read_ahead_path = NULL;
1413 imd->completed = FALSE;
1415 imd->auto_refresh_id = -1;
1416 imd->auto_refresh_interval = -1;
1418 imd->delay_flip = FALSE;
1420 imd->func_update = NULL;
1421 imd->func_complete = NULL;
1422 imd->func_tile_request = NULL;
1423 imd->func_tile_dispose = NULL;
1425 imd->func_button = NULL;
1426 imd->func_scroll = NULL;
1428 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1430 g_object_set(G_OBJECT(imd->pr), "zoom_2pass", TRUE, NULL);
1434 imd->widget = gtk_frame_new(NULL);
1435 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1436 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1437 gtk_widget_show(imd->pr);
1439 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1440 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1441 G_CALLBACK(image_focus_in_cb), imd);
1442 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1443 G_CALLBACK(image_focus_out_cb), imd);
1445 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1446 G_CALLBACK(image_focus_expose), imd);
1450 imd->widget = imd->pr;
1453 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1454 G_CALLBACK(image_click_cb), imd);
1455 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1456 G_CALLBACK(image_scroll_notify_cb), imd);
1458 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1459 G_CALLBACK(image_scroll_cb), imd);
1461 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1462 G_CALLBACK(image_destroy_cb), imd);