7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
17 #include "image-load.h"
20 #include "pixbuf-renderer.h"
21 #include "pixbuf_util.h"
22 #include "ui_fileops.h"
27 /* size of the image loader buffer (512 bytes x defined number) */
28 #define IMAGE_LOAD_BUFFER_COUNT 8
30 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
31 #define IMAGE_THROTTLE_LARGER_IMAGES 1
33 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
34 #define IMAGE_THROTTLE_FACTOR 4
36 /* the file size at which throttling take place */
37 #define IMAGE_THROTTLE_THRESHOLD 1048576
39 #define IMAGE_AUTO_REFRESH_TIME 3000
43 *-------------------------------------------------------------------
45 *-------------------------------------------------------------------
48 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
50 ImageWindow *imd = data;
54 imd->func_button(imd, event->button, event->time,
55 event->x, event->y, event->state, imd->data_button);
59 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
61 ImageWindow *imd = data;
63 if (imd->func_scroll_notify && pr->scale)
65 imd->func_scroll_notify(imd,
66 (gint)((gdouble)pr->x_scroll / pr->scale),
67 (gint)((gdouble)pr->y_scroll / pr->scale),
68 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
69 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
70 imd->data_scroll_notify);
74 static void image_update_util(ImageWindow *imd)
76 if (imd->func_update) imd->func_update(imd, imd->data_update);
79 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
81 ImageWindow *imd = data;
83 image_update_util(imd);
86 static void image_complete_util(ImageWindow *imd, gint preload)
88 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
90 if (debug) printf("image load completed \"%s\" (%s)\n",
91 (preload) ? imd->read_ahead_path : imd->image_path,
92 (preload) ? "preload" : "current");
94 if (!preload) imd->completed = TRUE;
95 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
98 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
100 ImageWindow *imd = data;
102 image_complete_util(imd, FALSE);
105 static void image_new_util(ImageWindow *imd)
107 if (imd->func_new) imd->func_new(imd, imd->data_new);
111 *-------------------------------------------------------------------
113 *-------------------------------------------------------------------
116 static void image_update_title(ImageWindow *imd)
120 gchar *collection = NULL;
122 if (!imd->top_window) return;
124 if (imd->collection && collection_to_number(imd->collection) >= 0)
127 name = imd->collection->name;
128 if (!name) name = _("Untitled");
129 collection = g_strdup_printf(" (Collection %s)", name);
132 if (imd->title_show_zoom)
134 gchar *buf = image_zoom_get_as_text(imd);
135 zoom = g_strconcat(" [", buf, "]", NULL);
139 title = g_strdup_printf("%s%s%s%s%s%s",
140 imd->title ? imd->title : "",
141 imd->image_name ? imd->image_name : "",
143 collection ? collection : "",
144 imd->image_name ? " - " : "",
145 imd->title_right ? imd->title_right : "");
147 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
155 *-------------------------------------------------------------------
156 * rotation, flip, etc.
157 *-------------------------------------------------------------------
160 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
163 GdkPixbuf *new = NULL;
167 pr = (PixbufRenderer *)imd->pr;
169 imd->delay_alter_type = ALTER_NONE;
171 if (!pr->pixbuf) return;
173 x = pr->x_scroll + (pr->vis_width / 2);
174 y = pr->y_scroll + (pr->vis_height / 2);
178 case ALTER_ROTATE_90:
179 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
184 case ALTER_ROTATE_90_CC:
185 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
190 case ALTER_ROTATE_180:
191 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
196 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
200 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
211 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
214 if (clamp && pr->zoom != 0.0)
216 pixbuf_renderer_scroll(pr, x - (pr->vis_width / 2), y - (pr->vis_height / 2));
220 static void image_post_process(ImageWindow *imd, gint clamp)
222 if (exif_rotate_enable && image_get_pixbuf(imd))
227 ed = exif_read(imd->image_path);
228 if (ed && exif_get_integer(ed, "Orientation", &orientation))
230 /* see http://jpegclub.org/exif_orientation.html
233 888888 888888 88 88 8888888888 88 88 8888888888
234 88 88 88 88 88 88 88 88 88 88 88 88
235 8888 8888 8888 8888 88 8888888888 8888888888 88
242 case EXIF_ORIENTATION_TOP_LEFT:
243 /* normal -- nothing to do */
245 case EXIF_ORIENTATION_TOP_RIGHT:
247 imd->delay_alter_type = ALTER_MIRROR;
249 case EXIF_ORIENTATION_BOTTOM_RIGHT:
251 imd->delay_alter_type = ALTER_ROTATE_180;
253 case EXIF_ORIENTATION_BOTTOM_LEFT:
255 imd->delay_alter_type = ALTER_FLIP;
257 case EXIF_ORIENTATION_LEFT_TOP:
258 /* not implemented -- too wacky to fix in one step */
260 case EXIF_ORIENTATION_RIGHT_TOP:
261 /* rotated -90 (270) */
262 imd->delay_alter_type = ALTER_ROTATE_90;
264 case EXIF_ORIENTATION_RIGHT_BOTTOM:
265 /* not implemented -- too wacky to fix in one step */
267 case EXIF_ORIENTATION_LEFT_BOTTOM:
269 imd->delay_alter_type = ALTER_ROTATE_90_CC;
272 /* The other values are out of range */
279 if (imd->delay_alter_type != ALTER_NONE)
281 image_alter_real(imd, imd->delay_alter_type, clamp);
286 *-------------------------------------------------------------------
287 * read ahead (prebuffer)
288 *-------------------------------------------------------------------
291 static void image_read_ahead_cancel(ImageWindow *imd)
293 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
295 image_loader_free(imd->read_ahead_il);
296 imd->read_ahead_il = NULL;
298 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
299 imd->read_ahead_pixbuf = NULL;
301 g_free(imd->read_ahead_path);
302 imd->read_ahead_path = NULL;
305 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
307 ImageWindow *imd = data;
309 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
311 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
312 if (imd->read_ahead_pixbuf)
314 g_object_ref(imd->read_ahead_pixbuf);
318 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
320 image_loader_free(imd->read_ahead_il);
321 imd->read_ahead_il = NULL;
323 image_complete_util(imd, TRUE);
326 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
328 /* we even treat errors as success, maybe at least some of the file was ok */
329 image_read_ahead_done_cb(il, data);
332 static void image_read_ahead_start(ImageWindow *imd)
334 /* already started ? */
335 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
337 /* still loading ?, do later */
340 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
342 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
344 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
345 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
347 image_read_ahead_cancel(imd);
348 image_complete_util(imd, TRUE);
352 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
354 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
356 image_read_ahead_cancel(imd);
358 imd->read_ahead_path = g_strdup(path);
360 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
362 image_read_ahead_start(imd);
366 *-------------------------------------------------------------------
368 *-------------------------------------------------------------------
371 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
373 g_free(imd->prev_path);
374 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
378 imd->prev_path = g_strdup(path);
380 g_object_ref(pixbuf);
381 imd->prev_pixbuf = pixbuf;
385 imd->prev_path = NULL;
386 imd->prev_pixbuf = NULL;
389 if (debug) printf("post buffer set: %s\n", path);
392 static gint image_post_buffer_get(ImageWindow *imd)
396 if (imd->prev_pixbuf &&
397 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
399 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
407 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
408 imd->prev_pixbuf = NULL;
410 g_free(imd->prev_path);
411 imd->prev_path = NULL;
417 *-------------------------------------------------------------------
419 *-------------------------------------------------------------------
422 static void image_load_pixbuf_ready(ImageWindow *imd)
424 if (image_get_pixbuf(imd) || !imd->il) return;
426 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
429 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
431 ImageWindow *imd = data;
434 pr = (PixbufRenderer *)imd->pr;
436 if (imd->delay_flip &&
437 pr->pixbuf != image_loader_get_pixbuf(il))
442 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
444 pixbuf_renderer_area_changed(pr, x, y, w, h);
447 static void image_load_done_cb(ImageLoader *il, gpointer data)
449 ImageWindow *imd = data;
451 if (debug) printf ("image done\n");
453 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
455 if (imd->delay_flip &&
456 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
458 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
461 image_loader_free(imd->il);
464 image_post_process(imd, TRUE);
466 image_read_ahead_start(imd);
469 static void image_load_error_cb(ImageLoader *il, gpointer data)
471 if (debug) printf ("image error\n");
473 /* even on error handle it like it was done,
474 * since we have a pixbuf with _something_ */
476 image_load_done_cb(il, data);
479 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
480 static void image_load_buffer_throttle(ImageLoader *il)
482 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
484 /* Larger image files usually have larger chunks of data per pixel...
485 * So increase the buffer read size so that the rendering chunks called
489 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
493 /* this read ahead is located here merely for the callbacks, above */
495 static gint image_read_ahead_check(ImageWindow *imd)
497 if (!imd->read_ahead_path) return FALSE;
498 if (imd->il) return FALSE;
500 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
502 image_read_ahead_cancel(imd);
506 if (imd->read_ahead_il)
508 imd->il = imd->read_ahead_il;
509 imd->read_ahead_il = NULL;
511 /* override the old signals */
512 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
513 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
514 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
516 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
517 image_load_buffer_throttle(imd->il);
520 /* do this one directly (probably should add a set func) */
521 imd->il->func_done = image_load_done_cb;
523 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
525 if (!imd->delay_flip)
527 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
530 image_read_ahead_cancel(imd);
533 else if (imd->read_ahead_pixbuf)
535 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
536 g_object_unref(imd->read_ahead_pixbuf);
537 imd->read_ahead_pixbuf = NULL;
539 image_read_ahead_cancel(imd);
541 image_post_process(imd, FALSE);
545 image_read_ahead_cancel(imd);
549 static gint image_load_begin(ImageWindow *imd, const gchar *path)
551 if (debug) printf ("image begin \n");
553 if (imd->il) return FALSE;
555 imd->completed = FALSE;
556 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
558 if (image_post_buffer_get(imd))
560 if (debug) printf("from post buffer: %s\n", imd->image_path);
564 if (image_read_ahead_check(imd))
566 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
570 if (!imd->delay_flip && image_get_pixbuf(imd))
574 pr = PIXBUF_RENDERER(imd->pr);
575 if (pr->pixbuf) g_object_unref(pr->pixbuf);
579 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
581 imd->il = image_loader_new(path);
583 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
584 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
585 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
587 if (!image_loader_start(imd->il, image_load_done_cb, imd))
589 if (debug) printf("image start error\n");
591 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
593 image_loader_free(imd->il);
596 image_complete_util(imd, FALSE);
601 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
602 image_load_buffer_throttle(imd->il);
605 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
610 static void image_reset(ImageWindow *imd)
612 /* stops anything currently being done */
614 if (debug) printf("image reset\n");
616 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
618 image_loader_free(imd->il);
621 imd->delay_alter_type = ALTER_NONE;
625 *-------------------------------------------------------------------
627 *-------------------------------------------------------------------
630 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
634 if (imd->image_path && isfile(imd->image_path))
638 pr = PIXBUF_RENDERER(imd->pr);
639 pr->zoom = zoom; /* store the zoom, needed by the loader */
641 if (image_load_begin(imd, imd->image_path))
643 imd->unknown = FALSE;
649 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
650 image_change_pixbuf(imd, pixbuf, zoom);
651 g_object_unref(pixbuf);
655 imd->size = filesize(imd->image_path);
656 imd->mtime = filetime(imd->image_path);
664 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
665 image_change_pixbuf(imd, pixbuf, zoom);
666 g_object_unref(pixbuf);
667 imd->mtime = filetime(imd->image_path);
671 image_change_pixbuf(imd, NULL, zoom);
678 image_update_util(imd);
681 static void image_change_real(ImageWindow *imd, const gchar *path,
682 CollectionData *cd, CollectInfo *info, gdouble zoom)
685 GdkPixbuf *prev_pixbuf = NULL;
686 gchar *prev_path = NULL;
687 gint prev_clear = FALSE;
689 imd->collection = cd;
690 imd->collection_info = info;
692 pixbuf = image_get_pixbuf(imd);
694 if (enable_read_ahead && imd->image_path && pixbuf)
698 /* current image is not finished */
703 prev_path = g_strdup(imd->image_path);
704 prev_pixbuf = pixbuf;
705 g_object_ref(prev_pixbuf);
709 g_free(imd->image_path);
710 imd->image_path = g_strdup(path);
711 imd->image_name = filename_from_path(imd->image_path);
713 image_change_complete(imd, zoom, TRUE);
717 image_post_buffer_set(imd, prev_path, prev_pixbuf);
719 g_object_unref(prev_pixbuf);
723 image_post_buffer_set(imd, NULL, NULL);
726 image_update_title(imd);
731 *-------------------------------------------------------------------
733 *-------------------------------------------------------------------
736 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
740 widget = imd->widget;
741 if (!widget->window) return;
745 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
746 area, widget, "image_window",
747 widget->allocation.x, widget->allocation.y,
748 widget->allocation.width - 1, widget->allocation.height - 1);
752 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
753 area, widget, "image_window",
754 widget->allocation.x, widget->allocation.y,
755 widget->allocation.width - 1, widget->allocation.height - 1);
759 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
761 ImageWindow *imd = data;
763 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
767 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
769 ImageWindow *imd = data;
771 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
772 image_focus_paint(imd, TRUE, NULL);
777 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
779 ImageWindow *imd = data;
781 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
782 image_focus_paint(imd, FALSE, NULL);
787 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
788 gint relative, gint always)
790 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
793 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
795 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
798 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
800 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
803 void image_overlay_remove(ImageWindow *imd, gint id)
805 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
808 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
810 ImageWindow *imd = data;
812 if (imd->func_scroll &&
813 event && event->type == GDK_SCROLL)
815 imd->func_scroll(imd, event->direction, event->time,
816 event->x, event->y, event->state, imd->data_scroll);
824 *-------------------------------------------------------------------
826 *-------------------------------------------------------------------
829 void image_attach_window(ImageWindow *imd, GtkWidget *window,
830 const gchar *title, const gchar *title_right, gint show_zoom)
832 imd->top_window = window;
834 imd->title = g_strdup(title);
835 g_free(imd->title_right);
836 imd->title_right = g_strdup(title_right);
837 imd->title_show_zoom = show_zoom;
839 if (!fit_window) window = NULL;
841 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
843 image_update_title(imd);
846 void image_set_update_func(ImageWindow *imd,
847 void (*func)(ImageWindow *imd, gpointer data),
850 imd->func_update = func;
851 imd->data_update = data;
854 void image_set_complete_func(ImageWindow *imd,
855 void (*func)(ImageWindow *, gint preload, gpointer),
858 imd->func_complete = func;
859 imd->data_complete = data;
862 void image_set_new_func(ImageWindow *imd,
863 void (*func)(ImageWindow *, gpointer),
866 imd->func_new = func;
867 imd->data_new = data;
871 void image_set_button_func(ImageWindow *imd,
872 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
875 imd->func_button = func;
876 imd->data_button = data;
879 void image_set_scroll_func(ImageWindow *imd,
880 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
883 imd->func_scroll = func;
884 imd->data_scroll = data;
887 void image_set_scroll_notify_func(ImageWindow *imd,
888 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
891 imd->func_scroll_notify = func;
892 imd->data_scroll_notify = data;
897 const gchar *image_get_path(ImageWindow *imd)
899 return imd->image_path;
902 const gchar *image_get_name(ImageWindow *imd)
904 return imd->image_name;
907 /* merely changes path string, does not change the image! */
908 void image_set_path(ImageWindow *imd, const gchar *newpath)
910 g_free(imd->image_path);
911 imd->image_path = g_strdup(newpath);
912 imd->image_name = filename_from_path(imd->image_path);
914 image_update_title(imd);
918 /* load a new image */
920 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
922 if (imd->image_path == path ||
923 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
925 image_change_real(imd, path, NULL, NULL, zoom);
928 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
930 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
933 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
935 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
939 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
941 if (!cd || !info || !g_list_find(cd->list, info)) return;
943 image_change_real(imd, info->path, cd, info, zoom);
946 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
948 if (collection_to_number(imd->collection) >= 0)
950 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
952 if (info) *info = imd->collection_info;
956 if (info) *info = NULL;
958 return imd->collection;
961 if (info) *info = NULL;
965 static void image_loader_sync_data(ImageLoader *il, gpointer data)
967 /* change data for the callbacks directly */
969 il->data_area_ready = data;
970 il->data_error = data;
971 il->data_done = data;
972 il->data_percent = data;
975 /* this is more like a move function
976 * it moves most data from source to imd
978 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
980 if (imd == source) return;
982 imd->unknown = source->unknown;
984 imd->collection = source->collection;
985 imd->collection_info = source->collection_info;
986 imd->size = source->size;
987 imd->mtime = source->mtime;
989 image_set_path(imd, image_get_path(source));
991 image_loader_free(imd->il);
996 imd->il = source->il;
999 image_loader_sync_data(imd->il, imd);
1001 imd->delay_alter_type = source->delay_alter_type;
1002 source->delay_alter_type = ALTER_NONE;
1005 image_loader_free(imd->read_ahead_il);
1006 imd->read_ahead_il = source->read_ahead_il;
1007 source->read_ahead_il = NULL;
1008 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1010 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1011 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1012 source->read_ahead_pixbuf = NULL;
1014 g_free(imd->read_ahead_path);
1015 imd->read_ahead_path = source->read_ahead_path;
1016 source->read_ahead_path = NULL;
1018 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1019 imd->prev_pixbuf = source->prev_pixbuf;
1020 source->prev_pixbuf = NULL;
1022 g_free(imd->prev_path);
1023 imd->prev_path = source->prev_path;
1024 source->prev_path = NULL;
1026 imd->completed = source->completed;
1028 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1033 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1035 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1038 void image_reload(ImageWindow *imd)
1040 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1042 image_change_complete(imd, image_zoom_get(imd), FALSE);
1045 void image_scroll(ImageWindow *imd, gint x, gint y)
1047 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1050 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1051 gdouble x_align, gdouble y_align)
1053 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1056 void image_alter(ImageWindow *imd, AlterType type)
1058 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1062 /* still loading, wait till done */
1063 imd->delay_alter_type = type;
1067 image_alter_real(imd, type, TRUE);
1070 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1072 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1075 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1077 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1080 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1082 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1085 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1087 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1090 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1096 pr = (PixbufRenderer *)imd->pr;
1098 if (!pixbuf_renderer_get_pixbuf(pr) ||
1099 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1103 zoom = (gdouble)pr->window_height / height;
1107 zoom = (gdouble)pr->window_width / width;
1112 zoom = 0.0 - 1.0 / zoom;
1115 pixbuf_renderer_zoom_set(pr, zoom);
1118 gdouble image_zoom_get(ImageWindow *imd)
1120 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1123 gdouble image_zoom_get_real(ImageWindow *imd)
1125 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1128 gchar *image_zoom_get_as_text(ImageWindow *imd)
1136 gchar *approx = " ";
1138 zoom = image_zoom_get(imd);
1139 scale = image_zoom_get_real(imd);
1145 else if (zoom < 0.0)
1149 else if (zoom == 0.0 && scale != 0.0)
1162 if (rint(l) != l) pl = 1;
1163 if (rint(r) != r) pr = 1;
1165 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1168 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1172 if (mode == ZOOM_RESET_ORIGINAL)
1176 else if (mode == ZOOM_RESET_FIT_WINDOW)
1184 zoom = image_zoom_get(imd);
1197 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1199 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1203 image_read_ahead_set(imd, path);
1207 image_read_ahead_cancel(imd);
1211 static gint image_auto_refresh_cb(gpointer data)
1213 ImageWindow *imd = data;
1216 if (!imd || !image_get_pixbuf(imd) ||
1217 imd->il || !imd->image_path ||
1218 !update_on_time_change) return TRUE;
1220 newtime = filetime(imd->image_path);
1221 if (newtime > 0 && newtime != imd->mtime)
1223 imd->mtime = newtime;
1230 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1232 void image_auto_refresh(ImageWindow *imd, gint interval)
1235 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1237 if (imd->auto_refresh_id > -1)
1239 g_source_remove(imd->auto_refresh_id);
1240 imd->auto_refresh_id = -1;
1241 imd->auto_refresh_interval = -1;
1244 if (interval < 0) return;
1246 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1248 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1249 imd->auto_refresh_interval = interval;
1252 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1254 imd->top_window_sync = allow_sync;
1256 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1259 void image_background_set_black(ImageWindow *imd, gint black)
1261 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1264 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1266 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1269 void image_set_delay_flip(ImageWindow *imd, gint delay)
1272 imd->delay_flip == delay) return;
1274 imd->delay_flip = delay;
1276 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1278 if (!imd->delay_flip && imd->il)
1282 pr = PIXBUF_RENDERER(imd->pr);
1283 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1286 image_load_pixbuf_ready(imd);
1290 void image_to_root_window(ImageWindow *imd, gint scaled)
1293 GdkWindow *rootwindow;
1301 pixbuf = image_get_pixbuf(imd);
1302 if (!pixbuf) return;
1304 screen = gtk_widget_get_screen(imd->widget);
1305 rootwindow = gdk_screen_get_root_window(screen);
1306 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1310 width = gdk_screen_width();
1311 height = gdk_screen_height();
1315 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1318 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1320 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1321 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1322 gdk_window_clear(rootwindow);
1324 g_object_unref(pixmap);
1330 *-------------------------------------------------------------------
1332 *-------------------------------------------------------------------
1335 static void image_free(ImageWindow *imd)
1339 image_read_ahead_cancel(imd);
1340 image_post_buffer_set(imd, NULL, NULL);
1341 image_auto_refresh(imd, -1);
1343 g_free(imd->image_path);
1345 g_free(imd->title_right);
1350 static void image_destroy_cb(GtkObject *widget, gpointer data)
1352 ImageWindow *imd = data;
1356 ImageWindow *image_new(gint frame)
1360 imd = g_new0(ImageWindow, 1);
1362 imd->top_window = NULL;
1364 imd->title_right = NULL;
1365 imd->title_show_zoom = FALSE;
1367 imd->unknown = TRUE;
1369 imd->has_frame = frame;
1370 imd->top_window_sync = FALSE;
1372 imd->delay_alter_type = ALTER_NONE;
1374 imd->read_ahead_il = NULL;
1375 imd->read_ahead_pixbuf = NULL;
1376 imd->read_ahead_path = NULL;
1378 imd->completed = FALSE;
1380 imd->auto_refresh_id = -1;
1381 imd->auto_refresh_interval = -1;
1383 imd->delay_flip = FALSE;
1385 imd->func_update = NULL;
1386 imd->func_complete = NULL;
1387 imd->func_tile_request = NULL;
1388 imd->func_tile_dispose = NULL;
1390 imd->func_button = NULL;
1391 imd->func_scroll = NULL;
1393 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1395 g_object_set(G_OBJECT(imd->pr), "zoom_2pass", TRUE, NULL);
1399 imd->widget = gtk_frame_new(NULL);
1400 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1401 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1402 gtk_widget_show(imd->pr);
1404 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1405 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1406 G_CALLBACK(image_focus_in_cb), imd);
1407 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1408 G_CALLBACK(image_focus_out_cb), imd);
1410 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1411 G_CALLBACK(image_focus_expose), imd);
1415 imd->widget = imd->pr;
1418 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1419 G_CALLBACK(image_click_cb), imd);
1420 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1421 G_CALLBACK(image_scroll_notify_cb), imd);
1423 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1424 G_CALLBACK(image_scroll_cb), imd);
1426 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1427 G_CALLBACK(image_destroy_cb), imd);
1429 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1430 G_CALLBACK(image_zoom_cb), imd);
1431 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1432 G_CALLBACK(image_render_complete_cb), imd);