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)
171 GdkPixbuf *new = NULL;
176 pr = (PixbufRenderer *)imd->pr;
178 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
179 imd->delay_alter_type = ALTER_NONE;
181 if (!pr->pixbuf) return;
183 x = pr->x_scroll + (pr->vis_width / 2);
184 y = pr->y_scroll + (pr->vis_height / 2);
188 case ALTER_ROTATE_90:
189 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
194 case ALTER_ROTATE_90_CC:
195 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
200 case ALTER_ROTATE_180:
201 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
206 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
210 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
213 case ALTER_DESATURATE:
214 pixbuf_desaturate_rect(pr->pixbuf,
215 0, 0, pr->image_width, pr->image_height);
216 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
226 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
229 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
233 switch (pr->scroll_reset)
235 case PR_SCROLL_RESET_NOCHANGE:
237 case PR_SCROLL_RESET_CENTER:
238 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
239 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
241 case PR_SCROLL_RESET_TOPLEFT:
248 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
249 (gint)((gdouble)y / pr->scale),
254 static void image_post_process_alter(ImageWindow *imd, gint clamp)
256 if (imd->delay_alter_type != ALTER_NONE)
258 image_alter_real(imd, imd->delay_alter_type, clamp);
262 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
264 ImageWindow *imd = data;
266 color_man_free((ColorMan *)imd->cm);
268 imd->state |= IMAGE_STATE_COLOR_ADJ;
270 if (type != COLOR_RETURN_IMAGE_CHANGED)
272 image_post_process_alter(imd, FALSE);
276 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif)
279 ColorManProfileType input_type;
280 ColorManProfileType screen_type;
281 const gchar *input_file;
282 const gchar *screen_file;
283 ExifItem *item = NULL;
285 if (imd->cm) return FALSE;
287 if (imd->color_profile_input >= 1 &&
288 imd->color_profile_input <= COLOR_PROFILE_INPUTS)
292 n = imd->color_profile_input - 1;
293 if (!color_profile_input_file[n]) return FALSE;
295 input_type = COLOR_PROFILE_FILE;
296 input_file = color_profile_input_file[n];
298 else if (imd->color_profile_input == 0)
300 input_type = COLOR_PROFILE_SRGB;
308 if (imd->color_profile_screen == 1 &&
309 color_profile_screen_file)
311 screen_type = COLOR_PROFILE_FILE;
312 screen_file = color_profile_screen_file;
314 else if (imd->color_profile_screen == 0)
316 screen_type = COLOR_PROFILE_SRGB;
324 if (imd->color_profile_use_image && exif)
326 item = exif_get_item(exif, "ColorProfile");
328 if (item && item->format == EXIF_FORMAT_UNDEFINED)
330 if (debug) printf("Found embedded color profile\n");
332 cm = color_man_new_embedded(imd,
333 item->data, item->data_len,
334 screen_type, screen_file,
335 image_post_process_color_cb, imd);
339 cm = color_man_new(imd,
340 input_type, input_file,
341 screen_type, screen_file,
342 image_post_process_color_cb, imd);
347 if (start_row > 0) cm->row = start_row;
349 imd->cm = (gpointer)cm;
356 static void image_post_process(ImageWindow *imd, gint clamp)
358 ExifData *exif = NULL;
360 if (!image_get_pixbuf(imd)) return;
362 if (exif_rotate_enable ||
363 (imd->color_profile_enable && imd->color_profile_use_image) )
365 exif = exif_read(imd->image_path, (imd->color_profile_enable && imd->color_profile_use_image));
368 if (exif_rotate_enable && exif)
372 if (exif_get_integer(exif, "Orientation", &orientation))
376 /* see http://jpegclub.org/exif_orientation.html
379 888888 888888 88 88 8888888888 88 88 8888888888
380 88 88 88 88 88 88 88 88 88 88 88 88
381 8888 8888 8888 8888 88 8888888888 8888888888 88
387 case EXIF_ORIENTATION_TOP_LEFT:
388 /* normal -- nothing to do */
391 case EXIF_ORIENTATION_TOP_RIGHT:
393 imd->delay_alter_type = ALTER_MIRROR;
395 case EXIF_ORIENTATION_BOTTOM_RIGHT:
397 imd->delay_alter_type = ALTER_ROTATE_180;
399 case EXIF_ORIENTATION_BOTTOM_LEFT:
401 imd->delay_alter_type = ALTER_FLIP;
403 case EXIF_ORIENTATION_LEFT_TOP:
404 /* not implemented -- too wacky to fix in one step */
407 case EXIF_ORIENTATION_RIGHT_TOP:
408 /* rotated -90 (270) */
409 imd->delay_alter_type = ALTER_ROTATE_90;
411 case EXIF_ORIENTATION_RIGHT_BOTTOM:
412 /* not implemented -- too wacky to fix in one step */
415 case EXIF_ORIENTATION_LEFT_BOTTOM:
417 imd->delay_alter_type = ALTER_ROTATE_90_CC;
420 /* The other values are out of range */
425 if (rotate) imd->state |= IMAGE_STATE_COLOR_ADJ;
429 if (imd->color_profile_enable)
431 if (!image_post_process_color(imd, 0, exif))
433 /* fixme: note error to user */
434 imd->state |= IMAGE_STATE_COLOR_ADJ;
438 if (!imd->cm) image_post_process_alter(imd, clamp);
444 *-------------------------------------------------------------------
445 * read ahead (prebuffer)
446 *-------------------------------------------------------------------
449 static void image_read_ahead_cancel(ImageWindow *imd)
451 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
453 image_loader_free(imd->read_ahead_il);
454 imd->read_ahead_il = NULL;
456 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
457 imd->read_ahead_pixbuf = NULL;
459 g_free(imd->read_ahead_path);
460 imd->read_ahead_path = NULL;
463 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
465 ImageWindow *imd = data;
467 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
469 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
470 if (imd->read_ahead_pixbuf)
472 g_object_ref(imd->read_ahead_pixbuf);
476 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
478 image_loader_free(imd->read_ahead_il);
479 imd->read_ahead_il = NULL;
481 image_complete_util(imd, TRUE);
484 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
486 /* we even treat errors as success, maybe at least some of the file was ok */
487 image_read_ahead_done_cb(il, data);
490 static void image_read_ahead_start(ImageWindow *imd)
492 /* already started ? */
493 if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
495 /* still loading ?, do later */
498 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
500 imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
502 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
503 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
505 image_read_ahead_cancel(imd);
506 image_complete_util(imd, TRUE);
510 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
512 if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
514 image_read_ahead_cancel(imd);
516 imd->read_ahead_path = g_strdup(path);
518 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
520 image_read_ahead_start(imd);
524 *-------------------------------------------------------------------
526 *-------------------------------------------------------------------
529 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf, gint color_row)
531 g_free(imd->prev_path);
532 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
536 imd->prev_path = g_strdup(path);
538 g_object_ref(pixbuf);
539 imd->prev_pixbuf = pixbuf;
540 imd->prev_color_row = color_row;
544 imd->prev_path = NULL;
545 imd->prev_pixbuf = NULL;
546 imd->prev_color_row = -1;
549 if (debug) printf("post buffer set: %s\n", path);
552 static gint image_post_buffer_get(ImageWindow *imd)
556 if (imd->prev_pixbuf &&
557 imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
559 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
560 if (imd->prev_color_row >= 0)
562 ExifData *exif = NULL;
564 if (imd->color_profile_use_image) exif = exif_read(imd->image_path, TRUE);
565 image_post_process_color(imd, imd->prev_color_row, exif);
575 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
576 imd->prev_pixbuf = NULL;
578 g_free(imd->prev_path);
579 imd->prev_path = NULL;
585 *-------------------------------------------------------------------
587 *-------------------------------------------------------------------
590 static void image_load_pixbuf_ready(ImageWindow *imd)
592 if (image_get_pixbuf(imd) || !imd->il) return;
594 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
597 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
599 ImageWindow *imd = data;
602 pr = (PixbufRenderer *)imd->pr;
604 if (imd->delay_flip &&
605 pr->pixbuf != image_loader_get_pixbuf(il))
610 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
612 pixbuf_renderer_area_changed(pr, x, y, w, h);
615 static void image_load_done_cb(ImageLoader *il, gpointer data)
617 ImageWindow *imd = data;
619 if (debug) printf ("image done\n");
621 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
623 if (imd->delay_flip &&
624 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
626 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
627 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
630 image_loader_free(imd->il);
633 image_post_process(imd, TRUE);
635 image_read_ahead_start(imd);
638 static void image_load_error_cb(ImageLoader *il, gpointer data)
640 if (debug) printf ("image error\n");
642 /* even on error handle it like it was done,
643 * since we have a pixbuf with _something_ */
645 image_load_done_cb(il, data);
648 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
649 static void image_load_buffer_throttle(ImageLoader *il)
651 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
653 /* Larger image files usually have larger chunks of data per pixel...
654 * So increase the buffer read size so that the rendering chunks called
658 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
662 /* this read ahead is located here merely for the callbacks, above */
664 static gint image_read_ahead_check(ImageWindow *imd)
666 if (!imd->read_ahead_path) return FALSE;
667 if (imd->il) return FALSE;
669 if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
671 image_read_ahead_cancel(imd);
675 if (imd->read_ahead_il)
677 imd->il = imd->read_ahead_il;
678 imd->read_ahead_il = NULL;
680 /* override the old signals */
681 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
682 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
683 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
685 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
686 image_load_buffer_throttle(imd->il);
689 /* do this one directly (probably should add a set func) */
690 imd->il->func_done = image_load_done_cb;
692 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
694 if (!imd->delay_flip)
696 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
699 image_read_ahead_cancel(imd);
702 else if (imd->read_ahead_pixbuf)
704 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
705 g_object_unref(imd->read_ahead_pixbuf);
706 imd->read_ahead_pixbuf = NULL;
708 image_read_ahead_cancel(imd);
710 image_post_process(imd, FALSE);
714 image_read_ahead_cancel(imd);
718 static gint image_load_begin(ImageWindow *imd, const gchar *path)
720 if (debug) printf ("image begin \n");
722 if (imd->il) return FALSE;
724 imd->completed = FALSE;
725 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
727 if (image_post_buffer_get(imd))
729 if (debug) printf("from post buffer: %s\n", imd->image_path);
733 if (image_read_ahead_check(imd))
735 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
739 if (!imd->delay_flip && image_get_pixbuf(imd))
743 pr = PIXBUF_RENDERER(imd->pr);
744 if (pr->pixbuf) g_object_unref(pr->pixbuf);
748 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
750 imd->il = image_loader_new(path);
752 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
753 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
754 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
756 if (!image_loader_start(imd->il, image_load_done_cb, imd))
758 if (debug) printf("image start error\n");
760 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
762 image_loader_free(imd->il);
765 image_complete_util(imd, FALSE);
770 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
771 image_load_buffer_throttle(imd->il);
774 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
779 static void image_reset(ImageWindow *imd)
781 /* stops anything currently being done */
783 if (debug) printf("image reset\n");
785 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
787 image_loader_free(imd->il);
790 color_man_free((ColorMan *)imd->cm);
793 imd->delay_alter_type = ALTER_NONE;
795 imd->state = IMAGE_STATE_NONE;
799 *-------------------------------------------------------------------
801 *-------------------------------------------------------------------
804 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
808 if (imd->image_path && isfile(imd->image_path))
812 pr = PIXBUF_RENDERER(imd->pr);
813 pr->zoom = zoom; /* store the zoom, needed by the loader */
815 if (image_load_begin(imd, imd->image_path))
817 imd->unknown = FALSE;
823 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
824 image_change_pixbuf(imd, pixbuf, zoom);
825 g_object_unref(pixbuf);
829 imd->size = filesize(imd->image_path);
830 imd->mtime = filetime(imd->image_path);
838 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
839 image_change_pixbuf(imd, pixbuf, zoom);
840 g_object_unref(pixbuf);
841 imd->mtime = filetime(imd->image_path);
845 image_change_pixbuf(imd, NULL, zoom);
852 image_update_util(imd);
855 static void image_change_real(ImageWindow *imd, const gchar *path,
856 CollectionData *cd, CollectInfo *info, gdouble zoom)
859 GdkPixbuf *prev_pixbuf = NULL;
860 gchar *prev_path = NULL;
861 gint prev_clear = FALSE;
862 gint prev_color_row = -1;
864 imd->collection = cd;
865 imd->collection_info = info;
867 pixbuf = image_get_pixbuf(imd);
869 if (enable_read_ahead && imd->image_path && pixbuf)
873 /* current image is not finished */
878 prev_path = g_strdup(imd->image_path);
879 prev_pixbuf = pixbuf;
880 g_object_ref(prev_pixbuf);
886 cm = (ColorMan *)imd->cm;
887 prev_color_row = cm->row;
892 g_free(imd->image_path);
893 imd->image_path = g_strdup(path);
894 imd->image_name = filename_from_path(imd->image_path);
896 image_change_complete(imd, zoom, TRUE);
900 image_post_buffer_set(imd, prev_path, prev_pixbuf, prev_color_row);
902 g_object_unref(prev_pixbuf);
906 image_post_buffer_set(imd, NULL, NULL, -1);
909 image_update_title(imd);
914 *-------------------------------------------------------------------
916 *-------------------------------------------------------------------
919 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
923 widget = imd->widget;
924 if (!widget->window) return;
928 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
929 area, widget, "image_window",
930 widget->allocation.x, widget->allocation.y,
931 widget->allocation.width - 1, widget->allocation.height - 1);
935 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
936 area, widget, "image_window",
937 widget->allocation.x, widget->allocation.y,
938 widget->allocation.width - 1, widget->allocation.height - 1);
942 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
944 ImageWindow *imd = data;
946 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
950 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
952 ImageWindow *imd = data;
954 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
955 image_focus_paint(imd, TRUE, NULL);
960 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
962 ImageWindow *imd = data;
964 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
965 image_focus_paint(imd, FALSE, NULL);
970 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
971 gint relative, gint always)
973 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
976 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
978 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
981 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
983 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
986 void image_overlay_remove(ImageWindow *imd, gint id)
988 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
991 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
993 ImageWindow *imd = data;
995 if (imd->func_scroll &&
996 event && event->type == GDK_SCROLL)
998 imd->func_scroll(imd, event->direction, event->time,
999 event->x, event->y, event->state, imd->data_scroll);
1007 *-------------------------------------------------------------------
1009 *-------------------------------------------------------------------
1012 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1013 const gchar *title, const gchar *title_right, gint show_zoom)
1015 imd->top_window = window;
1017 imd->title = g_strdup(title);
1018 g_free(imd->title_right);
1019 imd->title_right = g_strdup(title_right);
1020 imd->title_show_zoom = show_zoom;
1022 if (!fit_window) window = NULL;
1024 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1026 image_update_title(imd);
1029 void image_set_update_func(ImageWindow *imd,
1030 void (*func)(ImageWindow *imd, gpointer data),
1033 imd->func_update = func;
1034 imd->data_update = data;
1037 void image_set_complete_func(ImageWindow *imd,
1038 void (*func)(ImageWindow *, gint preload, gpointer),
1041 imd->func_complete = func;
1042 imd->data_complete = data;
1045 void image_set_new_func(ImageWindow *imd,
1046 void (*func)(ImageWindow *, gpointer),
1049 imd->func_new = func;
1050 imd->data_new = data;
1054 void image_set_button_func(ImageWindow *imd,
1055 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1058 imd->func_button = func;
1059 imd->data_button = data;
1062 void image_set_scroll_func(ImageWindow *imd,
1063 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1066 imd->func_scroll = func;
1067 imd->data_scroll = data;
1070 void image_set_scroll_notify_func(ImageWindow *imd,
1071 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1074 imd->func_scroll_notify = func;
1075 imd->data_scroll_notify = data;
1080 const gchar *image_get_path(ImageWindow *imd)
1082 return imd->image_path;
1085 const gchar *image_get_name(ImageWindow *imd)
1087 return imd->image_name;
1090 /* merely changes path string, does not change the image! */
1091 void image_set_path(ImageWindow *imd, const gchar *newpath)
1093 g_free(imd->image_path);
1094 imd->image_path = g_strdup(newpath);
1095 imd->image_name = filename_from_path(imd->image_path);
1097 image_update_title(imd);
1098 image_new_util(imd);
1101 /* load a new image */
1103 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
1105 if (imd->image_path == path ||
1106 (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
1108 image_change_real(imd, path, NULL, NULL, zoom);
1111 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1113 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1116 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1118 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1119 image_new_util(imd);
1122 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1124 if (!cd || !info || !g_list_find(cd->list, info)) return;
1126 image_change_real(imd, info->path, cd, info, zoom);
1129 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1131 if (collection_to_number(imd->collection) >= 0)
1133 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1135 if (info) *info = imd->collection_info;
1139 if (info) *info = NULL;
1141 return imd->collection;
1144 if (info) *info = NULL;
1148 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1150 /* change data for the callbacks directly */
1152 il->data_area_ready = data;
1153 il->data_error = data;
1154 il->data_done = data;
1155 il->data_percent = data;
1158 /* this is more like a move function
1159 * it moves most data from source to imd
1161 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1163 if (imd == source) return;
1165 imd->unknown = source->unknown;
1167 imd->collection = source->collection;
1168 imd->collection_info = source->collection_info;
1169 imd->size = source->size;
1170 imd->mtime = source->mtime;
1172 image_set_path(imd, image_get_path(source));
1174 image_loader_free(imd->il);
1179 imd->il = source->il;
1182 image_loader_sync_data(imd->il, imd);
1184 imd->delay_alter_type = source->delay_alter_type;
1185 source->delay_alter_type = ALTER_NONE;
1188 imd->color_profile_enable = source->color_profile_enable;
1189 imd->color_profile_input = source->color_profile_input;
1190 imd->color_profile_screen = source->color_profile_screen;
1191 imd->color_profile_use_image = source->color_profile_use_image;
1192 color_man_free((ColorMan *)imd->cm);
1198 imd->cm = source->cm;
1201 cm = (ColorMan *)imd->cm;
1203 cm->func_done_data = imd;
1206 image_loader_free(imd->read_ahead_il);
1207 imd->read_ahead_il = source->read_ahead_il;
1208 source->read_ahead_il = NULL;
1209 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1211 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1212 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1213 source->read_ahead_pixbuf = NULL;
1215 g_free(imd->read_ahead_path);
1216 imd->read_ahead_path = source->read_ahead_path;
1217 source->read_ahead_path = NULL;
1219 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1220 imd->prev_pixbuf = source->prev_pixbuf;
1221 source->prev_pixbuf = NULL;
1222 imd->prev_color_row = source->prev_color_row;
1223 source->prev_color_row = -1;
1225 g_free(imd->prev_path);
1226 imd->prev_path = source->prev_path;
1227 source->prev_path = NULL;
1229 imd->completed = source->completed;
1230 imd->state = source->state;
1231 source->state = IMAGE_STATE_NONE;
1233 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1238 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1240 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1243 void image_reload(ImageWindow *imd)
1245 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1247 image_change_complete(imd, image_zoom_get(imd), FALSE);
1250 void image_scroll(ImageWindow *imd, gint x, gint y)
1252 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1255 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1256 gdouble x_align, gdouble y_align)
1258 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1261 void image_alter(ImageWindow *imd, AlterType type)
1263 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1265 if (imd->il || imd->cm)
1267 /* still loading, wait till done */
1268 imd->delay_alter_type = type;
1269 imd->state |= IMAGE_STATE_ROTATE_USER;
1271 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1273 imd->state &= ~IMAGE_STATE_ROTATE_AUTO;
1278 image_alter_real(imd, type, TRUE);
1281 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1283 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1286 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1288 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1291 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1293 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1296 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1298 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1301 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1307 pr = (PixbufRenderer *)imd->pr;
1309 if (!pixbuf_renderer_get_pixbuf(pr) ||
1310 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1314 zoom = (gdouble)pr->window_height / height;
1318 zoom = (gdouble)pr->window_width / width;
1323 zoom = 0.0 - 1.0 / zoom;
1326 pixbuf_renderer_zoom_set(pr, zoom);
1329 gdouble image_zoom_get(ImageWindow *imd)
1331 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1334 gdouble image_zoom_get_real(ImageWindow *imd)
1336 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1339 gchar *image_zoom_get_as_text(ImageWindow *imd)
1347 gchar *approx = " ";
1349 zoom = image_zoom_get(imd);
1350 scale = image_zoom_get_real(imd);
1356 else if (zoom < 0.0)
1360 else if (zoom == 0.0 && scale != 0.0)
1373 if (rint(l) != l) pl = 1;
1374 if (rint(r) != r) pr = 1;
1376 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1379 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1383 if (mode == ZOOM_RESET_ORIGINAL)
1387 else if (mode == ZOOM_RESET_FIT_WINDOW)
1395 zoom = image_zoom_get(imd);
1408 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1410 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1414 image_read_ahead_set(imd, path);
1418 image_read_ahead_cancel(imd);
1422 static gint image_auto_refresh_cb(gpointer data)
1424 ImageWindow *imd = data;
1427 if (!imd || !image_get_pixbuf(imd) ||
1428 imd->il || !imd->image_path ||
1429 !update_on_time_change) return TRUE;
1431 newtime = filetime(imd->image_path);
1432 if (newtime > 0 && newtime != imd->mtime)
1434 imd->mtime = newtime;
1441 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1443 void image_auto_refresh(ImageWindow *imd, gint interval)
1446 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1448 if (imd->auto_refresh_id > -1)
1450 g_source_remove(imd->auto_refresh_id);
1451 imd->auto_refresh_id = -1;
1452 imd->auto_refresh_interval = -1;
1455 if (interval < 0) return;
1457 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1459 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1460 imd->auto_refresh_interval = interval;
1463 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1465 imd->top_window_sync = allow_sync;
1467 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1470 void image_background_set_black(ImageWindow *imd, gint black)
1472 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1475 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1477 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1480 void image_color_profile_set(ImageWindow *imd,
1481 gint input_type, gint screen_type,
1486 if (input_type < 0 || input_type > COLOR_PROFILE_INPUTS ||
1487 screen_type < 0 || screen_type > 1)
1492 imd->color_profile_input = input_type;
1493 imd->color_profile_screen = screen_type;
1494 imd->color_profile_use_image = use_image;
1497 gint image_color_profile_get(ImageWindow *imd,
1498 gint *input_type, gint *screen_type,
1501 if (!imd) return FALSE;
1503 if (input_type) *input_type = imd->color_profile_input;
1504 if (screen_type) *screen_type = imd->color_profile_screen;
1505 if (use_image) *use_image = imd->color_profile_use_image;
1510 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1514 if (imd->color_profile_enable == enable) return;
1516 imd->color_profile_enable = enable;
1519 gint image_color_profile_get_use(ImageWindow *imd)
1521 if (!imd) return FALSE;
1523 return imd->color_profile_enable;
1526 void image_set_delay_flip(ImageWindow *imd, gint delay)
1529 imd->delay_flip == delay) return;
1531 imd->delay_flip = delay;
1533 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1535 if (!imd->delay_flip && imd->il)
1539 pr = PIXBUF_RENDERER(imd->pr);
1540 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1543 image_load_pixbuf_ready(imd);
1547 void image_to_root_window(ImageWindow *imd, gint scaled)
1550 GdkWindow *rootwindow;
1558 pixbuf = image_get_pixbuf(imd);
1559 if (!pixbuf) return;
1561 screen = gtk_widget_get_screen(imd->widget);
1562 rootwindow = gdk_screen_get_root_window(screen);
1563 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1567 width = gdk_screen_width();
1568 height = gdk_screen_height();
1572 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1575 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1577 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1578 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1579 gdk_window_clear(rootwindow);
1581 g_object_unref(pixmap);
1587 *-------------------------------------------------------------------
1589 *-------------------------------------------------------------------
1592 static void image_options_set(ImageWindow *imd)
1594 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1595 "zoom_2pass", two_pass_zoom,
1596 "zoom_expand", zoom_to_fit_expands,
1597 "dither_quality", dither_quality,
1598 "scroll_reset", scroll_reset_method,
1599 "cache_display", tile_cache_max,
1600 "window_fit", (imd->top_window_sync && fit_window),
1601 "window_limit", limit_window_size,
1602 "window_limit_value", max_window_size,
1605 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1608 void image_options_sync(void)
1620 image_options_set(imd);
1625 *-------------------------------------------------------------------
1627 *-------------------------------------------------------------------
1630 static void image_free(ImageWindow *imd)
1632 image_list = g_list_remove(image_list, imd);
1636 image_read_ahead_cancel(imd);
1637 image_post_buffer_set(imd, NULL, NULL, -1);
1638 image_auto_refresh(imd, -1);
1640 g_free(imd->image_path);
1642 g_free(imd->title_right);
1647 static void image_destroy_cb(GtkObject *widget, gpointer data)
1649 ImageWindow *imd = data;
1653 ImageWindow *image_new(gint frame)
1657 imd = g_new0(ImageWindow, 1);
1659 imd->top_window = NULL;
1661 imd->title_right = NULL;
1662 imd->title_show_zoom = FALSE;
1664 imd->unknown = TRUE;
1666 imd->has_frame = frame;
1667 imd->top_window_sync = FALSE;
1669 imd->delay_alter_type = ALTER_NONE;
1671 imd->read_ahead_il = NULL;
1672 imd->read_ahead_pixbuf = NULL;
1673 imd->read_ahead_path = NULL;
1675 imd->completed = FALSE;
1676 imd->state = IMAGE_STATE_NONE;
1678 imd->color_profile_enable = FALSE;
1679 imd->color_profile_input = 0;
1680 imd->color_profile_screen = 0;
1681 imd->color_profile_use_image = FALSE;
1683 imd->auto_refresh_id = -1;
1684 imd->auto_refresh_interval = -1;
1686 imd->delay_flip = FALSE;
1688 imd->func_update = NULL;
1689 imd->func_complete = NULL;
1690 imd->func_tile_request = NULL;
1691 imd->func_tile_dispose = NULL;
1693 imd->func_button = NULL;
1694 imd->func_scroll = NULL;
1696 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1698 image_options_set(imd);
1702 imd->widget = gtk_frame_new(NULL);
1703 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1704 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1705 gtk_widget_show(imd->pr);
1707 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1708 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1709 G_CALLBACK(image_focus_in_cb), imd);
1710 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1711 G_CALLBACK(image_focus_out_cb), imd);
1713 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1714 G_CALLBACK(image_focus_expose), imd);
1718 imd->widget = imd->pr;
1721 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1722 G_CALLBACK(image_click_cb), imd);
1723 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1724 G_CALLBACK(image_scroll_notify_cb), imd);
1726 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1727 G_CALLBACK(image_scroll_cb), imd);
1729 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1730 G_CALLBACK(image_destroy_cb), imd);
1732 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1733 G_CALLBACK(image_zoom_cb), imd);
1734 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1735 G_CALLBACK(image_render_complete_cb), imd);
1737 image_list = g_list_append(image_list, imd);