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;
46 *-------------------------------------------------------------------
48 *-------------------------------------------------------------------
51 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
53 ImageWindow *imd = data;
57 imd->func_button(imd, event->button, event->time,
58 event->x, event->y, event->state, imd->data_button);
62 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
64 ImageWindow *imd = data;
66 if (imd->func_scroll_notify && pr->scale)
68 imd->func_scroll_notify(imd,
69 (gint)((gdouble)pr->x_scroll / pr->scale),
70 (gint)((gdouble)pr->y_scroll / pr->scale),
71 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
72 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
73 imd->data_scroll_notify);
77 static void image_update_util(ImageWindow *imd)
79 if (imd->func_update) imd->func_update(imd, imd->data_update);
82 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
84 ImageWindow *imd = data;
86 image_update_util(imd);
89 static void image_complete_util(ImageWindow *imd, gint preload)
91 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
93 if (debug) printf("image load completed \"%s\" (%s)\n",
94 (preload) ? imd->read_ahead_path : imd->image_path,
95 (preload) ? "preload" : "current");
97 if (!preload) imd->completed = TRUE;
98 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
101 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
103 ImageWindow *imd = data;
105 image_complete_util(imd, FALSE);
108 static void image_new_util(ImageWindow *imd)
110 if (imd->func_new) imd->func_new(imd, imd->data_new);
114 *-------------------------------------------------------------------
116 *-------------------------------------------------------------------
119 static void image_update_title(ImageWindow *imd)
123 gchar *collection = NULL;
125 if (!imd->top_window) return;
127 if (imd->collection && collection_to_number(imd->collection) >= 0)
130 name = imd->collection->name;
131 if (!name) name = _("Untitled");
132 collection = g_strdup_printf(" (Collection %s)", name);
135 if (imd->title_show_zoom)
137 gchar *buf = image_zoom_get_as_text(imd);
138 zoom = g_strconcat(" [", buf, "]", NULL);
142 title = g_strdup_printf("%s%s%s%s%s%s",
143 imd->title ? imd->title : "",
144 imd->image_name ? imd->image_name : "",
146 collection ? collection : "",
147 imd->image_name ? " - " : "",
148 imd->title_right ? imd->title_right : "");
150 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
158 *-------------------------------------------------------------------
159 * rotation, flip, etc.
160 *-------------------------------------------------------------------
163 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
166 GdkPixbuf *new = NULL;
170 pr = (PixbufRenderer *)imd->pr;
172 imd->delay_alter_type = ALTER_NONE;
174 if (!pr->pixbuf) return;
176 x = pr->x_scroll + (pr->vis_width / 2);
177 y = pr->y_scroll + (pr->vis_height / 2);
181 case ALTER_ROTATE_90:
182 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
187 case ALTER_ROTATE_90_CC:
188 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
193 case ALTER_ROTATE_180:
194 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
199 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
203 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
214 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
217 if (clamp && pr->zoom != 0.0)
219 pixbuf_renderer_scroll(pr, x - (pr->vis_width / 2), y - (pr->vis_height / 2));
223 static void image_post_process(ImageWindow *imd, gint clamp)
225 if (exif_rotate_enable && image_get_pixbuf(imd))
230 ed = exif_read(imd->image_path);
231 if (ed && exif_get_integer(ed, "Orientation", &orientation))
233 /* see http://jpegclub.org/exif_orientation.html
236 888888 888888 88 88 8888888888 88 88 8888888888
237 88 88 88 88 88 88 88 88 88 88 88 88
238 8888 8888 8888 8888 88 8888888888 8888888888 88
245 case EXIF_ORIENTATION_TOP_LEFT:
246 /* normal -- nothing to do */
248 case EXIF_ORIENTATION_TOP_RIGHT:
250 imd->delay_alter_type = ALTER_MIRROR;
252 case EXIF_ORIENTATION_BOTTOM_RIGHT:
254 imd->delay_alter_type = ALTER_ROTATE_180;
256 case EXIF_ORIENTATION_BOTTOM_LEFT:
258 imd->delay_alter_type = ALTER_FLIP;
260 case EXIF_ORIENTATION_LEFT_TOP:
261 /* not implemented -- too wacky to fix in one step */
263 case EXIF_ORIENTATION_RIGHT_TOP:
264 /* rotated -90 (270) */
265 imd->delay_alter_type = ALTER_ROTATE_90;
267 case EXIF_ORIENTATION_RIGHT_BOTTOM:
268 /* not implemented -- too wacky to fix in one step */
270 case EXIF_ORIENTATION_LEFT_BOTTOM:
272 imd->delay_alter_type = ALTER_ROTATE_90_CC;
275 /* The other values are out of range */
282 if (imd->delay_alter_type != ALTER_NONE)
284 image_alter_real(imd, imd->delay_alter_type, clamp);
289 *-------------------------------------------------------------------
290 * read ahead (prebuffer)
291 *-------------------------------------------------------------------
294 static void image_read_ahead_cancel(ImageWindow *imd)
296 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
298 image_loader_free(imd->read_ahead_il);
299 imd->read_ahead_il = NULL;
301 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
302 imd->read_ahead_pixbuf = NULL;
304 g_free(imd->read_ahead_path);
305 imd->read_ahead_path = NULL;
308 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
310 ImageWindow *imd = data;
312 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
314 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
315 if (imd->read_ahead_pixbuf)
317 g_object_ref(imd->read_ahead_pixbuf);
321 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
323 image_loader_free(imd->read_ahead_il);
324 imd->read_ahead_il = NULL;
326 image_complete_util(imd, TRUE);
329 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
331 /* we even treat errors as success, maybe at least some of the file was ok */
332 image_read_ahead_done_cb(il, data);
335 static void image_read_ahead_start(ImageWindow *imd)
337 /* already started ? */
338 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
340 /* still loading ?, do later */
343 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
345 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
347 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
348 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
350 image_read_ahead_cancel(imd);
351 image_complete_util(imd, TRUE);
355 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
357 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
359 image_read_ahead_cancel(imd);
361 imd->read_ahead_path = g_strdup(path);
363 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
365 image_read_ahead_start(imd);
369 *-------------------------------------------------------------------
371 *-------------------------------------------------------------------
374 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
376 g_free(imd->prev_path);
377 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
381 imd->prev_path = g_strdup(path);
383 g_object_ref(pixbuf);
384 imd->prev_pixbuf = pixbuf;
388 imd->prev_path = NULL;
389 imd->prev_pixbuf = NULL;
392 if (debug) printf("post buffer set: %s\n", path);
395 static gint image_post_buffer_get(ImageWindow *imd)
399 if (imd->prev_pixbuf &&
400 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
402 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
410 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
411 imd->prev_pixbuf = NULL;
413 g_free(imd->prev_path);
414 imd->prev_path = NULL;
420 *-------------------------------------------------------------------
422 *-------------------------------------------------------------------
425 static void image_load_pixbuf_ready(ImageWindow *imd)
427 if (image_get_pixbuf(imd) || !imd->il) return;
429 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
432 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
434 ImageWindow *imd = data;
437 pr = (PixbufRenderer *)imd->pr;
439 if (imd->delay_flip &&
440 pr->pixbuf != image_loader_get_pixbuf(il))
445 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
447 pixbuf_renderer_area_changed(pr, x, y, w, h);
450 static void image_load_done_cb(ImageLoader *il, gpointer data)
452 ImageWindow *imd = data;
454 if (debug) printf ("image done\n");
456 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
458 if (imd->delay_flip &&
459 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
461 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
464 image_loader_free(imd->il);
467 image_post_process(imd, TRUE);
469 image_read_ahead_start(imd);
472 static void image_load_error_cb(ImageLoader *il, gpointer data)
474 if (debug) printf ("image error\n");
476 /* even on error handle it like it was done,
477 * since we have a pixbuf with _something_ */
479 image_load_done_cb(il, data);
482 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
483 static void image_load_buffer_throttle(ImageLoader *il)
485 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
487 /* Larger image files usually have larger chunks of data per pixel...
488 * So increase the buffer read size so that the rendering chunks called
492 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
496 /* this read ahead is located here merely for the callbacks, above */
498 static gint image_read_ahead_check(ImageWindow *imd)
500 if (!imd->read_ahead_path) return FALSE;
501 if (imd->il) return FALSE;
503 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
505 image_read_ahead_cancel(imd);
509 if (imd->read_ahead_il)
511 imd->il = imd->read_ahead_il;
512 imd->read_ahead_il = NULL;
514 /* override the old signals */
515 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
516 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
517 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
519 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
520 image_load_buffer_throttle(imd->il);
523 /* do this one directly (probably should add a set func) */
524 imd->il->func_done = image_load_done_cb;
526 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
528 if (!imd->delay_flip)
530 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
533 image_read_ahead_cancel(imd);
536 else if (imd->read_ahead_pixbuf)
538 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
539 g_object_unref(imd->read_ahead_pixbuf);
540 imd->read_ahead_pixbuf = NULL;
542 image_read_ahead_cancel(imd);
544 image_post_process(imd, FALSE);
548 image_read_ahead_cancel(imd);
552 static gint image_load_begin(ImageWindow *imd, const gchar *path)
554 if (debug) printf ("image begin \n");
556 if (imd->il) return FALSE;
558 imd->completed = FALSE;
559 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
561 if (image_post_buffer_get(imd))
563 if (debug) printf("from post buffer: %s\n", imd->image_path);
567 if (image_read_ahead_check(imd))
569 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
573 if (!imd->delay_flip && image_get_pixbuf(imd))
577 pr = PIXBUF_RENDERER(imd->pr);
578 if (pr->pixbuf) g_object_unref(pr->pixbuf);
582 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
584 imd->il = image_loader_new(path);
586 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
587 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
588 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
590 if (!image_loader_start(imd->il, image_load_done_cb, imd))
592 if (debug) printf("image start error\n");
594 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
596 image_loader_free(imd->il);
599 image_complete_util(imd, FALSE);
604 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
605 image_load_buffer_throttle(imd->il);
608 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
613 static void image_reset(ImageWindow *imd)
615 /* stops anything currently being done */
617 if (debug) printf("image reset\n");
619 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
621 image_loader_free(imd->il);
624 imd->delay_alter_type = ALTER_NONE;
628 *-------------------------------------------------------------------
630 *-------------------------------------------------------------------
633 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
637 if (imd->image_path && isfile(imd->image_path))
641 pr = PIXBUF_RENDERER(imd->pr);
642 pr->zoom = zoom; /* store the zoom, needed by the loader */
644 if (image_load_begin(imd, imd->image_path))
646 imd->unknown = FALSE;
652 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
653 image_change_pixbuf(imd, pixbuf, zoom);
654 g_object_unref(pixbuf);
658 imd->size = filesize(imd->image_path);
659 imd->mtime = filetime(imd->image_path);
667 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
668 image_change_pixbuf(imd, pixbuf, zoom);
669 g_object_unref(pixbuf);
670 imd->mtime = filetime(imd->image_path);
674 image_change_pixbuf(imd, NULL, zoom);
681 image_update_util(imd);
684 static void image_change_real(ImageWindow *imd, const gchar *path,
685 CollectionData *cd, CollectInfo *info, gdouble zoom)
688 GdkPixbuf *prev_pixbuf = NULL;
689 gchar *prev_path = NULL;
690 gint prev_clear = FALSE;
692 imd->collection = cd;
693 imd->collection_info = info;
695 pixbuf = image_get_pixbuf(imd);
697 if (enable_read_ahead && imd->image_path && pixbuf)
701 /* current image is not finished */
706 prev_path = g_strdup(imd->image_path);
707 prev_pixbuf = pixbuf;
708 g_object_ref(prev_pixbuf);
712 g_free(imd->image_path);
713 imd->image_path = g_strdup(path);
714 imd->image_name = filename_from_path(imd->image_path);
716 image_change_complete(imd, zoom, TRUE);
720 image_post_buffer_set(imd, prev_path, prev_pixbuf);
722 g_object_unref(prev_pixbuf);
726 image_post_buffer_set(imd, NULL, NULL);
729 image_update_title(imd);
734 *-------------------------------------------------------------------
736 *-------------------------------------------------------------------
739 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
743 widget = imd->widget;
744 if (!widget->window) return;
748 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
749 area, widget, "image_window",
750 widget->allocation.x, widget->allocation.y,
751 widget->allocation.width - 1, widget->allocation.height - 1);
755 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
756 area, widget, "image_window",
757 widget->allocation.x, widget->allocation.y,
758 widget->allocation.width - 1, widget->allocation.height - 1);
762 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
764 ImageWindow *imd = data;
766 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
770 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
772 ImageWindow *imd = data;
774 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
775 image_focus_paint(imd, TRUE, NULL);
780 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
782 ImageWindow *imd = data;
784 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
785 image_focus_paint(imd, FALSE, NULL);
790 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
791 gint relative, gint always)
793 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
796 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
798 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
801 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
803 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
806 void image_overlay_remove(ImageWindow *imd, gint id)
808 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
811 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
813 ImageWindow *imd = data;
815 if (imd->func_scroll &&
816 event && event->type == GDK_SCROLL)
818 imd->func_scroll(imd, event->direction, event->time,
819 event->x, event->y, event->state, imd->data_scroll);
827 *-------------------------------------------------------------------
829 *-------------------------------------------------------------------
832 void image_attach_window(ImageWindow *imd, GtkWidget *window,
833 const gchar *title, const gchar *title_right, gint show_zoom)
835 imd->top_window = window;
837 imd->title = g_strdup(title);
838 g_free(imd->title_right);
839 imd->title_right = g_strdup(title_right);
840 imd->title_show_zoom = show_zoom;
842 if (!fit_window) window = NULL;
844 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
846 image_update_title(imd);
849 void image_set_update_func(ImageWindow *imd,
850 void (*func)(ImageWindow *imd, gpointer data),
853 imd->func_update = func;
854 imd->data_update = data;
857 void image_set_complete_func(ImageWindow *imd,
858 void (*func)(ImageWindow *, gint preload, gpointer),
861 imd->func_complete = func;
862 imd->data_complete = data;
865 void image_set_new_func(ImageWindow *imd,
866 void (*func)(ImageWindow *, gpointer),
869 imd->func_new = func;
870 imd->data_new = data;
874 void image_set_button_func(ImageWindow *imd,
875 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
878 imd->func_button = func;
879 imd->data_button = data;
882 void image_set_scroll_func(ImageWindow *imd,
883 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
886 imd->func_scroll = func;
887 imd->data_scroll = data;
890 void image_set_scroll_notify_func(ImageWindow *imd,
891 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
894 imd->func_scroll_notify = func;
895 imd->data_scroll_notify = data;
900 const gchar *image_get_path(ImageWindow *imd)
902 return imd->image_path;
905 const gchar *image_get_name(ImageWindow *imd)
907 return imd->image_name;
910 /* merely changes path string, does not change the image! */
911 void image_set_path(ImageWindow *imd, const gchar *newpath)
913 g_free(imd->image_path);
914 imd->image_path = g_strdup(newpath);
915 imd->image_name = filename_from_path(imd->image_path);
917 image_update_title(imd);
921 /* load a new image */
923 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
925 if (imd->image_path == path ||
926 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
928 image_change_real(imd, path, NULL, NULL, zoom);
931 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
933 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
936 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
938 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
942 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
944 if (!cd || !info || !g_list_find(cd->list, info)) return;
946 image_change_real(imd, info->path, cd, info, zoom);
949 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
951 if (collection_to_number(imd->collection) >= 0)
953 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
955 if (info) *info = imd->collection_info;
959 if (info) *info = NULL;
961 return imd->collection;
964 if (info) *info = NULL;
968 static void image_loader_sync_data(ImageLoader *il, gpointer data)
970 /* change data for the callbacks directly */
972 il->data_area_ready = data;
973 il->data_error = data;
974 il->data_done = data;
975 il->data_percent = data;
978 /* this is more like a move function
979 * it moves most data from source to imd
981 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
983 if (imd == source) return;
985 imd->unknown = source->unknown;
987 imd->collection = source->collection;
988 imd->collection_info = source->collection_info;
989 imd->size = source->size;
990 imd->mtime = source->mtime;
992 image_set_path(imd, image_get_path(source));
994 image_loader_free(imd->il);
999 imd->il = source->il;
1002 image_loader_sync_data(imd->il, imd);
1004 imd->delay_alter_type = source->delay_alter_type;
1005 source->delay_alter_type = ALTER_NONE;
1008 image_loader_free(imd->read_ahead_il);
1009 imd->read_ahead_il = source->read_ahead_il;
1010 source->read_ahead_il = NULL;
1011 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1013 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1014 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1015 source->read_ahead_pixbuf = NULL;
1017 g_free(imd->read_ahead_path);
1018 imd->read_ahead_path = source->read_ahead_path;
1019 source->read_ahead_path = NULL;
1021 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1022 imd->prev_pixbuf = source->prev_pixbuf;
1023 source->prev_pixbuf = NULL;
1025 g_free(imd->prev_path);
1026 imd->prev_path = source->prev_path;
1027 source->prev_path = NULL;
1029 imd->completed = source->completed;
1031 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1036 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1038 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1041 void image_reload(ImageWindow *imd)
1043 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1045 image_change_complete(imd, image_zoom_get(imd), FALSE);
1048 void image_scroll(ImageWindow *imd, gint x, gint y)
1050 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1053 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1054 gdouble x_align, gdouble y_align)
1056 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1059 void image_alter(ImageWindow *imd, AlterType type)
1061 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1065 /* still loading, wait till done */
1066 imd->delay_alter_type = type;
1070 image_alter_real(imd, type, TRUE);
1073 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1075 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1078 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1080 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1083 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1085 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1088 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1090 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1093 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1099 pr = (PixbufRenderer *)imd->pr;
1101 if (!pixbuf_renderer_get_pixbuf(pr) ||
1102 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1106 zoom = (gdouble)pr->window_height / height;
1110 zoom = (gdouble)pr->window_width / width;
1115 zoom = 0.0 - 1.0 / zoom;
1118 pixbuf_renderer_zoom_set(pr, zoom);
1121 gdouble image_zoom_get(ImageWindow *imd)
1123 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1126 gdouble image_zoom_get_real(ImageWindow *imd)
1128 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1131 gchar *image_zoom_get_as_text(ImageWindow *imd)
1139 gchar *approx = " ";
1141 zoom = image_zoom_get(imd);
1142 scale = image_zoom_get_real(imd);
1148 else if (zoom < 0.0)
1152 else if (zoom == 0.0 && scale != 0.0)
1165 if (rint(l) != l) pl = 1;
1166 if (rint(r) != r) pr = 1;
1168 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1171 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1175 if (mode == ZOOM_RESET_ORIGINAL)
1179 else if (mode == ZOOM_RESET_FIT_WINDOW)
1187 zoom = image_zoom_get(imd);
1200 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1202 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1206 image_read_ahead_set(imd, path);
1210 image_read_ahead_cancel(imd);
1214 static gint image_auto_refresh_cb(gpointer data)
1216 ImageWindow *imd = data;
1219 if (!imd || !image_get_pixbuf(imd) ||
1220 imd->il || !imd->image_path ||
1221 !update_on_time_change) return TRUE;
1223 newtime = filetime(imd->image_path);
1224 if (newtime > 0 && newtime != imd->mtime)
1226 imd->mtime = newtime;
1233 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1235 void image_auto_refresh(ImageWindow *imd, gint interval)
1238 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1240 if (imd->auto_refresh_id > -1)
1242 g_source_remove(imd->auto_refresh_id);
1243 imd->auto_refresh_id = -1;
1244 imd->auto_refresh_interval = -1;
1247 if (interval < 0) return;
1249 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1251 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1252 imd->auto_refresh_interval = interval;
1255 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1257 imd->top_window_sync = allow_sync;
1259 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1262 void image_background_set_black(ImageWindow *imd, gint black)
1264 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1267 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1269 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1272 void image_set_delay_flip(ImageWindow *imd, gint delay)
1275 imd->delay_flip == delay) return;
1277 imd->delay_flip = delay;
1279 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1281 if (!imd->delay_flip && imd->il)
1285 pr = PIXBUF_RENDERER(imd->pr);
1286 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1289 image_load_pixbuf_ready(imd);
1293 void image_to_root_window(ImageWindow *imd, gint scaled)
1296 GdkWindow *rootwindow;
1304 pixbuf = image_get_pixbuf(imd);
1305 if (!pixbuf) return;
1307 screen = gtk_widget_get_screen(imd->widget);
1308 rootwindow = gdk_screen_get_root_window(screen);
1309 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1313 width = gdk_screen_width();
1314 height = gdk_screen_height();
1318 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1321 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1323 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1324 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1325 gdk_window_clear(rootwindow);
1327 g_object_unref(pixmap);
1333 *-------------------------------------------------------------------
1335 *-------------------------------------------------------------------
1338 static void image_options_set(ImageWindow *imd)
1340 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1341 "zoom_2pass", two_pass_zoom,
1342 "zoom_expand", zoom_to_fit_expands,
1343 "dither_quality", dither_quality,
1344 "scroll_reset", scroll_reset_method,
1345 "cache_display", tile_cache_max,
1346 "window_fit", fit_window,
1347 "window_limit", limit_window_size,
1348 "window_limit_value", max_window_size,
1352 void image_options_sync(void)
1364 image_options_set(imd);
1369 *-------------------------------------------------------------------
1371 *-------------------------------------------------------------------
1374 static void image_free(ImageWindow *imd)
1376 image_list = g_list_remove(image_list, imd);
1380 image_read_ahead_cancel(imd);
1381 image_post_buffer_set(imd, NULL, NULL);
1382 image_auto_refresh(imd, -1);
1384 g_free(imd->image_path);
1386 g_free(imd->title_right);
1391 static void image_destroy_cb(GtkObject *widget, gpointer data)
1393 ImageWindow *imd = data;
1397 ImageWindow *image_new(gint frame)
1401 imd = g_new0(ImageWindow, 1);
1403 imd->top_window = NULL;
1405 imd->title_right = NULL;
1406 imd->title_show_zoom = FALSE;
1408 imd->unknown = TRUE;
1410 imd->has_frame = frame;
1411 imd->top_window_sync = FALSE;
1413 imd->delay_alter_type = ALTER_NONE;
1415 imd->read_ahead_il = NULL;
1416 imd->read_ahead_pixbuf = NULL;
1417 imd->read_ahead_path = NULL;
1419 imd->completed = FALSE;
1421 imd->auto_refresh_id = -1;
1422 imd->auto_refresh_interval = -1;
1424 imd->delay_flip = FALSE;
1426 imd->func_update = NULL;
1427 imd->func_complete = NULL;
1428 imd->func_tile_request = NULL;
1429 imd->func_tile_dispose = NULL;
1431 imd->func_button = NULL;
1432 imd->func_scroll = NULL;
1434 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1436 image_options_set(imd);
1440 imd->widget = gtk_frame_new(NULL);
1441 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1442 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1443 gtk_widget_show(imd->pr);
1445 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1446 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1447 G_CALLBACK(image_focus_in_cb), imd);
1448 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1449 G_CALLBACK(image_focus_out_cb), imd);
1451 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1452 G_CALLBACK(image_focus_expose), imd);
1456 imd->widget = imd->pr;
1459 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1460 G_CALLBACK(image_click_cb), imd);
1461 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1462 G_CALLBACK(image_scroll_notify_cb), imd);
1464 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1465 G_CALLBACK(image_scroll_cb), imd);
1467 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1468 G_CALLBACK(image_destroy_cb), imd);
1470 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1471 G_CALLBACK(image_zoom_cb), imd);
1472 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1473 G_CALLBACK(image_render_complete_cb), imd);
1475 image_list = g_list_append(image_list, imd);