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, gint exif_rotated)
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 && pr->scale != 0.0)
229 switch (pr->scroll_reset)
231 case PR_SCROLL_RESET_NOCHANGE:
233 case PR_SCROLL_RESET_CENTER:
234 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
235 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
237 case PR_SCROLL_RESET_TOPLEFT:
244 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
245 (gint)((gdouble)y / pr->scale),
250 static void image_post_process(ImageWindow *imd, gint clamp)
252 gint exif_rotated = FALSE;
254 if (exif_rotate_enable && image_get_pixbuf(imd))
259 ed = exif_read(imd->image_path);
260 if (ed && exif_get_integer(ed, "Orientation", &orientation))
262 /* see http://jpegclub.org/exif_orientation.html
265 888888 888888 88 88 8888888888 88 88 8888888888
266 88 88 88 88 88 88 88 88 88 88 88 88
267 8888 8888 8888 8888 88 8888888888 8888888888 88
274 case EXIF_ORIENTATION_TOP_LEFT:
275 /* normal -- nothing to do */
277 case EXIF_ORIENTATION_TOP_RIGHT:
279 imd->delay_alter_type = ALTER_MIRROR;
282 case EXIF_ORIENTATION_BOTTOM_RIGHT:
284 imd->delay_alter_type = ALTER_ROTATE_180;
287 case EXIF_ORIENTATION_BOTTOM_LEFT:
289 imd->delay_alter_type = ALTER_FLIP;
292 case EXIF_ORIENTATION_LEFT_TOP:
293 /* not implemented -- too wacky to fix in one step */
295 case EXIF_ORIENTATION_RIGHT_TOP:
296 /* rotated -90 (270) */
297 imd->delay_alter_type = ALTER_ROTATE_90;
300 case EXIF_ORIENTATION_RIGHT_BOTTOM:
301 /* not implemented -- too wacky to fix in one step */
303 case EXIF_ORIENTATION_LEFT_BOTTOM:
305 imd->delay_alter_type = ALTER_ROTATE_90_CC;
309 /* The other values are out of range */
316 if (imd->delay_alter_type != ALTER_NONE)
318 image_alter_real(imd, imd->delay_alter_type, clamp, exif_rotated);
323 *-------------------------------------------------------------------
324 * read ahead (prebuffer)
325 *-------------------------------------------------------------------
328 static void image_read_ahead_cancel(ImageWindow *imd)
330 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
332 image_loader_free(imd->read_ahead_il);
333 imd->read_ahead_il = NULL;
335 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
336 imd->read_ahead_pixbuf = NULL;
338 g_free(imd->read_ahead_path);
339 imd->read_ahead_path = NULL;
342 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
344 ImageWindow *imd = data;
346 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
348 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
349 if (imd->read_ahead_pixbuf)
351 g_object_ref(imd->read_ahead_pixbuf);
355 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
357 image_loader_free(imd->read_ahead_il);
358 imd->read_ahead_il = NULL;
360 image_complete_util(imd, TRUE);
363 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
365 /* we even treat errors as success, maybe at least some of the file was ok */
366 image_read_ahead_done_cb(il, data);
369 static void image_read_ahead_start(ImageWindow *imd)
371 /* already started ? */
372 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
374 /* still loading ?, do later */
377 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
379 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
381 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
382 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
384 image_read_ahead_cancel(imd);
385 image_complete_util(imd, TRUE);
389 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
391 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
393 image_read_ahead_cancel(imd);
395 imd->read_ahead_path = g_strdup(path);
397 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
399 image_read_ahead_start(imd);
403 *-------------------------------------------------------------------
405 *-------------------------------------------------------------------
408 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
410 g_free(imd->prev_path);
411 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
415 imd->prev_path = g_strdup(path);
417 g_object_ref(pixbuf);
418 imd->prev_pixbuf = pixbuf;
422 imd->prev_path = NULL;
423 imd->prev_pixbuf = NULL;
426 if (debug) printf("post buffer set: %s\n", path);
429 static gint image_post_buffer_get(ImageWindow *imd)
433 if (imd->prev_pixbuf &&
434 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
436 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
444 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
445 imd->prev_pixbuf = NULL;
447 g_free(imd->prev_path);
448 imd->prev_path = NULL;
454 *-------------------------------------------------------------------
456 *-------------------------------------------------------------------
459 static void image_load_pixbuf_ready(ImageWindow *imd)
461 if (image_get_pixbuf(imd) || !imd->il) return;
463 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
466 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
468 ImageWindow *imd = data;
471 pr = (PixbufRenderer *)imd->pr;
473 if (imd->delay_flip &&
474 pr->pixbuf != image_loader_get_pixbuf(il))
479 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
481 pixbuf_renderer_area_changed(pr, x, y, w, h);
484 static void image_load_done_cb(ImageLoader *il, gpointer data)
486 ImageWindow *imd = data;
488 if (debug) printf ("image done\n");
490 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
492 if (imd->delay_flip &&
493 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
495 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
496 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
499 image_loader_free(imd->il);
502 image_post_process(imd, TRUE);
504 image_read_ahead_start(imd);
507 static void image_load_error_cb(ImageLoader *il, gpointer data)
509 if (debug) printf ("image error\n");
511 /* even on error handle it like it was done,
512 * since we have a pixbuf with _something_ */
514 image_load_done_cb(il, data);
517 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
518 static void image_load_buffer_throttle(ImageLoader *il)
520 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
522 /* Larger image files usually have larger chunks of data per pixel...
523 * So increase the buffer read size so that the rendering chunks called
527 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
531 /* this read ahead is located here merely for the callbacks, above */
533 static gint image_read_ahead_check(ImageWindow *imd)
535 if (!imd->read_ahead_path) return FALSE;
536 if (imd->il) return FALSE;
538 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
540 image_read_ahead_cancel(imd);
544 if (imd->read_ahead_il)
546 imd->il = imd->read_ahead_il;
547 imd->read_ahead_il = NULL;
549 /* override the old signals */
550 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
551 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
552 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
554 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
555 image_load_buffer_throttle(imd->il);
558 /* do this one directly (probably should add a set func) */
559 imd->il->func_done = image_load_done_cb;
561 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
563 if (!imd->delay_flip)
565 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
568 image_read_ahead_cancel(imd);
571 else if (imd->read_ahead_pixbuf)
573 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
574 g_object_unref(imd->read_ahead_pixbuf);
575 imd->read_ahead_pixbuf = NULL;
577 image_read_ahead_cancel(imd);
579 image_post_process(imd, FALSE);
583 image_read_ahead_cancel(imd);
587 static gint image_load_begin(ImageWindow *imd, const gchar *path)
589 if (debug) printf ("image begin \n");
591 if (imd->il) return FALSE;
593 imd->completed = FALSE;
594 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
596 if (image_post_buffer_get(imd))
598 if (debug) printf("from post buffer: %s\n", imd->image_path);
602 if (image_read_ahead_check(imd))
604 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
608 if (!imd->delay_flip && image_get_pixbuf(imd))
612 pr = PIXBUF_RENDERER(imd->pr);
613 if (pr->pixbuf) g_object_unref(pr->pixbuf);
617 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
619 imd->il = image_loader_new(path);
621 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
622 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
623 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
625 if (!image_loader_start(imd->il, image_load_done_cb, imd))
627 if (debug) printf("image start error\n");
629 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
631 image_loader_free(imd->il);
634 image_complete_util(imd, FALSE);
639 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
640 image_load_buffer_throttle(imd->il);
643 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
648 static void image_reset(ImageWindow *imd)
650 /* stops anything currently being done */
652 if (debug) printf("image reset\n");
654 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
656 image_loader_free(imd->il);
659 imd->delay_alter_type = ALTER_NONE;
663 *-------------------------------------------------------------------
665 *-------------------------------------------------------------------
668 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
672 if (imd->image_path && isfile(imd->image_path))
676 pr = PIXBUF_RENDERER(imd->pr);
677 pr->zoom = zoom; /* store the zoom, needed by the loader */
679 if (image_load_begin(imd, imd->image_path))
681 imd->unknown = FALSE;
687 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
688 image_change_pixbuf(imd, pixbuf, zoom);
689 g_object_unref(pixbuf);
693 imd->size = filesize(imd->image_path);
694 imd->mtime = filetime(imd->image_path);
702 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
703 image_change_pixbuf(imd, pixbuf, zoom);
704 g_object_unref(pixbuf);
705 imd->mtime = filetime(imd->image_path);
709 image_change_pixbuf(imd, NULL, zoom);
716 image_update_util(imd);
719 static void image_change_real(ImageWindow *imd, const gchar *path,
720 CollectionData *cd, CollectInfo *info, gdouble zoom)
723 GdkPixbuf *prev_pixbuf = NULL;
724 gchar *prev_path = NULL;
725 gint prev_clear = FALSE;
727 imd->collection = cd;
728 imd->collection_info = info;
730 pixbuf = image_get_pixbuf(imd);
732 if (enable_read_ahead && imd->image_path && pixbuf)
736 /* current image is not finished */
741 prev_path = g_strdup(imd->image_path);
742 prev_pixbuf = pixbuf;
743 g_object_ref(prev_pixbuf);
747 g_free(imd->image_path);
748 imd->image_path = g_strdup(path);
749 imd->image_name = filename_from_path(imd->image_path);
751 image_change_complete(imd, zoom, TRUE);
755 image_post_buffer_set(imd, prev_path, prev_pixbuf);
757 g_object_unref(prev_pixbuf);
761 image_post_buffer_set(imd, NULL, NULL);
764 image_update_title(imd);
769 *-------------------------------------------------------------------
771 *-------------------------------------------------------------------
774 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
778 widget = imd->widget;
779 if (!widget->window) return;
783 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
784 area, widget, "image_window",
785 widget->allocation.x, widget->allocation.y,
786 widget->allocation.width - 1, widget->allocation.height - 1);
790 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
791 area, widget, "image_window",
792 widget->allocation.x, widget->allocation.y,
793 widget->allocation.width - 1, widget->allocation.height - 1);
797 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
799 ImageWindow *imd = data;
801 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
805 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
807 ImageWindow *imd = data;
809 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
810 image_focus_paint(imd, TRUE, NULL);
815 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
817 ImageWindow *imd = data;
819 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
820 image_focus_paint(imd, FALSE, NULL);
825 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
826 gint relative, gint always)
828 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
831 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
833 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
836 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
838 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
841 void image_overlay_remove(ImageWindow *imd, gint id)
843 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
846 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
848 ImageWindow *imd = data;
850 if (imd->func_scroll &&
851 event && event->type == GDK_SCROLL)
853 imd->func_scroll(imd, event->direction, event->time,
854 event->x, event->y, event->state, imd->data_scroll);
862 *-------------------------------------------------------------------
864 *-------------------------------------------------------------------
867 void image_attach_window(ImageWindow *imd, GtkWidget *window,
868 const gchar *title, const gchar *title_right, gint show_zoom)
870 imd->top_window = window;
872 imd->title = g_strdup(title);
873 g_free(imd->title_right);
874 imd->title_right = g_strdup(title_right);
875 imd->title_show_zoom = show_zoom;
877 if (!fit_window) window = NULL;
879 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
881 image_update_title(imd);
884 void image_set_update_func(ImageWindow *imd,
885 void (*func)(ImageWindow *imd, gpointer data),
888 imd->func_update = func;
889 imd->data_update = data;
892 void image_set_complete_func(ImageWindow *imd,
893 void (*func)(ImageWindow *, gint preload, gpointer),
896 imd->func_complete = func;
897 imd->data_complete = data;
900 void image_set_new_func(ImageWindow *imd,
901 void (*func)(ImageWindow *, gpointer),
904 imd->func_new = func;
905 imd->data_new = data;
909 void image_set_button_func(ImageWindow *imd,
910 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
913 imd->func_button = func;
914 imd->data_button = data;
917 void image_set_scroll_func(ImageWindow *imd,
918 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
921 imd->func_scroll = func;
922 imd->data_scroll = data;
925 void image_set_scroll_notify_func(ImageWindow *imd,
926 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
929 imd->func_scroll_notify = func;
930 imd->data_scroll_notify = data;
935 const gchar *image_get_path(ImageWindow *imd)
937 return imd->image_path;
940 const gchar *image_get_name(ImageWindow *imd)
942 return imd->image_name;
945 /* merely changes path string, does not change the image! */
946 void image_set_path(ImageWindow *imd, const gchar *newpath)
948 g_free(imd->image_path);
949 imd->image_path = g_strdup(newpath);
950 imd->image_name = filename_from_path(imd->image_path);
952 image_update_title(imd);
956 /* load a new image */
958 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
960 if (imd->image_path == path ||
961 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
963 image_change_real(imd, path, NULL, NULL, zoom);
966 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
968 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
971 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
973 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
977 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
979 if (!cd || !info || !g_list_find(cd->list, info)) return;
981 image_change_real(imd, info->path, cd, info, zoom);
984 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
986 if (collection_to_number(imd->collection) >= 0)
988 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
990 if (info) *info = imd->collection_info;
994 if (info) *info = NULL;
996 return imd->collection;
999 if (info) *info = NULL;
1003 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1005 /* change data for the callbacks directly */
1007 il->data_area_ready = data;
1008 il->data_error = data;
1009 il->data_done = data;
1010 il->data_percent = data;
1013 /* this is more like a move function
1014 * it moves most data from source to imd
1016 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1018 if (imd == source) return;
1020 imd->unknown = source->unknown;
1022 imd->collection = source->collection;
1023 imd->collection_info = source->collection_info;
1024 imd->size = source->size;
1025 imd->mtime = source->mtime;
1027 image_set_path(imd, image_get_path(source));
1029 image_loader_free(imd->il);
1034 imd->il = source->il;
1037 image_loader_sync_data(imd->il, imd);
1039 imd->delay_alter_type = source->delay_alter_type;
1040 source->delay_alter_type = ALTER_NONE;
1043 image_loader_free(imd->read_ahead_il);
1044 imd->read_ahead_il = source->read_ahead_il;
1045 source->read_ahead_il = NULL;
1046 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1048 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1049 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1050 source->read_ahead_pixbuf = NULL;
1052 g_free(imd->read_ahead_path);
1053 imd->read_ahead_path = source->read_ahead_path;
1054 source->read_ahead_path = NULL;
1056 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1057 imd->prev_pixbuf = source->prev_pixbuf;
1058 source->prev_pixbuf = NULL;
1060 g_free(imd->prev_path);
1061 imd->prev_path = source->prev_path;
1062 source->prev_path = NULL;
1064 imd->completed = source->completed;
1066 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1071 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1073 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1076 void image_reload(ImageWindow *imd)
1078 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1080 image_change_complete(imd, image_zoom_get(imd), FALSE);
1083 void image_scroll(ImageWindow *imd, gint x, gint y)
1085 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1088 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1089 gdouble x_align, gdouble y_align)
1091 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1094 void image_alter(ImageWindow *imd, AlterType type)
1096 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1100 /* still loading, wait till done */
1101 imd->delay_alter_type = type;
1105 image_alter_real(imd, type, TRUE, FALSE);
1108 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1110 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1113 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1115 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1118 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1120 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1123 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1125 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1128 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1134 pr = (PixbufRenderer *)imd->pr;
1136 if (!pixbuf_renderer_get_pixbuf(pr) ||
1137 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1141 zoom = (gdouble)pr->window_height / height;
1145 zoom = (gdouble)pr->window_width / width;
1150 zoom = 0.0 - 1.0 / zoom;
1153 pixbuf_renderer_zoom_set(pr, zoom);
1156 gdouble image_zoom_get(ImageWindow *imd)
1158 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1161 gdouble image_zoom_get_real(ImageWindow *imd)
1163 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1166 gchar *image_zoom_get_as_text(ImageWindow *imd)
1174 gchar *approx = " ";
1176 zoom = image_zoom_get(imd);
1177 scale = image_zoom_get_real(imd);
1183 else if (zoom < 0.0)
1187 else if (zoom == 0.0 && scale != 0.0)
1200 if (rint(l) != l) pl = 1;
1201 if (rint(r) != r) pr = 1;
1203 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1206 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1210 if (mode == ZOOM_RESET_ORIGINAL)
1214 else if (mode == ZOOM_RESET_FIT_WINDOW)
1222 zoom = image_zoom_get(imd);
1235 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1237 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1241 image_read_ahead_set(imd, path);
1245 image_read_ahead_cancel(imd);
1249 static gint image_auto_refresh_cb(gpointer data)
1251 ImageWindow *imd = data;
1254 if (!imd || !image_get_pixbuf(imd) ||
1255 imd->il || !imd->image_path ||
1256 !update_on_time_change) return TRUE;
1258 newtime = filetime(imd->image_path);
1259 if (newtime > 0 && newtime != imd->mtime)
1261 imd->mtime = newtime;
1268 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1270 void image_auto_refresh(ImageWindow *imd, gint interval)
1273 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1275 if (imd->auto_refresh_id > -1)
1277 g_source_remove(imd->auto_refresh_id);
1278 imd->auto_refresh_id = -1;
1279 imd->auto_refresh_interval = -1;
1282 if (interval < 0) return;
1284 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1286 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1287 imd->auto_refresh_interval = interval;
1290 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1292 imd->top_window_sync = allow_sync;
1294 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1297 void image_background_set_black(ImageWindow *imd, gint black)
1299 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1302 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1304 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1307 void image_set_delay_flip(ImageWindow *imd, gint delay)
1310 imd->delay_flip == delay) return;
1312 imd->delay_flip = delay;
1314 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1316 if (!imd->delay_flip && imd->il)
1320 pr = PIXBUF_RENDERER(imd->pr);
1321 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1324 image_load_pixbuf_ready(imd);
1328 void image_to_root_window(ImageWindow *imd, gint scaled)
1331 GdkWindow *rootwindow;
1339 pixbuf = image_get_pixbuf(imd);
1340 if (!pixbuf) return;
1342 screen = gtk_widget_get_screen(imd->widget);
1343 rootwindow = gdk_screen_get_root_window(screen);
1344 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1348 width = gdk_screen_width();
1349 height = gdk_screen_height();
1353 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1356 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1358 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1359 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1360 gdk_window_clear(rootwindow);
1362 g_object_unref(pixmap);
1368 *-------------------------------------------------------------------
1370 *-------------------------------------------------------------------
1373 static void image_options_set(ImageWindow *imd)
1375 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1376 "zoom_2pass", two_pass_zoom,
1377 "zoom_expand", zoom_to_fit_expands,
1378 "dither_quality", dither_quality,
1379 "scroll_reset", scroll_reset_method,
1380 "cache_display", tile_cache_max,
1381 "window_fit", (imd->top_window_sync && fit_window),
1382 "window_limit", limit_window_size,
1383 "window_limit_value", max_window_size,
1386 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1389 void image_options_sync(void)
1401 image_options_set(imd);
1406 *-------------------------------------------------------------------
1408 *-------------------------------------------------------------------
1411 static void image_free(ImageWindow *imd)
1413 image_list = g_list_remove(image_list, imd);
1417 image_read_ahead_cancel(imd);
1418 image_post_buffer_set(imd, NULL, NULL);
1419 image_auto_refresh(imd, -1);
1421 g_free(imd->image_path);
1423 g_free(imd->title_right);
1428 static void image_destroy_cb(GtkObject *widget, gpointer data)
1430 ImageWindow *imd = data;
1434 ImageWindow *image_new(gint frame)
1438 imd = g_new0(ImageWindow, 1);
1440 imd->top_window = NULL;
1442 imd->title_right = NULL;
1443 imd->title_show_zoom = FALSE;
1445 imd->unknown = TRUE;
1447 imd->has_frame = frame;
1448 imd->top_window_sync = FALSE;
1450 imd->delay_alter_type = ALTER_NONE;
1452 imd->read_ahead_il = NULL;
1453 imd->read_ahead_pixbuf = NULL;
1454 imd->read_ahead_path = NULL;
1456 imd->completed = FALSE;
1458 imd->auto_refresh_id = -1;
1459 imd->auto_refresh_interval = -1;
1461 imd->delay_flip = FALSE;
1463 imd->func_update = NULL;
1464 imd->func_complete = NULL;
1465 imd->func_tile_request = NULL;
1466 imd->func_tile_dispose = NULL;
1468 imd->func_button = NULL;
1469 imd->func_scroll = NULL;
1471 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1473 image_options_set(imd);
1477 imd->widget = gtk_frame_new(NULL);
1478 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1479 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1480 gtk_widget_show(imd->pr);
1482 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1483 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1484 G_CALLBACK(image_focus_in_cb), imd);
1485 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1486 G_CALLBACK(image_focus_out_cb), imd);
1488 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1489 G_CALLBACK(image_focus_expose), imd);
1493 imd->widget = imd->pr;
1496 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1497 G_CALLBACK(image_click_cb), imd);
1498 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1499 G_CALLBACK(image_scroll_notify_cb), imd);
1501 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1502 G_CALLBACK(image_scroll_cb), imd);
1504 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1505 G_CALLBACK(image_destroy_cb), imd);
1507 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1508 G_CALLBACK(image_zoom_cb), imd);
1509 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1510 G_CALLBACK(image_render_complete_cb), imd);
1512 image_list = g_list_append(image_list, imd);