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 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
462 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
465 image_loader_free(imd->il);
468 image_post_process(imd, TRUE);
470 image_read_ahead_start(imd);
473 static void image_load_error_cb(ImageLoader *il, gpointer data)
475 if (debug) printf ("image error\n");
477 /* even on error handle it like it was done,
478 * since we have a pixbuf with _something_ */
480 image_load_done_cb(il, data);
483 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
484 static void image_load_buffer_throttle(ImageLoader *il)
486 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
488 /* Larger image files usually have larger chunks of data per pixel...
489 * So increase the buffer read size so that the rendering chunks called
493 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
497 /* this read ahead is located here merely for the callbacks, above */
499 static gint image_read_ahead_check(ImageWindow *imd)
501 if (!imd->read_ahead_path) return FALSE;
502 if (imd->il) return FALSE;
504 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
506 image_read_ahead_cancel(imd);
510 if (imd->read_ahead_il)
512 imd->il = imd->read_ahead_il;
513 imd->read_ahead_il = NULL;
515 /* override the old signals */
516 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
517 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
518 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
520 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
521 image_load_buffer_throttle(imd->il);
524 /* do this one directly (probably should add a set func) */
525 imd->il->func_done = image_load_done_cb;
527 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
529 if (!imd->delay_flip)
531 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
534 image_read_ahead_cancel(imd);
537 else if (imd->read_ahead_pixbuf)
539 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
540 g_object_unref(imd->read_ahead_pixbuf);
541 imd->read_ahead_pixbuf = NULL;
543 image_read_ahead_cancel(imd);
545 image_post_process(imd, FALSE);
549 image_read_ahead_cancel(imd);
553 static gint image_load_begin(ImageWindow *imd, const gchar *path)
555 if (debug) printf ("image begin \n");
557 if (imd->il) return FALSE;
559 imd->completed = FALSE;
560 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
562 if (image_post_buffer_get(imd))
564 if (debug) printf("from post buffer: %s\n", imd->image_path);
568 if (image_read_ahead_check(imd))
570 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
574 if (!imd->delay_flip && image_get_pixbuf(imd))
578 pr = PIXBUF_RENDERER(imd->pr);
579 if (pr->pixbuf) g_object_unref(pr->pixbuf);
583 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
585 imd->il = image_loader_new(path);
587 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
588 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
589 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
591 if (!image_loader_start(imd->il, image_load_done_cb, imd))
593 if (debug) printf("image start error\n");
595 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
597 image_loader_free(imd->il);
600 image_complete_util(imd, FALSE);
605 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
606 image_load_buffer_throttle(imd->il);
609 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
614 static void image_reset(ImageWindow *imd)
616 /* stops anything currently being done */
618 if (debug) printf("image reset\n");
620 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
622 image_loader_free(imd->il);
625 imd->delay_alter_type = ALTER_NONE;
629 *-------------------------------------------------------------------
631 *-------------------------------------------------------------------
634 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
638 if (imd->image_path && isfile(imd->image_path))
642 pr = PIXBUF_RENDERER(imd->pr);
643 pr->zoom = zoom; /* store the zoom, needed by the loader */
645 if (image_load_begin(imd, imd->image_path))
647 imd->unknown = FALSE;
653 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
654 image_change_pixbuf(imd, pixbuf, zoom);
655 g_object_unref(pixbuf);
659 imd->size = filesize(imd->image_path);
660 imd->mtime = filetime(imd->image_path);
668 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
669 image_change_pixbuf(imd, pixbuf, zoom);
670 g_object_unref(pixbuf);
671 imd->mtime = filetime(imd->image_path);
675 image_change_pixbuf(imd, NULL, zoom);
682 image_update_util(imd);
685 static void image_change_real(ImageWindow *imd, const gchar *path,
686 CollectionData *cd, CollectInfo *info, gdouble zoom)
689 GdkPixbuf *prev_pixbuf = NULL;
690 gchar *prev_path = NULL;
691 gint prev_clear = FALSE;
693 imd->collection = cd;
694 imd->collection_info = info;
696 pixbuf = image_get_pixbuf(imd);
698 if (enable_read_ahead && imd->image_path && pixbuf)
702 /* current image is not finished */
707 prev_path = g_strdup(imd->image_path);
708 prev_pixbuf = pixbuf;
709 g_object_ref(prev_pixbuf);
713 g_free(imd->image_path);
714 imd->image_path = g_strdup(path);
715 imd->image_name = filename_from_path(imd->image_path);
717 image_change_complete(imd, zoom, TRUE);
721 image_post_buffer_set(imd, prev_path, prev_pixbuf);
723 g_object_unref(prev_pixbuf);
727 image_post_buffer_set(imd, NULL, NULL);
730 image_update_title(imd);
735 *-------------------------------------------------------------------
737 *-------------------------------------------------------------------
740 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
744 widget = imd->widget;
745 if (!widget->window) return;
749 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
750 area, widget, "image_window",
751 widget->allocation.x, widget->allocation.y,
752 widget->allocation.width - 1, widget->allocation.height - 1);
756 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
757 area, widget, "image_window",
758 widget->allocation.x, widget->allocation.y,
759 widget->allocation.width - 1, widget->allocation.height - 1);
763 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
765 ImageWindow *imd = data;
767 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
771 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
773 ImageWindow *imd = data;
775 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
776 image_focus_paint(imd, TRUE, NULL);
781 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
783 ImageWindow *imd = data;
785 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
786 image_focus_paint(imd, FALSE, NULL);
791 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
792 gint relative, gint always)
794 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
797 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
799 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
802 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
804 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
807 void image_overlay_remove(ImageWindow *imd, gint id)
809 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
812 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
814 ImageWindow *imd = data;
816 if (imd->func_scroll &&
817 event && event->type == GDK_SCROLL)
819 imd->func_scroll(imd, event->direction, event->time,
820 event->x, event->y, event->state, imd->data_scroll);
828 *-------------------------------------------------------------------
830 *-------------------------------------------------------------------
833 void image_attach_window(ImageWindow *imd, GtkWidget *window,
834 const gchar *title, const gchar *title_right, gint show_zoom)
836 imd->top_window = window;
838 imd->title = g_strdup(title);
839 g_free(imd->title_right);
840 imd->title_right = g_strdup(title_right);
841 imd->title_show_zoom = show_zoom;
843 if (!fit_window) window = NULL;
845 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
847 image_update_title(imd);
850 void image_set_update_func(ImageWindow *imd,
851 void (*func)(ImageWindow *imd, gpointer data),
854 imd->func_update = func;
855 imd->data_update = data;
858 void image_set_complete_func(ImageWindow *imd,
859 void (*func)(ImageWindow *, gint preload, gpointer),
862 imd->func_complete = func;
863 imd->data_complete = data;
866 void image_set_new_func(ImageWindow *imd,
867 void (*func)(ImageWindow *, gpointer),
870 imd->func_new = func;
871 imd->data_new = data;
875 void image_set_button_func(ImageWindow *imd,
876 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
879 imd->func_button = func;
880 imd->data_button = data;
883 void image_set_scroll_func(ImageWindow *imd,
884 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
887 imd->func_scroll = func;
888 imd->data_scroll = data;
891 void image_set_scroll_notify_func(ImageWindow *imd,
892 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
895 imd->func_scroll_notify = func;
896 imd->data_scroll_notify = data;
901 const gchar *image_get_path(ImageWindow *imd)
903 return imd->image_path;
906 const gchar *image_get_name(ImageWindow *imd)
908 return imd->image_name;
911 /* merely changes path string, does not change the image! */
912 void image_set_path(ImageWindow *imd, const gchar *newpath)
914 g_free(imd->image_path);
915 imd->image_path = g_strdup(newpath);
916 imd->image_name = filename_from_path(imd->image_path);
918 image_update_title(imd);
922 /* load a new image */
924 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
926 if (imd->image_path == path ||
927 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
929 image_change_real(imd, path, NULL, NULL, zoom);
932 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
934 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
937 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
939 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
943 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
945 if (!cd || !info || !g_list_find(cd->list, info)) return;
947 image_change_real(imd, info->path, cd, info, zoom);
950 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
952 if (collection_to_number(imd->collection) >= 0)
954 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
956 if (info) *info = imd->collection_info;
960 if (info) *info = NULL;
962 return imd->collection;
965 if (info) *info = NULL;
969 static void image_loader_sync_data(ImageLoader *il, gpointer data)
971 /* change data for the callbacks directly */
973 il->data_area_ready = data;
974 il->data_error = data;
975 il->data_done = data;
976 il->data_percent = data;
979 /* this is more like a move function
980 * it moves most data from source to imd
982 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
984 if (imd == source) return;
986 imd->unknown = source->unknown;
988 imd->collection = source->collection;
989 imd->collection_info = source->collection_info;
990 imd->size = source->size;
991 imd->mtime = source->mtime;
993 image_set_path(imd, image_get_path(source));
995 image_loader_free(imd->il);
1000 imd->il = source->il;
1003 image_loader_sync_data(imd->il, imd);
1005 imd->delay_alter_type = source->delay_alter_type;
1006 source->delay_alter_type = ALTER_NONE;
1009 image_loader_free(imd->read_ahead_il);
1010 imd->read_ahead_il = source->read_ahead_il;
1011 source->read_ahead_il = NULL;
1012 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1014 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1015 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1016 source->read_ahead_pixbuf = NULL;
1018 g_free(imd->read_ahead_path);
1019 imd->read_ahead_path = source->read_ahead_path;
1020 source->read_ahead_path = NULL;
1022 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1023 imd->prev_pixbuf = source->prev_pixbuf;
1024 source->prev_pixbuf = NULL;
1026 g_free(imd->prev_path);
1027 imd->prev_path = source->prev_path;
1028 source->prev_path = NULL;
1030 imd->completed = source->completed;
1032 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1037 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1039 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1042 void image_reload(ImageWindow *imd)
1044 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1046 image_change_complete(imd, image_zoom_get(imd), FALSE);
1049 void image_scroll(ImageWindow *imd, gint x, gint y)
1051 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1054 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1055 gdouble x_align, gdouble y_align)
1057 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1060 void image_alter(ImageWindow *imd, AlterType type)
1062 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1066 /* still loading, wait till done */
1067 imd->delay_alter_type = type;
1071 image_alter_real(imd, type, TRUE);
1074 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1076 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1079 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1081 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1084 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1086 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1089 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1091 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1094 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1100 pr = (PixbufRenderer *)imd->pr;
1102 if (!pixbuf_renderer_get_pixbuf(pr) ||
1103 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1107 zoom = (gdouble)pr->window_height / height;
1111 zoom = (gdouble)pr->window_width / width;
1116 zoom = 0.0 - 1.0 / zoom;
1119 pixbuf_renderer_zoom_set(pr, zoom);
1122 gdouble image_zoom_get(ImageWindow *imd)
1124 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1127 gdouble image_zoom_get_real(ImageWindow *imd)
1129 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1132 gchar *image_zoom_get_as_text(ImageWindow *imd)
1140 gchar *approx = " ";
1142 zoom = image_zoom_get(imd);
1143 scale = image_zoom_get_real(imd);
1149 else if (zoom < 0.0)
1153 else if (zoom == 0.0 && scale != 0.0)
1166 if (rint(l) != l) pl = 1;
1167 if (rint(r) != r) pr = 1;
1169 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1172 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1176 if (mode == ZOOM_RESET_ORIGINAL)
1180 else if (mode == ZOOM_RESET_FIT_WINDOW)
1188 zoom = image_zoom_get(imd);
1201 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1203 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1207 image_read_ahead_set(imd, path);
1211 image_read_ahead_cancel(imd);
1215 static gint image_auto_refresh_cb(gpointer data)
1217 ImageWindow *imd = data;
1220 if (!imd || !image_get_pixbuf(imd) ||
1221 imd->il || !imd->image_path ||
1222 !update_on_time_change) return TRUE;
1224 newtime = filetime(imd->image_path);
1225 if (newtime > 0 && newtime != imd->mtime)
1227 imd->mtime = newtime;
1234 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1236 void image_auto_refresh(ImageWindow *imd, gint interval)
1239 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1241 if (imd->auto_refresh_id > -1)
1243 g_source_remove(imd->auto_refresh_id);
1244 imd->auto_refresh_id = -1;
1245 imd->auto_refresh_interval = -1;
1248 if (interval < 0) return;
1250 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1252 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1253 imd->auto_refresh_interval = interval;
1256 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1258 imd->top_window_sync = allow_sync;
1260 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1263 void image_background_set_black(ImageWindow *imd, gint black)
1265 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1268 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1270 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1273 void image_set_delay_flip(ImageWindow *imd, gint delay)
1276 imd->delay_flip == delay) return;
1278 imd->delay_flip = delay;
1280 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1282 if (!imd->delay_flip && imd->il)
1286 pr = PIXBUF_RENDERER(imd->pr);
1287 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1290 image_load_pixbuf_ready(imd);
1294 void image_to_root_window(ImageWindow *imd, gint scaled)
1297 GdkWindow *rootwindow;
1305 pixbuf = image_get_pixbuf(imd);
1306 if (!pixbuf) return;
1308 screen = gtk_widget_get_screen(imd->widget);
1309 rootwindow = gdk_screen_get_root_window(screen);
1310 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1314 width = gdk_screen_width();
1315 height = gdk_screen_height();
1319 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1322 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1324 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1325 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1326 gdk_window_clear(rootwindow);
1328 g_object_unref(pixmap);
1334 *-------------------------------------------------------------------
1336 *-------------------------------------------------------------------
1339 static void image_options_set(ImageWindow *imd)
1341 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1342 "zoom_2pass", two_pass_zoom,
1343 "zoom_expand", zoom_to_fit_expands,
1344 "dither_quality", dither_quality,
1345 "scroll_reset", scroll_reset_method,
1346 "cache_display", tile_cache_max,
1347 "window_fit", (imd->top_window_sync && fit_window),
1348 "window_limit", limit_window_size,
1349 "window_limit_value", max_window_size,
1352 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1355 void image_options_sync(void)
1367 image_options_set(imd);
1372 *-------------------------------------------------------------------
1374 *-------------------------------------------------------------------
1377 static void image_free(ImageWindow *imd)
1379 image_list = g_list_remove(image_list, imd);
1383 image_read_ahead_cancel(imd);
1384 image_post_buffer_set(imd, NULL, NULL);
1385 image_auto_refresh(imd, -1);
1387 g_free(imd->image_path);
1389 g_free(imd->title_right);
1394 static void image_destroy_cb(GtkObject *widget, gpointer data)
1396 ImageWindow *imd = data;
1400 ImageWindow *image_new(gint frame)
1404 imd = g_new0(ImageWindow, 1);
1406 imd->top_window = NULL;
1408 imd->title_right = NULL;
1409 imd->title_show_zoom = FALSE;
1411 imd->unknown = TRUE;
1413 imd->has_frame = frame;
1414 imd->top_window_sync = FALSE;
1416 imd->delay_alter_type = ALTER_NONE;
1418 imd->read_ahead_il = NULL;
1419 imd->read_ahead_pixbuf = NULL;
1420 imd->read_ahead_path = NULL;
1422 imd->completed = FALSE;
1424 imd->auto_refresh_id = -1;
1425 imd->auto_refresh_interval = -1;
1427 imd->delay_flip = FALSE;
1429 imd->func_update = NULL;
1430 imd->func_complete = NULL;
1431 imd->func_tile_request = NULL;
1432 imd->func_tile_dispose = NULL;
1434 imd->func_button = NULL;
1435 imd->func_scroll = NULL;
1437 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1439 image_options_set(imd);
1443 imd->widget = gtk_frame_new(NULL);
1444 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1445 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1446 gtk_widget_show(imd->pr);
1448 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1449 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1450 G_CALLBACK(image_focus_in_cb), imd);
1451 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1452 G_CALLBACK(image_focus_out_cb), imd);
1454 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1455 G_CALLBACK(image_focus_expose), imd);
1459 imd->widget = imd->pr;
1462 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1463 G_CALLBACK(image_click_cb), imd);
1464 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1465 G_CALLBACK(image_scroll_notify_cb), imd);
1467 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1468 G_CALLBACK(image_scroll_cb), imd);
1470 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1471 G_CALLBACK(image_destroy_cb), imd);
1473 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1474 G_CALLBACK(image_zoom_cb), imd);
1475 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1476 G_CALLBACK(image_render_complete_cb), imd);
1478 image_list = g_list_append(image_list, imd);