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"
30 /* size of the image loader buffer (512 bytes x defined number) */
31 #define IMAGE_LOAD_BUFFER_COUNT 8
33 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
34 #define IMAGE_THROTTLE_LARGER_IMAGES 1
36 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
37 #define IMAGE_THROTTLE_FACTOR 4
39 /* the file size at which throttling take place */
40 #define IMAGE_THROTTLE_THRESHOLD 1048576
42 #define IMAGE_AUTO_REFRESH_TIME 3000
45 static GList *image_list = NULL;
48 static void image_update_title(ImageWindow *imd);
49 static void image_post_process(ImageWindow *imd, gint clamp);
50 static void image_read_ahead_start(ImageWindow *imd);
53 *-------------------------------------------------------------------
55 *-------------------------------------------------------------------
58 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
60 ImageWindow *imd = data;
64 imd->func_button(imd, event->button, event->time,
65 event->x, event->y, event->state, imd->data_button);
69 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
71 ImageWindow *imd = data;
74 pixbuf_renderer_get_scaled_size(pr, &width, &height);
78 imd->func_drag(imd, event->button, event->time,
79 event->x, event->y, event->state,
80 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
85 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
87 ImageWindow *imd = data;
89 if (imd->func_scroll_notify && pr->scale)
91 imd->func_scroll_notify(imd,
92 (gint)((gdouble)pr->x_scroll / pr->scale),
93 (gint)((gdouble)pr->y_scroll / pr->scale),
94 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
95 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
96 imd->data_scroll_notify);
100 static void image_update_util(ImageWindow *imd)
102 if (imd->func_update) imd->func_update(imd, imd->data_update);
105 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
107 ImageWindow *imd = data;
109 if (imd->title_show_zoom) image_update_title(imd);
110 image_update_util(imd);
113 static void image_complete_util(ImageWindow *imd, gint preload)
115 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
117 if (debug) printf("image load completed \"%s\" (%s)\n",
118 (preload) ? imd->read_ahead_fd->path : imd->image_fd->path,
119 (preload) ? "preload" : "current");
121 if (!preload) imd->completed = TRUE;
122 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
125 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
127 ImageWindow *imd = data;
129 image_complete_util(imd, FALSE);
132 static void image_state_set(ImageWindow *imd, ImageState state)
134 if (state == IMAGE_STATE_NONE)
142 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
145 static void image_state_unset(ImageWindow *imd, ImageState state)
147 imd->state &= ~state;
148 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
152 *-------------------------------------------------------------------
154 *-------------------------------------------------------------------
157 static void image_update_title(ImageWindow *imd)
161 gchar *collection = NULL;
163 if (!imd->top_window) return;
165 if (imd->collection && collection_to_number(imd->collection) >= 0)
168 name = imd->collection->name;
169 if (!name) name = _("Untitled");
170 collection = g_strdup_printf(" (Collection %s)", name);
173 if (imd->title_show_zoom)
175 gchar *buf = image_zoom_get_as_text(imd);
176 zoom = g_strconcat(" [", buf, "]", NULL);
180 title = g_strdup_printf("%s%s%s%s%s%s",
181 imd->title ? imd->title : "",
182 imd->image_fd ? imd->image_fd->name : "",
184 collection ? collection : "",
185 imd->image_fd ? " - " : "",
186 imd->title_right ? imd->title_right : "");
188 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
196 *-------------------------------------------------------------------
197 * rotation, flip, etc.
198 *-------------------------------------------------------------------
201 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
204 GdkPixbuf *new = NULL;
209 pr = (PixbufRenderer *)imd->pr;
211 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
212 imd->delay_alter_type = ALTER_NONE;
214 if (!pr->pixbuf) return;
216 x = pr->x_scroll + (pr->vis_width / 2);
217 y = pr->y_scroll + (pr->vis_height / 2);
221 case ALTER_ROTATE_90:
222 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
227 case ALTER_ROTATE_90_CC:
228 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
233 case ALTER_ROTATE_180:
234 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
239 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
243 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
246 case ALTER_DESATURATE:
247 pixbuf_desaturate_rect(pr->pixbuf,
248 0, 0, pr->image_width, pr->image_height);
249 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
259 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
262 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
266 switch (pr->scroll_reset)
268 case PR_SCROLL_RESET_NOCHANGE:
270 case PR_SCROLL_RESET_CENTER:
271 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
272 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
274 case PR_SCROLL_RESET_TOPLEFT:
281 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
282 (gint)((gdouble)y / pr->scale),
286 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
289 static void image_post_process_alter(ImageWindow *imd, gint clamp)
291 if (imd->delay_alter_type != ALTER_NONE)
293 image_alter_real(imd, imd->delay_alter_type, clamp);
297 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
299 ImageWindow *imd = data;
302 if (type == COLOR_RETURN_IMAGE_CHANGED)
304 if (cm == imd->cm) imd->cm = NULL;
309 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
311 image_post_process_alter(imd, FALSE);
313 image_read_ahead_start(imd);
316 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif)
319 ColorManProfileType input_type;
320 ColorManProfileType screen_type;
321 const gchar *input_file;
322 const gchar *screen_file;
323 ExifItem *item = NULL;
325 if (imd->cm) return FALSE;
327 if (imd->color_profile_input >= 1 &&
328 imd->color_profile_input <= COLOR_PROFILE_INPUTS)
332 n = imd->color_profile_input - 1;
333 if (!color_profile_input_file[n]) return FALSE;
335 input_type = COLOR_PROFILE_FILE;
336 input_file = color_profile_input_file[n];
338 else if (imd->color_profile_input == 0)
340 input_type = COLOR_PROFILE_SRGB;
348 if (imd->color_profile_screen == 1 &&
349 color_profile_screen_file)
351 screen_type = COLOR_PROFILE_FILE;
352 screen_file = color_profile_screen_file;
354 else if (imd->color_profile_screen == 0)
356 screen_type = COLOR_PROFILE_SRGB;
364 if (imd->color_profile_use_image && exif)
366 item = exif_get_item(exif, "ColorProfile");
371 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
372 if (exif_get_integer(exif, "ColorSpace", &cs) &&
375 input_type = COLOR_PROFILE_SRGB;
378 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
382 if (item && item->format == EXIF_FORMAT_UNDEFINED)
384 if (debug) printf("Found embedded color profile\n");
386 cm = color_man_new_embedded(imd, NULL,
387 item->data, item->data_len,
388 screen_type, screen_file,
389 image_post_process_color_cb, imd);
393 cm = color_man_new(imd, NULL,
394 input_type, input_file,
395 screen_type, screen_file,
396 image_post_process_color_cb, imd);
404 cm->incremental_sync = TRUE;
407 imd->cm = (gpointer)cm;
414 static void image_post_process(ImageWindow *imd, gint clamp)
416 ExifData *exif = NULL;
418 if (!image_get_pixbuf(imd)) return;
420 if (exif_rotate_enable ||
421 (imd->color_profile_enable && imd->color_profile_use_image) )
423 exif = exif_read(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image));
426 if (exif_rotate_enable && exif)
430 if (exif_get_integer(exif, "Orientation", &orientation))
434 /* see http://jpegclub.org/exif_orientation.html
437 888888 888888 88 88 8888888888 88 88 8888888888
438 88 88 88 88 88 88 88 88 88 88 88 88
439 8888 8888 8888 8888 88 8888888888 8888888888 88
445 case EXIF_ORIENTATION_TOP_LEFT:
446 /* normal -- nothing to do */
449 case EXIF_ORIENTATION_TOP_RIGHT:
451 imd->delay_alter_type = ALTER_MIRROR;
453 case EXIF_ORIENTATION_BOTTOM_RIGHT:
455 imd->delay_alter_type = ALTER_ROTATE_180;
457 case EXIF_ORIENTATION_BOTTOM_LEFT:
459 imd->delay_alter_type = ALTER_FLIP;
461 case EXIF_ORIENTATION_LEFT_TOP:
462 /* not implemented -- too wacky to fix in one step */
465 case EXIF_ORIENTATION_RIGHT_TOP:
466 /* rotated -90 (270) */
467 imd->delay_alter_type = ALTER_ROTATE_90;
469 case EXIF_ORIENTATION_RIGHT_BOTTOM:
470 /* not implemented -- too wacky to fix in one step */
473 case EXIF_ORIENTATION_LEFT_BOTTOM:
475 imd->delay_alter_type = ALTER_ROTATE_90_CC;
478 /* The other values are out of range */
483 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
487 if (imd->color_profile_enable)
489 if (!image_post_process_color(imd, 0, exif))
491 /* fixme: note error to user */
492 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
496 if (!imd->cm) image_post_process_alter(imd, clamp);
502 *-------------------------------------------------------------------
503 * read ahead (prebuffer)
504 *-------------------------------------------------------------------
507 static void image_read_ahead_cancel(ImageWindow *imd)
509 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_fd->path);
511 image_loader_free(imd->read_ahead_il);
512 imd->read_ahead_il = NULL;
514 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
515 imd->read_ahead_pixbuf = NULL;
517 file_data_unref(imd->read_ahead_fd);
518 imd->read_ahead_fd = NULL;
521 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
523 ImageWindow *imd = data;
525 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_fd->path);
527 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
528 if (imd->read_ahead_pixbuf)
530 g_object_ref(imd->read_ahead_pixbuf);
534 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
536 image_loader_free(imd->read_ahead_il);
537 imd->read_ahead_il = NULL;
539 image_complete_util(imd, TRUE);
542 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
544 /* we even treat errors as success, maybe at least some of the file was ok */
545 image_read_ahead_done_cb(il, data);
548 static void image_read_ahead_start(ImageWindow *imd)
550 /* already started ? */
551 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
553 /* still loading ?, do later */
554 if (imd->il || imd->cm) return;
556 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_fd->path);
558 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
560 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
561 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
563 image_read_ahead_cancel(imd);
564 image_complete_util(imd, TRUE);
568 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
570 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
572 image_read_ahead_cancel(imd);
574 imd->read_ahead_fd = file_data_ref(fd);
576 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
578 image_read_ahead_start(imd);
582 *-------------------------------------------------------------------
584 *-------------------------------------------------------------------
587 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
589 file_data_unref(imd->prev_fd);
590 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
594 imd->prev_fd = file_data_ref(fd);
596 g_object_ref(pixbuf);
597 imd->prev_pixbuf = pixbuf;
598 imd->prev_color_row = color_row;
603 imd->prev_pixbuf = NULL;
604 imd->prev_color_row = -1;
607 if (debug) printf("post buffer set: %s\n", fd->path);
610 static gint image_post_buffer_get(ImageWindow *imd)
614 if (imd->prev_pixbuf &&
615 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
617 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
618 if (imd->prev_color_row >= 0)
620 ExifData *exif = NULL;
622 if (imd->color_profile_use_image) exif = exif_read(imd->image_fd, TRUE);
623 image_post_process_color(imd, imd->prev_color_row, exif);
633 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
634 imd->prev_pixbuf = NULL;
636 file_data_unref(imd->prev_fd);
643 *-------------------------------------------------------------------
645 *-------------------------------------------------------------------
648 static void image_load_pixbuf_ready(ImageWindow *imd)
650 if (image_get_pixbuf(imd) || !imd->il) return;
652 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
655 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
657 ImageWindow *imd = data;
660 pr = (PixbufRenderer *)imd->pr;
662 if (imd->delay_flip &&
663 pr->pixbuf != image_loader_get_pixbuf(il))
668 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
670 pixbuf_renderer_area_changed(pr, x, y, w, h);
673 static void image_load_done_cb(ImageLoader *il, gpointer data)
675 ImageWindow *imd = data;
677 if (debug) printf ("image done\n");
679 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
680 image_state_unset(imd, IMAGE_STATE_LOADING);
682 if (imd->delay_flip &&
683 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
685 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
686 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
689 image_loader_free(imd->il);
692 image_post_process(imd, TRUE);
694 image_read_ahead_start(imd);
697 static void image_load_error_cb(ImageLoader *il, gpointer data)
699 if (debug) printf ("image error\n");
701 /* even on error handle it like it was done,
702 * since we have a pixbuf with _something_ */
704 image_load_done_cb(il, data);
707 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
708 static void image_load_buffer_throttle(ImageLoader *il)
710 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
712 /* Larger image files usually have larger chunks of data per pixel...
713 * So increase the buffer read size so that the rendering chunks called
717 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
721 /* this read ahead is located here merely for the callbacks, above */
723 static gint image_read_ahead_check(ImageWindow *imd)
725 if (!imd->read_ahead_fd) return FALSE;
726 if (imd->il) return FALSE;
728 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
730 image_read_ahead_cancel(imd);
734 if (imd->read_ahead_il)
736 imd->il = imd->read_ahead_il;
737 imd->read_ahead_il = NULL;
739 /* override the old signals */
740 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
741 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
742 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
744 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
745 image_load_buffer_throttle(imd->il);
748 /* do this one directly (probably should add a set func) */
749 imd->il->func_done = image_load_done_cb;
751 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
752 image_state_set(imd, IMAGE_STATE_LOADING);
754 if (!imd->delay_flip)
756 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
759 image_read_ahead_cancel(imd);
762 else if (imd->read_ahead_pixbuf)
764 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
765 g_object_unref(imd->read_ahead_pixbuf);
766 imd->read_ahead_pixbuf = NULL;
768 image_read_ahead_cancel(imd);
770 image_post_process(imd, FALSE);
774 image_read_ahead_cancel(imd);
778 static gint image_load_begin(ImageWindow *imd, FileData *fd)
780 if (debug) printf ("image begin \n");
782 if (imd->il) return FALSE;
784 imd->completed = FALSE;
785 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
787 if (image_post_buffer_get(imd))
789 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
793 if (image_read_ahead_check(imd))
795 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
799 if (!imd->delay_flip && image_get_pixbuf(imd))
803 pr = PIXBUF_RENDERER(imd->pr);
804 if (pr->pixbuf) g_object_unref(pr->pixbuf);
808 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
810 imd->il = image_loader_new(fd);
812 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
813 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
814 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
816 if (!image_loader_start(imd->il, image_load_done_cb, imd))
818 if (debug) printf("image start error\n");
820 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
822 image_loader_free(imd->il);
825 image_complete_util(imd, FALSE);
830 image_state_set(imd, IMAGE_STATE_LOADING);
832 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
833 image_load_buffer_throttle(imd->il);
836 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
841 static void image_reset(ImageWindow *imd)
843 /* stops anything currently being done */
845 if (debug) printf("image reset\n");
847 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
849 image_loader_free(imd->il);
852 color_man_free((ColorMan *)imd->cm);
855 imd->delay_alter_type = ALTER_NONE;
857 image_state_set(imd, IMAGE_STATE_NONE);
861 *-------------------------------------------------------------------
863 *-------------------------------------------------------------------
866 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
870 if (imd->image_fd && isfile(imd->image_fd->path))
874 pr = PIXBUF_RENDERER(imd->pr);
875 pr->zoom = zoom; /* store the zoom, needed by the loader */
877 if (image_load_begin(imd, imd->image_fd))
879 imd->unknown = FALSE;
885 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
886 image_change_pixbuf(imd, pixbuf, zoom);
887 g_object_unref(pixbuf);
891 imd->size = filesize(imd->image_fd->path);
892 imd->mtime = filetime(imd->image_fd->path);
900 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
901 image_change_pixbuf(imd, pixbuf, zoom);
902 g_object_unref(pixbuf);
903 imd->mtime = filetime(imd->image_fd->path);
907 image_change_pixbuf(imd, NULL, zoom);
914 image_update_util(imd);
917 static void image_change_real(ImageWindow *imd, FileData *fd,
918 CollectionData *cd, CollectInfo *info, gdouble zoom)
921 GdkPixbuf *prev_pixbuf = NULL;
922 FileData *prev_fd = NULL;
923 gint prev_clear = FALSE;
924 gint prev_color_row = -1;
926 imd->collection = cd;
927 imd->collection_info = info;
929 pixbuf = image_get_pixbuf(imd);
931 if (enable_read_ahead && imd->image_fd && pixbuf)
935 /* current image is not finished */
940 prev_fd = file_data_ref(imd->image_fd);
941 prev_pixbuf = pixbuf;
942 g_object_ref(prev_pixbuf);
948 cm = (ColorMan *)imd->cm;
949 prev_color_row = cm->row;
954 file_data_unref(imd->image_fd);
955 imd->image_fd = file_data_ref(fd);
957 image_change_complete(imd, zoom, TRUE);
961 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
962 file_data_unref(prev_fd);
963 g_object_unref(prev_pixbuf);
967 image_post_buffer_set(imd, NULL, NULL, -1);
970 image_update_title(imd);
971 image_state_set(imd, IMAGE_STATE_IMAGE);
975 *-------------------------------------------------------------------
977 *-------------------------------------------------------------------
980 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
984 widget = imd->widget;
985 if (!widget->window) return;
989 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
990 area, widget, "image_window",
991 widget->allocation.x, widget->allocation.y,
992 widget->allocation.width - 1, widget->allocation.height - 1);
996 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
997 area, widget, "image_window",
998 widget->allocation.x, widget->allocation.y,
999 widget->allocation.width - 1, widget->allocation.height - 1);
1003 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1005 ImageWindow *imd = data;
1007 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1011 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1013 ImageWindow *imd = data;
1015 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1016 image_focus_paint(imd, TRUE, NULL);
1021 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1023 ImageWindow *imd = data;
1025 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1026 image_focus_paint(imd, FALSE, NULL);
1031 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1032 gint relative, gint always)
1034 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1037 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1039 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1042 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1044 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1047 void image_overlay_remove(ImageWindow *imd, gint id)
1049 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1052 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1054 ImageWindow *imd = data;
1056 if (imd->func_scroll &&
1057 event && event->type == GDK_SCROLL)
1059 imd->func_scroll(imd, event->direction, event->time,
1060 event->x, event->y, event->state, imd->data_scroll);
1068 *-------------------------------------------------------------------
1070 *-------------------------------------------------------------------
1073 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1074 const gchar *title, const gchar *title_right, gint show_zoom)
1076 imd->top_window = window;
1078 imd->title = g_strdup(title);
1079 g_free(imd->title_right);
1080 imd->title_right = g_strdup(title_right);
1081 imd->title_show_zoom = show_zoom;
1083 if (!fit_window) window = NULL;
1085 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1087 image_update_title(imd);
1090 void image_set_update_func(ImageWindow *imd,
1091 void (*func)(ImageWindow *imd, gpointer data),
1094 imd->func_update = func;
1095 imd->data_update = data;
1098 void image_set_complete_func(ImageWindow *imd,
1099 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1102 imd->func_complete = func;
1103 imd->data_complete = data;
1106 void image_set_state_func(ImageWindow *imd,
1107 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1110 imd->func_state = func;
1111 imd->data_state = data;
1115 void image_set_button_func(ImageWindow *imd,
1116 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1119 imd->func_button = func;
1120 imd->data_button = data;
1123 void image_set_drag_func(ImageWindow *imd,
1124 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1127 imd->func_drag = func;
1128 imd->data_drag = data;
1131 void image_set_scroll_func(ImageWindow *imd,
1132 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1135 imd->func_scroll = func;
1136 imd->data_scroll = data;
1139 void image_set_scroll_notify_func(ImageWindow *imd,
1140 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1143 imd->func_scroll_notify = func;
1144 imd->data_scroll_notify = data;
1149 const gchar *image_get_path(ImageWindow *imd)
1151 if (imd->image_fd == NULL) return NULL;
1152 return imd->image_fd->path;
1155 const gchar *image_get_name(ImageWindow *imd)
1157 if (imd->image_fd == NULL) return NULL;
1158 return imd->image_fd->name;
1161 FileData *image_get_fd(ImageWindow *imd)
1163 return imd->image_fd;
1166 /* merely changes path string, does not change the image! */
1167 void image_set_fd(ImageWindow *imd, FileData *fd)
1169 file_data_unref(imd->image_fd);
1170 imd->image_fd = file_data_ref(fd);
1172 image_update_title(imd);
1173 image_state_set(imd, IMAGE_STATE_IMAGE);
1176 /* load a new image */
1178 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1180 if (imd->image_fd == fd) return;
1182 image_change_real(imd, fd, NULL, NULL, zoom);
1185 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1187 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1190 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1192 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1193 image_state_set(imd, IMAGE_STATE_IMAGE);
1196 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1198 if (!cd || !info || !g_list_find(cd->list, info)) return;
1200 image_change_real(imd, info->fd, cd, info, zoom);
1203 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1205 if (collection_to_number(imd->collection) >= 0)
1207 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1209 if (info) *info = imd->collection_info;
1213 if (info) *info = NULL;
1215 return imd->collection;
1218 if (info) *info = NULL;
1222 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1224 /* change data for the callbacks directly */
1226 il->data_area_ready = data;
1227 il->data_error = data;
1228 il->data_done = data;
1229 il->data_percent = data;
1232 /* this is more like a move function
1233 * it moves most data from source to imd
1235 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1237 if (imd == source) return;
1239 imd->unknown = source->unknown;
1241 imd->collection = source->collection;
1242 imd->collection_info = source->collection_info;
1243 imd->size = source->size;
1244 imd->mtime = source->mtime;
1246 image_set_fd(imd, image_get_fd(source));
1248 image_loader_free(imd->il);
1253 imd->il = source->il;
1256 image_loader_sync_data(imd->il, imd);
1258 imd->delay_alter_type = source->delay_alter_type;
1259 source->delay_alter_type = ALTER_NONE;
1262 imd->color_profile_enable = source->color_profile_enable;
1263 imd->color_profile_input = source->color_profile_input;
1264 imd->color_profile_screen = source->color_profile_screen;
1265 imd->color_profile_use_image = source->color_profile_use_image;
1266 color_man_free((ColorMan *)imd->cm);
1272 imd->cm = source->cm;
1275 cm = (ColorMan *)imd->cm;
1277 cm->func_done_data = imd;
1280 image_loader_free(imd->read_ahead_il);
1281 imd->read_ahead_il = source->read_ahead_il;
1282 source->read_ahead_il = NULL;
1283 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1285 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1286 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1287 source->read_ahead_pixbuf = NULL;
1289 file_data_unref(imd->read_ahead_fd);
1290 imd->read_ahead_fd = source->read_ahead_fd;
1291 source->read_ahead_fd = NULL;
1293 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1294 imd->prev_pixbuf = source->prev_pixbuf;
1295 source->prev_pixbuf = NULL;
1296 imd->prev_color_row = source->prev_color_row;
1297 source->prev_color_row = -1;
1299 file_data_unref(imd->prev_fd);
1300 imd->prev_fd = source->prev_fd;
1301 source->prev_fd = NULL;
1303 imd->completed = source->completed;
1304 imd->state = source->state;
1305 source->state = IMAGE_STATE_NONE;
1307 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1312 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1314 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1317 void image_reload(ImageWindow *imd)
1319 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1321 image_change_complete(imd, image_zoom_get(imd), FALSE);
1324 void image_scroll(ImageWindow *imd, gint x, gint y)
1326 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1329 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1330 gdouble x_align, gdouble y_align)
1332 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1335 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1337 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1340 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1342 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1347 void image_alter(ImageWindow *imd, AlterType type)
1349 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1351 if (imd->il || imd->cm)
1353 /* still loading, wait till done */
1354 imd->delay_alter_type = type;
1355 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1357 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1359 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1364 image_alter_real(imd, type, TRUE);
1367 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1369 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1372 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1374 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1377 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1379 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1382 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1384 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1387 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1393 pr = (PixbufRenderer *)imd->pr;
1395 if (!pixbuf_renderer_get_pixbuf(pr) ||
1396 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1400 zoom = (gdouble)pr->window_height / height;
1404 zoom = (gdouble)pr->window_width / width;
1409 zoom = 0.0 - 1.0 / zoom;
1412 pixbuf_renderer_zoom_set(pr, zoom);
1415 gdouble image_zoom_get(ImageWindow *imd)
1417 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1420 gdouble image_zoom_get_real(ImageWindow *imd)
1422 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1425 gchar *image_zoom_get_as_text(ImageWindow *imd)
1433 gchar *approx = " ";
1435 zoom = image_zoom_get(imd);
1436 scale = image_zoom_get_real(imd);
1442 else if (zoom < 0.0)
1446 else if (zoom == 0.0 && scale != 0.0)
1459 if (rint(l) != l) pl = 1;
1460 if (rint(r) != r) pr = 1;
1462 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1465 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1469 if (mode == ZOOM_RESET_ORIGINAL)
1473 else if (mode == ZOOM_RESET_FIT_WINDOW)
1481 zoom = image_zoom_get(imd);
1494 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1496 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1500 image_read_ahead_set(imd, fd);
1504 image_read_ahead_cancel(imd);
1508 static gint image_auto_refresh_cb(gpointer data)
1510 ImageWindow *imd = data;
1513 if (!imd || !image_get_pixbuf(imd) ||
1514 imd->il || !imd->image_fd ||
1515 !update_on_time_change) return TRUE;
1517 newtime = filetime(imd->image_fd->path);
1518 if (newtime > 0 && newtime != imd->mtime)
1520 imd->mtime = newtime;
1527 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1529 void image_auto_refresh(ImageWindow *imd, gint interval)
1532 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1534 if (imd->auto_refresh_id > -1)
1536 g_source_remove(imd->auto_refresh_id);
1537 imd->auto_refresh_id = -1;
1538 imd->auto_refresh_interval = -1;
1541 if (interval < 0) return;
1543 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1545 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1546 imd->auto_refresh_interval = interval;
1549 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1551 imd->top_window_sync = allow_sync;
1553 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1556 void image_background_set_black(ImageWindow *imd, gint black)
1558 pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1561 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1563 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1566 void image_color_profile_set(ImageWindow *imd,
1567 gint input_type, gint screen_type,
1572 if (input_type < 0 || input_type > COLOR_PROFILE_INPUTS ||
1573 screen_type < 0 || screen_type > 1)
1578 imd->color_profile_input = input_type;
1579 imd->color_profile_screen = screen_type;
1580 imd->color_profile_use_image = use_image;
1583 gint image_color_profile_get(ImageWindow *imd,
1584 gint *input_type, gint *screen_type,
1587 if (!imd) return FALSE;
1589 if (input_type) *input_type = imd->color_profile_input;
1590 if (screen_type) *screen_type = imd->color_profile_screen;
1591 if (use_image) *use_image = imd->color_profile_use_image;
1596 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1600 if (imd->color_profile_enable == enable) return;
1602 imd->color_profile_enable = enable;
1605 gint image_color_profile_get_use(ImageWindow *imd)
1607 if (!imd) return FALSE;
1609 return imd->color_profile_enable;
1612 void image_set_delay_flip(ImageWindow *imd, gint delay)
1615 imd->delay_flip == delay) return;
1617 imd->delay_flip = delay;
1619 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1621 if (!imd->delay_flip && imd->il)
1625 pr = PIXBUF_RENDERER(imd->pr);
1626 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1629 image_load_pixbuf_ready(imd);
1633 void image_to_root_window(ImageWindow *imd, gint scaled)
1636 GdkWindow *rootwindow;
1644 pixbuf = image_get_pixbuf(imd);
1645 if (!pixbuf) return;
1647 screen = gtk_widget_get_screen(imd->widget);
1648 rootwindow = gdk_screen_get_root_window(screen);
1649 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1653 width = gdk_screen_width();
1654 height = gdk_screen_height();
1658 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1661 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1663 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1664 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1665 gdk_window_clear(rootwindow);
1667 g_object_unref(pixmap);
1672 void image_select(ImageWindow *imd, gboolean select)
1678 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1679 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1682 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1688 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1694 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1695 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1699 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1700 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1706 *-------------------------------------------------------------------
1708 *-------------------------------------------------------------------
1711 static void image_options_set(ImageWindow *imd)
1713 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1714 "zoom_2pass", two_pass_zoom,
1715 "zoom_expand", zoom_to_fit_expands,
1716 "dither_quality", dither_quality,
1717 "scroll_reset", scroll_reset_method,
1718 "cache_display", tile_cache_max,
1719 "window_fit", (imd->top_window_sync && fit_window),
1720 "window_limit", limit_window_size,
1721 "window_limit_value", max_window_size,
1724 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1727 void image_options_sync(void)
1739 image_options_set(imd);
1744 *-------------------------------------------------------------------
1746 *-------------------------------------------------------------------
1749 static void image_free(ImageWindow *imd)
1751 image_list = g_list_remove(image_list, imd);
1755 image_read_ahead_cancel(imd);
1756 image_post_buffer_set(imd, NULL, NULL, -1);
1757 image_auto_refresh(imd, -1);
1759 file_data_unref(imd->image_fd);
1761 g_free(imd->title_right);
1766 static void image_destroy_cb(GtkObject *widget, gpointer data)
1768 ImageWindow *imd = data;
1772 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1774 gtk_paint_flat_box(widget->style,
1777 GTK_FRAME (widget)->shadow_type,
1781 widget->allocation.x + 3, widget->allocation.y + 3,
1782 widget->allocation.width - 6, widget->allocation.height - 6);
1789 void image_set_frame(ImageWindow *imd, gboolean frame)
1793 if (frame == imd->has_frame) return;
1795 gtk_widget_hide(imd->pr);
1799 imd->frame = gtk_frame_new(NULL);
1800 gtk_widget_ref(imd->pr);
1801 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1802 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1803 gtk_widget_unref(imd->pr);
1804 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1805 G_CALLBACK (selectable_frame_expose_cb), NULL);
1807 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1808 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1809 G_CALLBACK(image_focus_in_cb), imd);
1810 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1811 G_CALLBACK(image_focus_out_cb), imd);
1813 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1814 G_CALLBACK(image_focus_expose), imd);
1817 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1818 gtk_widget_show(imd->frame);
1822 gtk_widget_ref(imd->pr);
1825 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1826 gtk_widget_destroy(imd->frame);
1829 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
1830 gtk_widget_unref(imd->pr);
1833 gtk_widget_show(imd->pr);
1835 imd->has_frame = frame;
1838 ImageWindow *image_new(gint frame)
1842 imd = g_new0(ImageWindow, 1);
1844 imd->top_window = NULL;
1846 imd->title_right = NULL;
1847 imd->title_show_zoom = FALSE;
1849 imd->unknown = TRUE;
1851 imd->has_frame = -1; /* not initialized; for image_set_frame */
1852 imd->top_window_sync = FALSE;
1854 imd->delay_alter_type = ALTER_NONE;
1856 imd->read_ahead_il = NULL;
1857 imd->read_ahead_pixbuf = NULL;
1858 imd->read_ahead_fd = NULL;
1860 imd->completed = FALSE;
1861 imd->state = IMAGE_STATE_NONE;
1863 imd->color_profile_enable = FALSE;
1864 imd->color_profile_input = 0;
1865 imd->color_profile_screen = 0;
1866 imd->color_profile_use_image = FALSE;
1868 imd->auto_refresh_id = -1;
1869 imd->auto_refresh_interval = -1;
1871 imd->delay_flip = FALSE;
1873 imd->func_update = NULL;
1874 imd->func_complete = NULL;
1875 imd->func_tile_request = NULL;
1876 imd->func_tile_dispose = NULL;
1878 imd->func_button = NULL;
1879 imd->func_scroll = NULL;
1881 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1883 image_options_set(imd);
1886 imd->widget = gtk_vbox_new(0, 0);
1888 image_set_frame(imd, frame);
1890 image_set_selectable(imd, 0);
1892 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1893 G_CALLBACK(image_click_cb), imd);
1894 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1895 G_CALLBACK(image_scroll_notify_cb), imd);
1897 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1898 G_CALLBACK(image_scroll_cb), imd);
1900 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1901 G_CALLBACK(image_destroy_cb), imd);
1903 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1904 G_CALLBACK(image_zoom_cb), imd);
1905 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1906 G_CALLBACK(image_render_complete_cb), imd);
1907 g_signal_connect(G_OBJECT(imd->pr), "drag",
1908 G_CALLBACK(image_drag_cb), imd);
1910 image_list = g_list_append(image_list, imd);