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"
19 #include "color-man.h"
21 #include "pixbuf-renderer.h"
22 #include "pixbuf_util.h"
23 #include "ui_fileops.h"
28 /* size of the image loader buffer (512 bytes x defined number) */
29 #define IMAGE_LOAD_BUFFER_COUNT 8
31 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
32 #define IMAGE_THROTTLE_LARGER_IMAGES 1
34 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
35 #define IMAGE_THROTTLE_FACTOR 4
37 /* the file size at which throttling take place */
38 #define IMAGE_THROTTLE_THRESHOLD 1048576
40 #define IMAGE_AUTO_REFRESH_TIME 3000
43 static GList *image_list = NULL;
46 static void image_update_title(ImageWindow *imd);
47 static void image_post_process(ImageWindow *imd, gint clamp);
50 *-------------------------------------------------------------------
52 *-------------------------------------------------------------------
55 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
57 ImageWindow *imd = data;
61 imd->func_button(imd, event->button, event->time,
62 event->x, event->y, event->state, imd->data_button);
66 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
68 ImageWindow *imd = data;
70 if (imd->func_scroll_notify && pr->scale)
72 imd->func_scroll_notify(imd,
73 (gint)((gdouble)pr->x_scroll / pr->scale),
74 (gint)((gdouble)pr->y_scroll / pr->scale),
75 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
76 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
77 imd->data_scroll_notify);
81 static void image_update_util(ImageWindow *imd)
83 if (imd->func_update) imd->func_update(imd, imd->data_update);
86 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
88 ImageWindow *imd = data;
90 if (imd->title_show_zoom) image_update_title(imd);
91 image_update_util(imd);
94 static void image_complete_util(ImageWindow *imd, gint preload)
96 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
98 if (debug) printf("image load completed \"%s\" (%s)\n",
99 (preload) ? imd->read_ahead_path : imd->image_path,
100 (preload) ? "preload" : "current");
102 if (!preload) imd->completed = TRUE;
103 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
106 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
108 ImageWindow *imd = data;
110 image_complete_util(imd, FALSE);
113 static void image_new_util(ImageWindow *imd)
115 if (imd->func_new) imd->func_new(imd, imd->data_new);
119 *-------------------------------------------------------------------
121 *-------------------------------------------------------------------
124 static void image_update_title(ImageWindow *imd)
128 gchar *collection = NULL;
130 if (!imd->top_window) return;
132 if (imd->collection && collection_to_number(imd->collection) >= 0)
135 name = imd->collection->name;
136 if (!name) name = _("Untitled");
137 collection = g_strdup_printf(" (Collection %s)", name);
140 if (imd->title_show_zoom)
142 gchar *buf = image_zoom_get_as_text(imd);
143 zoom = g_strconcat(" [", buf, "]", NULL);
147 title = g_strdup_printf("%s%s%s%s%s%s",
148 imd->title ? imd->title : "",
149 imd->image_name ? imd->image_name : "",
151 collection ? collection : "",
152 imd->image_name ? " - " : "",
153 imd->title_right ? imd->title_right : "");
155 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
163 *-------------------------------------------------------------------
164 * rotation, flip, etc.
165 *-------------------------------------------------------------------
168 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp, gint exif_rotated)
171 GdkPixbuf *new = NULL;
175 pr = (PixbufRenderer *)imd->pr;
177 imd->delay_alter_type = ALTER_NONE;
179 if (!pr->pixbuf) return;
181 x = pr->x_scroll + (pr->vis_width / 2);
182 y = pr->y_scroll + (pr->vis_height / 2);
186 case ALTER_ROTATE_90:
187 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
192 case ALTER_ROTATE_90_CC:
193 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
198 case ALTER_ROTATE_180:
199 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
204 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
208 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
211 case ALTER_DESATURATE:
212 pixbuf_desaturate_rect(pr->pixbuf,
213 0, 0, pr->image_width, pr->image_height);
214 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
224 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
227 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
231 switch (pr->scroll_reset)
233 case PR_SCROLL_RESET_NOCHANGE:
235 case PR_SCROLL_RESET_CENTER:
236 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
237 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
239 case PR_SCROLL_RESET_TOPLEFT:
246 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
247 (gint)((gdouble)y / pr->scale),
252 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
254 ImageWindow *imd = data;
256 color_man_free((ColorMan *)imd->cm);
258 imd->state |= IMAGE_STATE_COLOR_ADJ;
260 if (type != COLOR_RETURN_IMAGE_CHANGED)
262 image_post_process(imd, FALSE);
266 static gint image_post_process_color(ImageWindow *imd, gint start_row)
269 ColorManProfileType input_type;
270 ColorManProfileType screen_type;
271 const gchar *input_file;
272 const gchar *screen_file;
274 if (imd->cm) return FALSE;
276 if (imd->color_profile_input >= 1 &&
277 imd->color_profile_input <= COLOR_PROFILE_INPUTS)
281 n = imd->color_profile_input - 1;
282 if (!color_profile_input_file[n]) return FALSE;
284 input_type = COLOR_PROFILE_FILE;
285 input_file = color_profile_input_file[n];
287 else if (imd->color_profile_input == 0)
289 input_type = COLOR_PROFILE_SRGB;
297 if (imd->color_profile_screen == 1 &&
298 color_profile_screen_file)
300 screen_type = COLOR_PROFILE_FILE;
301 screen_file = color_profile_screen_file;
303 else if (imd->color_profile_screen == 0)
305 screen_type = COLOR_PROFILE_SRGB;
313 cm = color_man_new(imd,
314 input_type, input_file,
315 screen_type, screen_file,
316 image_post_process_color_cb, imd);
319 if (start_row > 0) cm->row = start_row;
321 imd->cm = (gpointer)cm;
328 static void image_post_process(ImageWindow *imd, gint clamp)
330 gint exif_rotated = FALSE;
332 if (imd->color_profile_enable &&
333 !(imd->state & IMAGE_STATE_COLOR_ADJ))
335 if (image_post_process_color(imd, 0)) return;
337 /* fixme: note error to user */
338 imd->state |= IMAGE_STATE_COLOR_ADJ;
341 if (exif_rotate_enable && image_get_pixbuf(imd))
346 ed = exif_read(imd->image_path);
347 if (ed && exif_get_integer(ed, "Orientation", &orientation))
349 /* see http://jpegclub.org/exif_orientation.html
352 888888 888888 88 88 8888888888 88 88 8888888888
353 88 88 88 88 88 88 88 88 88 88 88 88
354 8888 8888 8888 8888 88 8888888888 8888888888 88
361 case EXIF_ORIENTATION_TOP_LEFT:
362 /* normal -- nothing to do */
364 case EXIF_ORIENTATION_TOP_RIGHT:
366 imd->delay_alter_type = ALTER_MIRROR;
369 case EXIF_ORIENTATION_BOTTOM_RIGHT:
371 imd->delay_alter_type = ALTER_ROTATE_180;
374 case EXIF_ORIENTATION_BOTTOM_LEFT:
376 imd->delay_alter_type = ALTER_FLIP;
379 case EXIF_ORIENTATION_LEFT_TOP:
380 /* not implemented -- too wacky to fix in one step */
382 case EXIF_ORIENTATION_RIGHT_TOP:
383 /* rotated -90 (270) */
384 imd->delay_alter_type = ALTER_ROTATE_90;
387 case EXIF_ORIENTATION_RIGHT_BOTTOM:
388 /* not implemented -- too wacky to fix in one step */
390 case EXIF_ORIENTATION_LEFT_BOTTOM:
392 imd->delay_alter_type = ALTER_ROTATE_90_CC;
396 /* The other values are out of range */
403 if (imd->delay_alter_type != ALTER_NONE)
405 image_alter_real(imd, imd->delay_alter_type, clamp, exif_rotated);
410 *-------------------------------------------------------------------
411 * read ahead (prebuffer)
412 *-------------------------------------------------------------------
415 static void image_read_ahead_cancel(ImageWindow *imd)
417 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
419 image_loader_free(imd->read_ahead_il);
420 imd->read_ahead_il = NULL;
422 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
423 imd->read_ahead_pixbuf = NULL;
425 g_free(imd->read_ahead_path);
426 imd->read_ahead_path = NULL;
429 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
431 ImageWindow *imd = data;
433 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
435 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
436 if (imd->read_ahead_pixbuf)
438 g_object_ref(imd->read_ahead_pixbuf);
442 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
444 image_loader_free(imd->read_ahead_il);
445 imd->read_ahead_il = NULL;
447 image_complete_util(imd, TRUE);
450 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
452 /* we even treat errors as success, maybe at least some of the file was ok */
453 image_read_ahead_done_cb(il, data);
456 static void image_read_ahead_start(ImageWindow *imd)
458 /* already started ? */
459 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
461 /* still loading ?, do later */
464 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
466 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
468 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
469 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
471 image_read_ahead_cancel(imd);
472 image_complete_util(imd, TRUE);
476 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
478 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
480 image_read_ahead_cancel(imd);
482 imd->read_ahead_path = g_strdup(path);
484 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
486 image_read_ahead_start(imd);
490 *-------------------------------------------------------------------
492 *-------------------------------------------------------------------
495 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf, gint color_row)
497 g_free(imd->prev_path);
498 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
502 imd->prev_path = g_strdup(path);
504 g_object_ref(pixbuf);
505 imd->prev_pixbuf = pixbuf;
506 imd->prev_color_row = color_row;
510 imd->prev_path = NULL;
511 imd->prev_pixbuf = NULL;
512 imd->prev_color_row = -1;
515 if (debug) printf("post buffer set: %s\n", path);
518 static gint image_post_buffer_get(ImageWindow *imd)
522 if (imd->prev_pixbuf &&
523 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
525 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
526 if (imd->prev_color_row >= 0)
528 image_post_process_color(imd, imd->prev_color_row);
537 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
538 imd->prev_pixbuf = NULL;
540 g_free(imd->prev_path);
541 imd->prev_path = NULL;
547 *-------------------------------------------------------------------
549 *-------------------------------------------------------------------
552 static void image_load_pixbuf_ready(ImageWindow *imd)
554 if (image_get_pixbuf(imd) || !imd->il) return;
556 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
559 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
561 ImageWindow *imd = data;
564 pr = (PixbufRenderer *)imd->pr;
566 if (imd->delay_flip &&
567 pr->pixbuf != image_loader_get_pixbuf(il))
572 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
574 pixbuf_renderer_area_changed(pr, x, y, w, h);
577 static void image_load_done_cb(ImageLoader *il, gpointer data)
579 ImageWindow *imd = data;
581 if (debug) printf ("image done\n");
583 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
585 if (imd->delay_flip &&
586 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
588 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
589 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
592 image_loader_free(imd->il);
595 image_post_process(imd, TRUE);
597 image_read_ahead_start(imd);
600 static void image_load_error_cb(ImageLoader *il, gpointer data)
602 if (debug) printf ("image error\n");
604 /* even on error handle it like it was done,
605 * since we have a pixbuf with _something_ */
607 image_load_done_cb(il, data);
610 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
611 static void image_load_buffer_throttle(ImageLoader *il)
613 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
615 /* Larger image files usually have larger chunks of data per pixel...
616 * So increase the buffer read size so that the rendering chunks called
620 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
624 /* this read ahead is located here merely for the callbacks, above */
626 static gint image_read_ahead_check(ImageWindow *imd)
628 if (!imd->read_ahead_path) return FALSE;
629 if (imd->il) return FALSE;
631 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
633 image_read_ahead_cancel(imd);
637 if (imd->read_ahead_il)
639 imd->il = imd->read_ahead_il;
640 imd->read_ahead_il = NULL;
642 /* override the old signals */
643 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
644 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
645 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
647 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
648 image_load_buffer_throttle(imd->il);
651 /* do this one directly (probably should add a set func) */
652 imd->il->func_done = image_load_done_cb;
654 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
656 if (!imd->delay_flip)
658 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
661 image_read_ahead_cancel(imd);
664 else if (imd->read_ahead_pixbuf)
666 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
667 g_object_unref(imd->read_ahead_pixbuf);
668 imd->read_ahead_pixbuf = NULL;
670 image_read_ahead_cancel(imd);
672 image_post_process(imd, FALSE);
676 image_read_ahead_cancel(imd);
680 static gint image_load_begin(ImageWindow *imd, const gchar *path)
682 if (debug) printf ("image begin \n");
684 if (imd->il) return FALSE;
686 imd->completed = FALSE;
687 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
689 if (image_post_buffer_get(imd))
691 if (debug) printf("from post buffer: %s\n", imd->image_path);
695 if (image_read_ahead_check(imd))
697 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
701 if (!imd->delay_flip && image_get_pixbuf(imd))
705 pr = PIXBUF_RENDERER(imd->pr);
706 if (pr->pixbuf) g_object_unref(pr->pixbuf);
710 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
712 imd->il = image_loader_new(path);
714 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
715 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
716 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
718 if (!image_loader_start(imd->il, image_load_done_cb, imd))
720 if (debug) printf("image start error\n");
722 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
724 image_loader_free(imd->il);
727 image_complete_util(imd, FALSE);
732 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
733 image_load_buffer_throttle(imd->il);
736 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
741 static void image_reset(ImageWindow *imd)
743 /* stops anything currently being done */
745 if (debug) printf("image reset\n");
747 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
749 image_loader_free(imd->il);
752 color_man_free((ColorMan *)imd->cm);
755 imd->delay_alter_type = ALTER_NONE;
757 imd->state = IMAGE_STATE_NONE;
761 *-------------------------------------------------------------------
763 *-------------------------------------------------------------------
766 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
770 if (imd->image_path && isfile(imd->image_path))
774 pr = PIXBUF_RENDERER(imd->pr);
775 pr->zoom = zoom; /* store the zoom, needed by the loader */
777 if (image_load_begin(imd, imd->image_path))
779 imd->unknown = FALSE;
785 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
786 image_change_pixbuf(imd, pixbuf, zoom);
787 g_object_unref(pixbuf);
791 imd->size = filesize(imd->image_path);
792 imd->mtime = filetime(imd->image_path);
800 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
801 image_change_pixbuf(imd, pixbuf, zoom);
802 g_object_unref(pixbuf);
803 imd->mtime = filetime(imd->image_path);
807 image_change_pixbuf(imd, NULL, zoom);
814 image_update_util(imd);
817 static void image_change_real(ImageWindow *imd, const gchar *path,
818 CollectionData *cd, CollectInfo *info, gdouble zoom)
821 GdkPixbuf *prev_pixbuf = NULL;
822 gchar *prev_path = NULL;
823 gint prev_clear = FALSE;
824 gint prev_color_row = -1;
826 imd->collection = cd;
827 imd->collection_info = info;
829 pixbuf = image_get_pixbuf(imd);
831 if (enable_read_ahead && imd->image_path && pixbuf)
835 /* current image is not finished */
840 prev_path = g_strdup(imd->image_path);
841 prev_pixbuf = pixbuf;
842 g_object_ref(prev_pixbuf);
848 cm = (ColorMan *)imd->cm;
849 prev_color_row = cm->row;
854 g_free(imd->image_path);
855 imd->image_path = g_strdup(path);
856 imd->image_name = filename_from_path(imd->image_path);
858 image_change_complete(imd, zoom, TRUE);
862 image_post_buffer_set(imd, prev_path, prev_pixbuf, prev_color_row);
864 g_object_unref(prev_pixbuf);
868 image_post_buffer_set(imd, NULL, NULL, -1);
871 image_update_title(imd);
876 *-------------------------------------------------------------------
878 *-------------------------------------------------------------------
881 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
885 widget = imd->widget;
886 if (!widget->window) return;
890 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
891 area, widget, "image_window",
892 widget->allocation.x, widget->allocation.y,
893 widget->allocation.width - 1, widget->allocation.height - 1);
897 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
898 area, widget, "image_window",
899 widget->allocation.x, widget->allocation.y,
900 widget->allocation.width - 1, widget->allocation.height - 1);
904 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
906 ImageWindow *imd = data;
908 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
912 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
914 ImageWindow *imd = data;
916 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
917 image_focus_paint(imd, TRUE, NULL);
922 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
924 ImageWindow *imd = data;
926 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
927 image_focus_paint(imd, FALSE, NULL);
932 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
933 gint relative, gint always)
935 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
938 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
940 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
943 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
945 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
948 void image_overlay_remove(ImageWindow *imd, gint id)
950 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
953 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
955 ImageWindow *imd = data;
957 if (imd->func_scroll &&
958 event && event->type == GDK_SCROLL)
960 imd->func_scroll(imd, event->direction, event->time,
961 event->x, event->y, event->state, imd->data_scroll);
969 *-------------------------------------------------------------------
971 *-------------------------------------------------------------------
974 void image_attach_window(ImageWindow *imd, GtkWidget *window,
975 const gchar *title, const gchar *title_right, gint show_zoom)
977 imd->top_window = window;
979 imd->title = g_strdup(title);
980 g_free(imd->title_right);
981 imd->title_right = g_strdup(title_right);
982 imd->title_show_zoom = show_zoom;
984 if (!fit_window) window = NULL;
986 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
988 image_update_title(imd);
991 void image_set_update_func(ImageWindow *imd,
992 void (*func)(ImageWindow *imd, gpointer data),
995 imd->func_update = func;
996 imd->data_update = data;
999 void image_set_complete_func(ImageWindow *imd,
1000 void (*func)(ImageWindow *, gint preload, gpointer),
1003 imd->func_complete = func;
1004 imd->data_complete = data;
1007 void image_set_new_func(ImageWindow *imd,
1008 void (*func)(ImageWindow *, gpointer),
1011 imd->func_new = func;
1012 imd->data_new = data;
1016 void image_set_button_func(ImageWindow *imd,
1017 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1020 imd->func_button = func;
1021 imd->data_button = data;
1024 void image_set_scroll_func(ImageWindow *imd,
1025 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1028 imd->func_scroll = func;
1029 imd->data_scroll = data;
1032 void image_set_scroll_notify_func(ImageWindow *imd,
1033 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1036 imd->func_scroll_notify = func;
1037 imd->data_scroll_notify = data;
1042 const gchar *image_get_path(ImageWindow *imd)
1044 return imd->image_path;
1047 const gchar *image_get_name(ImageWindow *imd)
1049 return imd->image_name;
1052 /* merely changes path string, does not change the image! */
1053 void image_set_path(ImageWindow *imd, const gchar *newpath)
1055 g_free(imd->image_path);
1056 imd->image_path = g_strdup(newpath);
1057 imd->image_name = filename_from_path(imd->image_path);
1059 image_update_title(imd);
1060 image_new_util(imd);
1063 /* load a new image */
1065 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
1067 if (imd->image_path == path ||
1068 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
1070 image_change_real(imd, path, NULL, NULL, zoom);
1073 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1075 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1078 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1080 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1081 image_new_util(imd);
1084 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1086 if (!cd || !info || !g_list_find(cd->list, info)) return;
1088 image_change_real(imd, info->path, cd, info, zoom);
1091 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1093 if (collection_to_number(imd->collection) >= 0)
1095 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1097 if (info) *info = imd->collection_info;
1101 if (info) *info = NULL;
1103 return imd->collection;
1106 if (info) *info = NULL;
1110 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1112 /* change data for the callbacks directly */
1114 il->data_area_ready = data;
1115 il->data_error = data;
1116 il->data_done = data;
1117 il->data_percent = data;
1120 /* this is more like a move function
1121 * it moves most data from source to imd
1123 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1125 if (imd == source) return;
1127 imd->unknown = source->unknown;
1129 imd->collection = source->collection;
1130 imd->collection_info = source->collection_info;
1131 imd->size = source->size;
1132 imd->mtime = source->mtime;
1134 image_set_path(imd, image_get_path(source));
1136 image_loader_free(imd->il);
1141 imd->il = source->il;
1144 image_loader_sync_data(imd->il, imd);
1146 imd->delay_alter_type = source->delay_alter_type;
1147 source->delay_alter_type = ALTER_NONE;
1150 imd->color_profile_enable = source->color_profile_enable;
1151 imd->color_profile_input = source->color_profile_input;
1152 imd->color_profile_screen = source->color_profile_screen;
1153 imd->color_profile_use_image = source->color_profile_use_image;
1154 color_man_free((ColorMan *)imd->cm);
1160 imd->cm = source->cm;
1163 cm = (ColorMan *)imd->cm;
1165 cm->func_done_data = imd;
1168 image_loader_free(imd->read_ahead_il);
1169 imd->read_ahead_il = source->read_ahead_il;
1170 source->read_ahead_il = NULL;
1171 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1173 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1174 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1175 source->read_ahead_pixbuf = NULL;
1177 g_free(imd->read_ahead_path);
1178 imd->read_ahead_path = source->read_ahead_path;
1179 source->read_ahead_path = NULL;
1181 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1182 imd->prev_pixbuf = source->prev_pixbuf;
1183 source->prev_pixbuf = NULL;
1184 imd->prev_color_row = source->prev_color_row;
1185 source->prev_color_row = -1;
1187 g_free(imd->prev_path);
1188 imd->prev_path = source->prev_path;
1189 source->prev_path = NULL;
1191 imd->completed = source->completed;
1192 imd->state = source->state;
1193 source->state = IMAGE_STATE_NONE;
1195 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1200 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1202 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1205 void image_reload(ImageWindow *imd)
1207 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1209 image_change_complete(imd, image_zoom_get(imd), FALSE);
1212 void image_scroll(ImageWindow *imd, gint x, gint y)
1214 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1217 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1218 gdouble x_align, gdouble y_align)
1220 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1223 void image_alter(ImageWindow *imd, AlterType type)
1225 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1227 if (imd->il || imd->cm)
1229 /* still loading, wait till done */
1230 imd->delay_alter_type = type;
1234 image_alter_real(imd, type, TRUE, FALSE);
1237 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1239 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1242 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1244 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1247 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1249 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1252 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1254 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1257 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1263 pr = (PixbufRenderer *)imd->pr;
1265 if (!pixbuf_renderer_get_pixbuf(pr) ||
1266 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1270 zoom = (gdouble)pr->window_height / height;
1274 zoom = (gdouble)pr->window_width / width;
1279 zoom = 0.0 - 1.0 / zoom;
1282 pixbuf_renderer_zoom_set(pr, zoom);
1285 gdouble image_zoom_get(ImageWindow *imd)
1287 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1290 gdouble image_zoom_get_real(ImageWindow *imd)
1292 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1295 gchar *image_zoom_get_as_text(ImageWindow *imd)
1303 gchar *approx = " ";
1305 zoom = image_zoom_get(imd);
1306 scale = image_zoom_get_real(imd);
1312 else if (zoom < 0.0)
1316 else if (zoom == 0.0 && scale != 0.0)
1329 if (rint(l) != l) pl = 1;
1330 if (rint(r) != r) pr = 1;
1332 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1335 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1339 if (mode == ZOOM_RESET_ORIGINAL)
1343 else if (mode == ZOOM_RESET_FIT_WINDOW)
1351 zoom = image_zoom_get(imd);
1364 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1366 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1370 image_read_ahead_set(imd, path);
1374 image_read_ahead_cancel(imd);
1378 static gint image_auto_refresh_cb(gpointer data)
1380 ImageWindow *imd = data;
1383 if (!imd || !image_get_pixbuf(imd) ||
1384 imd->il || !imd->image_path ||
1385 !update_on_time_change) return TRUE;
1387 newtime = filetime(imd->image_path);
1388 if (newtime > 0 && newtime != imd->mtime)
1390 imd->mtime = newtime;
1397 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1399 void image_auto_refresh(ImageWindow *imd, gint interval)
1402 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1404 if (imd->auto_refresh_id > -1)
1406 g_source_remove(imd->auto_refresh_id);
1407 imd->auto_refresh_id = -1;
1408 imd->auto_refresh_interval = -1;
1411 if (interval < 0) return;
1413 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1415 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1416 imd->auto_refresh_interval = interval;
1419 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1421 imd->top_window_sync = allow_sync;
1423 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1426 void image_background_set_black(ImageWindow *imd, gint black)
1428 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1431 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1433 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1436 void image_color_profile_set(ImageWindow *imd,
1437 gint input_type, gint screen_type,
1442 if (input_type < 0 || input_type > COLOR_PROFILE_INPUTS ||
1443 screen_type < 0 || screen_type > 1)
1448 imd->color_profile_input = input_type;
1449 imd->color_profile_screen = screen_type;
1450 imd->color_profile_use_image = use_image;
1453 gint image_color_profile_get(ImageWindow *imd,
1454 gint *input_type, gint *screen_type,
1457 if (!imd) return FALSE;
1459 if (input_type) *input_type = imd->color_profile_input;
1460 if (screen_type) *screen_type = imd->color_profile_screen;
1461 if (use_image) *use_image = imd->color_profile_use_image;
1466 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1470 if (imd->color_profile_enable == enable) return;
1472 imd->color_profile_enable = enable;
1475 gint image_color_profile_get_use(ImageWindow *imd)
1477 if (!imd) return FALSE;
1479 return imd->color_profile_enable;
1482 void image_set_delay_flip(ImageWindow *imd, gint delay)
1485 imd->delay_flip == delay) return;
1487 imd->delay_flip = delay;
1489 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1491 if (!imd->delay_flip && imd->il)
1495 pr = PIXBUF_RENDERER(imd->pr);
1496 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1499 image_load_pixbuf_ready(imd);
1503 void image_to_root_window(ImageWindow *imd, gint scaled)
1506 GdkWindow *rootwindow;
1514 pixbuf = image_get_pixbuf(imd);
1515 if (!pixbuf) return;
1517 screen = gtk_widget_get_screen(imd->widget);
1518 rootwindow = gdk_screen_get_root_window(screen);
1519 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1523 width = gdk_screen_width();
1524 height = gdk_screen_height();
1528 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1531 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1533 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1534 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1535 gdk_window_clear(rootwindow);
1537 g_object_unref(pixmap);
1543 *-------------------------------------------------------------------
1545 *-------------------------------------------------------------------
1548 static void image_options_set(ImageWindow *imd)
1550 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1551 "zoom_2pass", two_pass_zoom,
1552 "zoom_expand", zoom_to_fit_expands,
1553 "dither_quality", dither_quality,
1554 "scroll_reset", scroll_reset_method,
1555 "cache_display", tile_cache_max,
1556 "window_fit", (imd->top_window_sync && fit_window),
1557 "window_limit", limit_window_size,
1558 "window_limit_value", max_window_size,
1561 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1564 void image_options_sync(void)
1576 image_options_set(imd);
1581 *-------------------------------------------------------------------
1583 *-------------------------------------------------------------------
1586 static void image_free(ImageWindow *imd)
1588 image_list = g_list_remove(image_list, imd);
1592 image_read_ahead_cancel(imd);
1593 image_post_buffer_set(imd, NULL, NULL, -1);
1594 image_auto_refresh(imd, -1);
1596 g_free(imd->image_path);
1598 g_free(imd->title_right);
1603 static void image_destroy_cb(GtkObject *widget, gpointer data)
1605 ImageWindow *imd = data;
1609 ImageWindow *image_new(gint frame)
1613 imd = g_new0(ImageWindow, 1);
1615 imd->top_window = NULL;
1617 imd->title_right = NULL;
1618 imd->title_show_zoom = FALSE;
1620 imd->unknown = TRUE;
1622 imd->has_frame = frame;
1623 imd->top_window_sync = FALSE;
1625 imd->delay_alter_type = ALTER_NONE;
1627 imd->read_ahead_il = NULL;
1628 imd->read_ahead_pixbuf = NULL;
1629 imd->read_ahead_path = NULL;
1631 imd->completed = FALSE;
1632 imd->state = IMAGE_STATE_NONE;
1634 imd->color_profile_enable = FALSE;
1635 imd->color_profile_input = 0;
1636 imd->color_profile_screen = 0;
1637 imd->color_profile_use_image = FALSE;
1639 imd->auto_refresh_id = -1;
1640 imd->auto_refresh_interval = -1;
1642 imd->delay_flip = FALSE;
1644 imd->func_update = NULL;
1645 imd->func_complete = NULL;
1646 imd->func_tile_request = NULL;
1647 imd->func_tile_dispose = NULL;
1649 imd->func_button = NULL;
1650 imd->func_scroll = NULL;
1652 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1654 image_options_set(imd);
1658 imd->widget = gtk_frame_new(NULL);
1659 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1660 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1661 gtk_widget_show(imd->pr);
1663 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1664 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1665 G_CALLBACK(image_focus_in_cb), imd);
1666 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1667 G_CALLBACK(image_focus_out_cb), imd);
1669 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1670 G_CALLBACK(image_focus_expose), imd);
1674 imd->widget = imd->pr;
1677 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1678 G_CALLBACK(image_click_cb), imd);
1679 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1680 G_CALLBACK(image_scroll_notify_cb), imd);
1682 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1683 G_CALLBACK(image_scroll_cb), imd);
1685 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1686 G_CALLBACK(image_destroy_cb), imd);
1688 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1689 G_CALLBACK(image_zoom_cb), imd);
1690 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1691 G_CALLBACK(image_render_complete_cb), imd);
1693 image_list = g_list_append(image_list, imd);