4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
19 #include "color-man.h"
21 #include "histogram.h"
22 #include "image-load.h"
23 #include "image-overlay.h"
25 #include "layout_image.h"
26 #include "pixbuf-renderer.h"
27 #include "pixbuf_util.h"
28 #include "ui_fileops.h"
35 /* size of the image loader buffer (512 bytes x defined number) */
36 #define IMAGE_LOAD_BUFFER_COUNT 8
38 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
39 #define IMAGE_THROTTLE_LARGER_IMAGES 1
41 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
42 #define IMAGE_THROTTLE_FACTOR 32
44 /* the file size at which throttling take place */
45 #define IMAGE_THROTTLE_THRESHOLD 1048576
47 #define IMAGE_AUTO_REFRESH_TIME 3000
50 static GList *image_list = NULL;
53 static void image_update_title(ImageWindow *imd);
54 static void image_post_process(ImageWindow *imd, gint clamp);
55 static void image_read_ahead_start(ImageWindow *imd);
58 *-------------------------------------------------------------------
60 *-------------------------------------------------------------------
63 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
65 ImageWindow *imd = data;
69 imd->func_button(imd, event->button, event->time,
70 event->x, event->y, event->state, imd->data_button);
74 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
76 ImageWindow *imd = data;
79 pixbuf_renderer_get_scaled_size(pr, &width, &height);
83 imd->func_drag(imd, event->button, event->time,
84 event->x, event->y, event->state,
85 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
90 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
92 ImageWindow *imd = data;
94 if (imd->func_scroll_notify && pr->scale)
96 imd->func_scroll_notify(imd,
97 (gint)((gdouble)pr->x_scroll / pr->scale),
98 (gint)((gdouble)pr->y_scroll / pr->scale),
99 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
100 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
101 imd->data_scroll_notify);
105 static void image_update_util(ImageWindow *imd)
107 if (imd->func_update) imd->func_update(imd, imd->data_update);
110 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
112 ImageWindow *imd = data;
114 if (imd->title_show_zoom) image_update_title(imd);
115 if (imd->overlay_show_zoom) image_osd_update(imd);
117 image_update_util(imd);
120 static void image_complete_util(ImageWindow *imd, gint preload)
122 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
124 DEBUG_1("%s image load completed \"%s\" (%s)", get_exec_time(),
125 (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") :
126 (imd->image_fd ? imd->image_fd->path : "null"),
127 (preload) ? "preload" : "current");
129 if (!preload) imd->completed = TRUE;
130 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
133 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
135 ImageWindow *imd = data;
137 image_complete_util(imd, FALSE);
140 static void image_state_set(ImageWindow *imd, ImageState state)
142 if (state == IMAGE_STATE_NONE)
150 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
153 static void image_state_unset(ImageWindow *imd, ImageState state)
155 imd->state &= ~state;
156 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
160 *-------------------------------------------------------------------
162 *-------------------------------------------------------------------
165 static void image_update_title(ImageWindow *imd)
169 gchar *collection = NULL;
171 if (!imd->top_window) return;
173 if (imd->collection && collection_to_number(imd->collection) >= 0)
176 name = imd->collection->name;
177 if (!name) name = _("Untitled");
178 collection = g_strdup_printf(" (Collection %s)", name);
181 if (imd->title_show_zoom)
183 gchar *buf = image_zoom_get_as_text(imd);
184 zoom = g_strconcat(" [", buf, "]", NULL);
188 title = g_strdup_printf("%s%s%s%s%s%s",
189 imd->title ? imd->title : "",
190 imd->image_fd ? imd->image_fd->name : "",
192 collection ? collection : "",
193 imd->image_fd ? " - " : "",
194 imd->title_right ? imd->title_right : "");
196 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
204 *-------------------------------------------------------------------
205 * rotation, flip, etc.
206 *-------------------------------------------------------------------
212 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
215 GdkPixbuf *new = NULL;
220 pr = (PixbufRenderer *)imd->pr;
222 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
223 imd->delay_alter_type = ALTER_NONE;
225 if (!pr->pixbuf) return;
227 x = pr->x_scroll + (pr->vis_width / 2);
228 y = pr->y_scroll + (pr->vis_height / 2);
232 case ALTER_ROTATE_90:
233 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
238 case ALTER_ROTATE_90_CC:
239 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
244 case ALTER_ROTATE_180:
245 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
250 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
254 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
257 case ALTER_DESATURATE:
258 pixbuf_desaturate_rect(pr->pixbuf,
259 0, 0, pr->image_width, pr->image_height);
260 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
261 layout_image_overlay_update(layout_find_by_image(imd));
271 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
274 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
278 switch (pr->scroll_reset)
280 case PR_SCROLL_RESET_NOCHANGE:
282 case PR_SCROLL_RESET_CENTER:
283 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
284 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
286 case PR_SCROLL_RESET_TOPLEFT:
293 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
294 (gint)((gdouble)y / pr->scale),
298 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
299 layout_image_overlay_update(layout_find_by_image(imd));
300 DEBUG_1("%s image postprocess done: %s", get_exec_time(), imd->image_fd->name);
303 static void image_post_process_alter(ImageWindow *imd, gint clamp)
305 if (imd->delay_alter_type != ALTER_NONE)
307 image_alter_real(imd, imd->delay_alter_type, clamp);
312 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
314 ImageWindow *imd = data;
317 if (type == COLOR_RETURN_IMAGE_CHANGED)
319 if (cm == imd->cm) imd->cm = NULL;
324 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
325 DEBUG_1("%s image postprocess cm done: %s", get_exec_time(), imd->image_fd->name);
327 image_post_process_alter(imd, FALSE);
329 image_read_ahead_start(imd);
333 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg)
336 ColorManProfileType input_type;
337 ColorManProfileType screen_type;
338 const gchar *input_file;
339 const gchar *screen_file;
340 unsigned char *profile = NULL;
343 if (imd->cm) return FALSE;
345 if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
346 imd->color_profile_input < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
350 n = imd->color_profile_input - COLOR_PROFILE_FILE;
351 if (!options->color_profile.input_file[n]) return FALSE;
353 input_type = COLOR_PROFILE_FILE;
354 input_file = options->color_profile.input_file[n];
356 else if (imd->color_profile_input >= COLOR_PROFILE_SRGB &&
357 imd->color_profile_input < COLOR_PROFILE_FILE)
359 input_type = imd->color_profile_input;
367 if (imd->color_profile_screen == 1 &&
368 options->color_profile.screen_file)
370 screen_type = COLOR_PROFILE_FILE;
371 screen_file = options->color_profile.screen_file;
373 else if (imd->color_profile_screen == 0)
375 screen_type = COLOR_PROFILE_SRGB;
382 imd->color_profile_from_image = COLOR_PROFILE_NONE;
384 if (imd->color_profile_use_image && exif)
386 profile = exif_get_color_profile(exif, &profile_len);
390 gchar *interop_index;
392 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
393 if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
394 interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
398 input_type = COLOR_PROFILE_SRGB;
400 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
402 DEBUG_1("Found EXIF ColorSpace of sRGB");
404 if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
406 input_type = COLOR_PROFILE_ADOBERGB;
408 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
410 DEBUG_1("Found EXIF ColorSpace of AdobeRGB");
413 g_free(interop_index);
419 DEBUG_1("Found embedded color profile");
420 imd->color_profile_from_image = COLOR_PROFILE_MEM;
422 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
423 profile, profile_len,
424 screen_type, screen_file);
429 cm = color_man_new(run_in_bg ? imd : NULL, NULL,
430 input_type, input_file,
431 screen_type, screen_file);
439 cm->incremental_sync = TRUE;
442 imd->cm = (gpointer)cm;
444 if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd);
452 static void image_post_process(ImageWindow *imd, gint clamp)
455 ExifData *exif = NULL;
457 if (!image_get_pixbuf(imd)) return;
459 DEBUG_1("%s image postprocess: %s", get_exec_time(), imd->image_fd->name);
461 if (options->image.exif_rotate_enable ||
462 (imd->color_profile_enable && imd->color_profile_use_image) )
464 exif = exif_read_fd(imd->image_fd);
466 if (options->image.exif_rotate_enable && exif)
470 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
474 /* see http://jpegclub.org/exif_orientation.html
477 888888 888888 88 88 8888888888 88 88 8888888888
478 88 88 88 88 88 88 88 88 88 88 88 88
479 8888 8888 8888 8888 88 8888888888 8888888888 88
485 case EXIF_ORIENTATION_TOP_LEFT:
486 /* normal -- nothing to do */
489 case EXIF_ORIENTATION_TOP_RIGHT:
491 imd->delay_alter_type = ALTER_MIRROR;
493 case EXIF_ORIENTATION_BOTTOM_RIGHT:
495 imd->delay_alter_type = ALTER_ROTATE_180;
497 case EXIF_ORIENTATION_BOTTOM_LEFT:
499 imd->delay_alter_type = ALTER_FLIP;
501 case EXIF_ORIENTATION_LEFT_TOP:
502 /* not implemented -- too wacky to fix in one step */
505 case EXIF_ORIENTATION_RIGHT_TOP:
506 /* rotated -90 (270) */
507 imd->delay_alter_type = ALTER_ROTATE_90;
509 case EXIF_ORIENTATION_RIGHT_BOTTOM:
510 /* not implemented -- too wacky to fix in one step */
513 case EXIF_ORIENTATION_LEFT_BOTTOM:
515 imd->delay_alter_type = ALTER_ROTATE_90_CC;
518 /* The other values are out of range */
523 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
526 if (imd->color_profile_enable)
528 if (!image_post_process_color(imd, 0, exif, TRUE))
530 /* fixme: note error to user */
531 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
536 if (!imd->cm) image_post_process_alter(imd, clamp);
542 static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data)
544 ImageWindow *imd = (ImageWindow *)data;
545 if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h);
546 if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h);
550 void image_alter(ImageWindow *imd, AlterType type)
552 static const gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1};
553 static const gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3};
554 static const gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6};
555 static const gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7};
556 static const gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5};
559 if (!imd || !imd->pr) return;
561 if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
565 case ALTER_ROTATE_90:
566 imd->orientation = rotate_90[imd->orientation];
568 case ALTER_ROTATE_90_CC:
569 imd->orientation = rotate_90_cc[imd->orientation];
571 case ALTER_ROTATE_180:
572 imd->orientation = rotate_180[imd->orientation];
575 imd->orientation = mirror[imd->orientation];
578 imd->orientation = flip[imd->orientation];
580 case ALTER_DESATURATE:
581 imd->desaturate = !imd->desaturate;
584 imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1;
585 imd->desaturate = FALSE;
592 if (type != ALTER_NONE && type != ALTER_DESATURATE)
594 if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd);
595 imd->image_fd->user_orientation = imd->orientation;
599 if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd);
600 imd->image_fd->user_orientation = 0;
603 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
604 if (imd->cm || imd->desaturate)
605 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
607 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
612 *-------------------------------------------------------------------
613 * read ahead (prebuffer)
614 *-------------------------------------------------------------------
617 static void image_read_ahead_cancel(ImageWindow *imd)
619 DEBUG_1("%s read ahead cancelled for :%s", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
621 image_loader_free(imd->read_ahead_il);
622 imd->read_ahead_il = NULL;
624 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
625 imd->read_ahead_pixbuf = NULL;
627 file_data_unref(imd->read_ahead_fd);
628 imd->read_ahead_fd = NULL;
631 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
633 ImageWindow *imd = data;
635 DEBUG_1("%s read ahead done for :%s", get_exec_time(), imd->read_ahead_fd->path);
637 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
638 if (imd->read_ahead_pixbuf)
640 g_object_ref(imd->read_ahead_pixbuf);
644 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
646 image_loader_free(imd->read_ahead_il);
647 imd->read_ahead_il = NULL;
649 image_complete_util(imd, TRUE);
652 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
654 /* we even treat errors as success, maybe at least some of the file was ok */
655 image_read_ahead_done_cb(il, data);
658 static void image_read_ahead_start(ImageWindow *imd)
660 /* already started ? */
661 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
663 /* still loading ?, do later */
664 if (imd->il /*|| imd->cm*/) return;
666 DEBUG_1("%s read ahead started for :%s", get_exec_time(), imd->read_ahead_fd->path);
668 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
670 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
671 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
673 image_read_ahead_cancel(imd);
674 image_complete_util(imd, TRUE);
678 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
680 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
682 image_read_ahead_cancel(imd);
684 imd->read_ahead_fd = file_data_ref(fd);
686 DEBUG_1("read ahead set to :%s", imd->read_ahead_fd->path);
688 image_read_ahead_start(imd);
692 *-------------------------------------------------------------------
694 *-------------------------------------------------------------------
697 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
699 file_data_unref(imd->prev_fd);
700 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
704 imd->prev_fd = file_data_ref(fd);
706 g_object_ref(pixbuf);
707 imd->prev_pixbuf = pixbuf;
708 imd->prev_color_row = color_row;
713 imd->prev_pixbuf = NULL;
714 imd->prev_color_row = -1;
717 DEBUG_1("%s post buffer set: %s", get_exec_time(), fd ? fd->path : "null");
720 static gint image_post_buffer_get(ImageWindow *imd)
724 if (imd->prev_pixbuf &&
725 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
727 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
728 if (imd->prev_color_row >= 0)
730 ExifData *exif = NULL;
732 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
733 // image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
743 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
744 imd->prev_pixbuf = NULL;
746 file_data_unref(imd->prev_fd);
753 *-------------------------------------------------------------------
755 *-------------------------------------------------------------------
758 static void image_load_pixbuf_ready(ImageWindow *imd)
760 if (image_get_pixbuf(imd) || !imd->il) return;
762 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
765 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
767 ImageWindow *imd = data;
770 pr = (PixbufRenderer *)imd->pr;
772 if (imd->delay_flip &&
773 pr->pixbuf != image_loader_get_pixbuf(il))
778 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
780 pixbuf_renderer_area_changed(pr, x, y, w, h);
783 static void image_load_done_cb(ImageLoader *il, gpointer data)
785 ImageWindow *imd = data;
787 DEBUG_1("%s image done", get_exec_time());
789 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
790 image_state_unset(imd, IMAGE_STATE_LOADING);
792 if (imd->delay_flip &&
793 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
795 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
796 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
799 image_loader_free(imd->il);
802 image_post_process(imd, TRUE);
804 image_read_ahead_start(imd);
807 static void image_load_error_cb(ImageLoader *il, gpointer data)
809 DEBUG_1("%s image error", get_exec_time());
811 /* even on error handle it like it was done,
812 * since we have a pixbuf with _something_ */
814 image_load_done_cb(il, data);
817 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
818 static void image_load_buffer_throttle(ImageLoader *il)
820 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
822 /* Larger image files usually have larger chunks of data per pixel...
823 * So increase the buffer read size so that the rendering chunks called
827 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
831 /* this read ahead is located here merely for the callbacks, above */
833 static gint image_read_ahead_check(ImageWindow *imd)
835 if (!imd->read_ahead_fd) return FALSE;
836 if (imd->il) return FALSE;
838 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
840 image_read_ahead_cancel(imd);
844 if (imd->read_ahead_il)
846 imd->il = imd->read_ahead_il;
847 imd->read_ahead_il = NULL;
849 /* override the old signals */
850 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
851 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
852 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
854 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
855 image_load_buffer_throttle(imd->il);
858 /* do this one directly (probably should add a set func) */
859 imd->il->func_done = image_load_done_cb;
861 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
862 image_state_set(imd, IMAGE_STATE_LOADING);
864 if (!imd->delay_flip)
866 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
869 image_read_ahead_cancel(imd);
872 else if (imd->read_ahead_pixbuf)
874 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
875 g_object_unref(imd->read_ahead_pixbuf);
876 imd->read_ahead_pixbuf = NULL;
878 image_read_ahead_cancel(imd);
880 image_post_process(imd, FALSE);
884 image_read_ahead_cancel(imd);
888 static gint image_load_begin(ImageWindow *imd, FileData *fd)
890 DEBUG_1("%s image begin", get_exec_time());
892 if (imd->il) return FALSE;
894 imd->completed = FALSE;
895 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
897 if (image_post_buffer_get(imd))
899 DEBUG_1("from post buffer: %s", imd->image_fd->path);
903 if (image_read_ahead_check(imd))
905 DEBUG_1("from read ahead buffer: %s", imd->image_fd->path);
909 if (!imd->delay_flip && image_get_pixbuf(imd))
913 pr = PIXBUF_RENDERER(imd->pr);
914 if (pr->pixbuf) g_object_unref(pr->pixbuf);
918 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
920 imd->il = image_loader_new(fd);
922 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
923 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
924 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
926 if (!image_loader_start(imd->il, image_load_done_cb, imd))
928 DEBUG_1("image start error");
930 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
932 image_loader_free(imd->il);
935 image_complete_util(imd, FALSE);
940 image_state_set(imd, IMAGE_STATE_LOADING);
942 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
943 image_load_buffer_throttle(imd->il);
946 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
951 static void image_reset(ImageWindow *imd)
953 /* stops anything currently being done */
955 DEBUG_1("%s image reset", get_exec_time());
957 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
959 image_loader_free(imd->il);
962 color_man_free((ColorMan *)imd->cm);
965 imd->delay_alter_type = ALTER_NONE;
967 image_state_set(imd, IMAGE_STATE_NONE);
971 *-------------------------------------------------------------------
973 *-------------------------------------------------------------------
976 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
980 if (imd->image_fd && isfile(imd->image_fd->path))
984 pr = PIXBUF_RENDERER(imd->pr);
985 pr->zoom = zoom; /* store the zoom, needed by the loader */
987 if (image_load_begin(imd, imd->image_fd))
989 imd->unknown = FALSE;
995 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
996 image_change_pixbuf(imd, pixbuf, zoom);
997 g_object_unref(pixbuf);
1001 imd->size = filesize(imd->image_fd->path);
1002 imd->mtime = filetime(imd->image_fd->path);
1010 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
1011 image_change_pixbuf(imd, pixbuf, zoom);
1012 g_object_unref(pixbuf);
1013 imd->mtime = filetime(imd->image_fd->path);
1017 image_change_pixbuf(imd, NULL, zoom);
1020 imd->unknown = TRUE;
1024 image_update_util(imd);
1027 static void image_change_real(ImageWindow *imd, FileData *fd,
1028 CollectionData *cd, CollectInfo *info, gdouble zoom)
1031 GdkPixbuf *prev_pixbuf = NULL;
1032 FileData *prev_fd = NULL;
1033 gint prev_clear = FALSE;
1034 gint prev_color_row = -1;
1036 imd->collection = cd;
1037 imd->collection_info = info;
1039 pixbuf = image_get_pixbuf(imd);
1041 if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1045 /* current image is not finished */
1050 prev_fd = file_data_ref(imd->image_fd);
1051 prev_pixbuf = pixbuf;
1052 g_object_ref(prev_pixbuf);
1058 cm = (ColorMan *)imd->cm;
1059 prev_color_row = cm->row;
1064 file_data_unref(imd->image_fd);
1065 imd->image_fd = file_data_ref(fd);
1067 image_change_complete(imd, zoom, TRUE);
1071 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
1072 file_data_unref(prev_fd);
1073 g_object_unref(prev_pixbuf);
1075 else if (prev_clear)
1077 image_post_buffer_set(imd, NULL, NULL, -1);
1080 image_update_title(imd);
1081 image_state_set(imd, IMAGE_STATE_IMAGE);
1085 *-------------------------------------------------------------------
1087 *-------------------------------------------------------------------
1090 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1094 widget = imd->widget;
1095 if (!widget->window) return;
1099 gtk_paint_focus(widget->style, widget->window, GTK_STATE_ACTIVE,
1100 area, widget, "image_window",
1101 widget->allocation.x, widget->allocation.y,
1102 widget->allocation.width - 1, widget->allocation.height - 1);
1106 gtk_paint_shadow(widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1107 area, widget, "image_window",
1108 widget->allocation.x, widget->allocation.y,
1109 widget->allocation.width - 1, widget->allocation.height - 1);
1113 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1115 ImageWindow *imd = data;
1117 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1121 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1123 ImageWindow *imd = data;
1125 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1126 image_focus_paint(imd, TRUE, NULL);
1131 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1133 ImageWindow *imd = data;
1135 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1136 image_focus_paint(imd, FALSE, NULL);
1141 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1142 gint relative, gint always)
1144 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1147 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1149 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1152 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1154 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1157 void image_overlay_remove(ImageWindow *imd, gint id)
1159 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1162 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1164 ImageWindow *imd = data;
1166 if (imd->func_scroll &&
1167 event && event->type == GDK_SCROLL)
1169 imd->func_scroll(imd, event->direction, event->time,
1170 event->x, event->y, event->state, imd->data_scroll);
1178 *-------------------------------------------------------------------
1180 *-------------------------------------------------------------------
1183 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1184 const gchar *title, const gchar *title_right, gint show_zoom)
1186 imd->top_window = window;
1188 imd->title = g_strdup(title);
1189 g_free(imd->title_right);
1190 imd->title_right = g_strdup(title_right);
1191 imd->title_show_zoom = show_zoom;
1193 if (!options->image.fit_window_to_image) window = NULL;
1195 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1197 image_update_title(imd);
1200 void image_set_update_func(ImageWindow *imd,
1201 void (*func)(ImageWindow *imd, gpointer data),
1204 imd->func_update = func;
1205 imd->data_update = data;
1208 void image_set_complete_func(ImageWindow *imd,
1209 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1212 imd->func_complete = func;
1213 imd->data_complete = data;
1216 void image_set_state_func(ImageWindow *imd,
1217 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1220 imd->func_state = func;
1221 imd->data_state = data;
1225 void image_set_button_func(ImageWindow *imd,
1226 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1229 imd->func_button = func;
1230 imd->data_button = data;
1233 void image_set_drag_func(ImageWindow *imd,
1234 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1237 imd->func_drag = func;
1238 imd->data_drag = data;
1241 void image_set_scroll_func(ImageWindow *imd,
1242 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1245 imd->func_scroll = func;
1246 imd->data_scroll = data;
1249 void image_set_scroll_notify_func(ImageWindow *imd,
1250 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1253 imd->func_scroll_notify = func;
1254 imd->data_scroll_notify = data;
1259 const gchar *image_get_path(ImageWindow *imd)
1261 if (imd->image_fd == NULL) return NULL;
1262 return imd->image_fd->path;
1265 const gchar *image_get_name(ImageWindow *imd)
1267 if (imd->image_fd == NULL) return NULL;
1268 return imd->image_fd->name;
1271 FileData *image_get_fd(ImageWindow *imd)
1273 return imd->image_fd;
1276 /* merely changes path string, does not change the image! */
1277 void image_set_fd(ImageWindow *imd, FileData *fd)
1279 file_data_unref(imd->image_fd);
1280 imd->image_fd = file_data_ref(fd);
1282 image_update_title(imd);
1283 image_state_set(imd, IMAGE_STATE_IMAGE);
1286 /* load a new image */
1288 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1290 if (imd->image_fd == fd) return;
1292 image_change_real(imd, fd, NULL, NULL, zoom);
1295 gint image_get_image_size(ImageWindow *imd, gint *width, gint *height)
1297 return pixbuf_renderer_get_image_size(PIXBUF_RENDERER(imd->pr), width, height);
1300 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1302 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1305 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1308 ExifData *exif = NULL;
1309 gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
1310 gint read_exif_for_orientation = FALSE;
1312 if (imd->image_fd && imd->image_fd->user_orientation)
1313 imd->orientation = imd->image_fd->user_orientation;
1314 else if (options->image.exif_rotate_enable)
1315 read_exif_for_orientation = TRUE;
1317 if (read_exif_for_color_profile || read_exif_for_orientation)
1321 exif = exif_read_fd(imd->image_fd);
1323 if (exif && read_exif_for_orientation)
1325 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1326 imd->orientation = orientation;
1328 imd->orientation = 1;
1329 imd->image_fd->exif_orientation = imd->orientation;
1333 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1336 color_man_free(imd->cm);
1340 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1341 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1343 if (imd->color_profile_enable)
1345 if (!image_post_process_color(imd, 0, exif, FALSE))
1347 /* fixme: note error to user */
1348 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1354 if (imd->cm || imd->desaturate)
1355 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1357 image_state_set(imd, IMAGE_STATE_IMAGE);
1360 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1362 if (!cd || !info || !g_list_find(cd->list, info)) return;
1364 image_change_real(imd, info->fd, cd, info, zoom);
1367 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1369 if (collection_to_number(imd->collection) >= 0)
1371 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1373 if (info) *info = imd->collection_info;
1377 if (info) *info = NULL;
1379 return imd->collection;
1382 if (info) *info = NULL;
1386 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1388 /* change data for the callbacks directly */
1390 il->data_area_ready = data;
1391 il->data_error = data;
1392 il->data_done = data;
1393 il->data_percent = data;
1396 /* this is more like a move function
1397 * it moves most data from source to imd
1399 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1401 if (imd == source) return;
1403 imd->unknown = source->unknown;
1405 imd->collection = source->collection;
1406 imd->collection_info = source->collection_info;
1407 imd->size = source->size;
1408 imd->mtime = source->mtime;
1410 image_set_fd(imd, image_get_fd(source));
1412 image_loader_free(imd->il);
1417 imd->il = source->il;
1420 image_loader_sync_data(imd->il, imd);
1422 imd->delay_alter_type = source->delay_alter_type;
1423 source->delay_alter_type = ALTER_NONE;
1426 imd->color_profile_enable = source->color_profile_enable;
1427 imd->color_profile_input = source->color_profile_input;
1428 imd->color_profile_screen = source->color_profile_screen;
1429 imd->color_profile_use_image = source->color_profile_use_image;
1430 color_man_free((ColorMan *)imd->cm);
1436 imd->cm = source->cm;
1439 cm = (ColorMan *)imd->cm;
1441 cm->func_done_data = imd;
1444 image_loader_free(imd->read_ahead_il);
1445 imd->read_ahead_il = source->read_ahead_il;
1446 source->read_ahead_il = NULL;
1447 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1449 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1450 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1451 source->read_ahead_pixbuf = NULL;
1453 file_data_unref(imd->read_ahead_fd);
1454 imd->read_ahead_fd = source->read_ahead_fd;
1455 source->read_ahead_fd = NULL;
1457 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1458 imd->prev_pixbuf = source->prev_pixbuf;
1459 source->prev_pixbuf = NULL;
1460 imd->prev_color_row = source->prev_color_row;
1461 source->prev_color_row = -1;
1463 file_data_unref(imd->prev_fd);
1464 imd->prev_fd = source->prev_fd;
1465 source->prev_fd = NULL;
1467 imd->completed = source->completed;
1468 imd->state = source->state;
1469 source->state = IMAGE_STATE_NONE;
1471 imd->orientation = source->orientation;
1472 imd->desaturate = source->desaturate;
1474 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1476 if (imd->cm || imd->desaturate)
1477 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1479 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1485 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1487 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1490 void image_reload(ImageWindow *imd)
1492 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1494 image_change_complete(imd, image_zoom_get(imd), FALSE);
1497 void image_scroll(ImageWindow *imd, gint x, gint y)
1499 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1502 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1503 gdouble x_align, gdouble y_align)
1505 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1508 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1510 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1513 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1515 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1520 void image_alter(ImageWindow *imd, AlterType type)
1522 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1524 if (imd->il || imd->cm)
1526 /* still loading, wait till done */
1527 imd->delay_alter_type = type;
1528 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1530 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1532 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1537 image_alter_real(imd, type, TRUE);
1541 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1543 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1546 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1548 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1551 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1553 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1556 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1558 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1561 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1567 pr = (PixbufRenderer *)imd->pr;
1569 if (!pixbuf_renderer_get_pixbuf(pr) ||
1570 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1574 zoom = (gdouble)pr->window_height / height;
1578 zoom = (gdouble)pr->window_width / width;
1583 zoom = 0.0 - 1.0 / zoom;
1586 pixbuf_renderer_zoom_set(pr, zoom);
1589 gdouble image_zoom_get(ImageWindow *imd)
1591 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1594 gdouble image_zoom_get_real(ImageWindow *imd)
1596 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1599 gchar *image_zoom_get_as_text(ImageWindow *imd)
1607 gchar *approx = " ";
1609 zoom = image_zoom_get(imd);
1610 scale = image_zoom_get_real(imd);
1616 else if (zoom < 0.0)
1620 else if (zoom == 0.0 && scale != 0.0)
1633 if (rint(l) != l) pl = 1;
1634 if (rint(r) != r) pr = 1;
1636 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1639 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1643 if (mode == ZOOM_RESET_ORIGINAL)
1647 else if (mode == ZOOM_RESET_FIT_WINDOW)
1655 zoom = image_zoom_get(imd);
1668 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1670 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1674 image_read_ahead_set(imd, fd);
1678 image_read_ahead_cancel(imd);
1682 static gint image_auto_refresh_cb(gpointer data)
1684 ImageWindow *imd = data;
1687 if (!imd || !image_get_pixbuf(imd) ||
1688 imd->il || !imd->image_fd ||
1689 !options->update_on_time_change) return TRUE;
1691 newtime = filetime(imd->image_fd->path);
1692 if (newtime > 0 && newtime != imd->mtime)
1694 imd->mtime = newtime;
1701 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1703 void image_auto_refresh(ImageWindow *imd, gint interval)
1706 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1708 if (imd->auto_refresh_id > -1)
1710 g_source_remove(imd->auto_refresh_id);
1711 imd->auto_refresh_id = -1;
1712 imd->auto_refresh_interval = -1;
1715 if (interval < 0) return;
1717 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1719 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1720 imd->auto_refresh_interval = interval;
1723 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1725 imd->top_window_sync = allow_sync;
1727 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1730 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1732 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1735 void image_color_profile_set(ImageWindow *imd,
1736 gint input_type, gint screen_type,
1741 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1742 screen_type < 0 || screen_type > 1)
1747 imd->color_profile_input = input_type;
1748 imd->color_profile_screen = screen_type;
1749 imd->color_profile_use_image = use_image;
1752 gint image_color_profile_get(ImageWindow *imd,
1753 gint *input_type, gint *screen_type,
1756 if (!imd) return FALSE;
1758 if (input_type) *input_type = imd->color_profile_input;
1759 if (screen_type) *screen_type = imd->color_profile_screen;
1760 if (use_image) *use_image = imd->color_profile_use_image;
1765 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1769 if (imd->color_profile_enable == enable) return;
1771 imd->color_profile_enable = enable;
1774 gint image_color_profile_get_use(ImageWindow *imd)
1776 if (!imd) return FALSE;
1778 return imd->color_profile_enable;
1781 gint image_color_profile_get_from_image(ImageWindow *imd)
1783 if (!imd) return FALSE;
1785 return imd->color_profile_from_image;
1788 void image_set_delay_flip(ImageWindow *imd, gint delay)
1791 imd->delay_flip == delay) return;
1793 imd->delay_flip = delay;
1795 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1797 if (!imd->delay_flip && imd->il)
1801 pr = PIXBUF_RENDERER(imd->pr);
1802 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1805 image_load_pixbuf_ready(imd);
1809 void image_to_root_window(ImageWindow *imd, gint scaled)
1812 GdkWindow *rootwindow;
1820 pixbuf = image_get_pixbuf(imd);
1821 if (!pixbuf) return;
1823 screen = gtk_widget_get_screen(imd->widget);
1824 rootwindow = gdk_screen_get_root_window(screen);
1825 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1829 width = gdk_screen_width();
1830 height = gdk_screen_height();
1834 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1837 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1839 gdk_pixbuf_render_pixmap_and_mask(pb, &pixmap, NULL, 128);
1840 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1841 gdk_window_clear(rootwindow);
1843 g_object_unref(pixmap);
1848 void image_select(ImageWindow *imd, gboolean select)
1854 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1855 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1858 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1864 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1870 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1871 gtk_container_set_border_width(GTK_CONTAINER(imd->frame), 4);
1875 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1876 gtk_container_set_border_width(GTK_CONTAINER(imd->frame), 0);
1882 *-------------------------------------------------------------------
1884 *-------------------------------------------------------------------
1887 static void image_options_set(ImageWindow *imd)
1889 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1890 "zoom_2pass", options->image.zoom_2pass,
1891 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1892 "dither_quality", options->image.dither_quality,
1893 "scroll_reset", options->image.scroll_reset_method,
1894 "cache_display", options->image.tile_cache_max,
1895 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1896 "window_limit", options->image.limit_window_size,
1897 "window_limit_value", options->image.max_window_size,
1898 "autofit_limit", options->image.limit_autofit_size,
1899 "autofit_limit_value", options->image.max_autofit_size,
1903 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1906 void image_options_sync(void)
1918 image_options_set(imd);
1923 *-------------------------------------------------------------------
1925 *-------------------------------------------------------------------
1928 static void image_free(ImageWindow *imd)
1930 image_list = g_list_remove(image_list, imd);
1934 image_read_ahead_cancel(imd);
1935 image_post_buffer_set(imd, NULL, NULL, -1);
1936 image_auto_refresh(imd, -1);
1938 file_data_unref(imd->image_fd);
1940 g_free(imd->title_right);
1944 static void image_destroy_cb(GtkObject *widget, gpointer data)
1946 ImageWindow *imd = data;
1950 gboolean selectable_frame_expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1952 gtk_paint_flat_box(widget->style,
1955 (GTK_FRAME(widget))->shadow_type,
1959 widget->allocation.x + 3, widget->allocation.y + 3,
1960 widget->allocation.width - 6, widget->allocation.height - 6);
1967 void image_set_frame(ImageWindow *imd, gboolean frame)
1971 if (frame == imd->has_frame) return;
1973 gtk_widget_hide(imd->pr);
1977 imd->frame = gtk_frame_new(NULL);
1978 gtk_widget_ref(imd->pr);
1979 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1980 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1981 gtk_widget_unref(imd->pr);
1982 g_signal_connect(G_OBJECT(imd->frame), "expose_event",
1983 G_CALLBACK(selectable_frame_expose_cb), NULL);
1985 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1986 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1987 G_CALLBACK(image_focus_in_cb), imd);
1988 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1989 G_CALLBACK(image_focus_out_cb), imd);
1991 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1992 G_CALLBACK(image_focus_expose), imd);
1995 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1996 gtk_widget_show(imd->frame);
2000 gtk_widget_ref(imd->pr);
2003 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
2004 gtk_widget_destroy(imd->frame);
2007 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2008 gtk_widget_unref(imd->pr);
2011 gtk_widget_show(imd->pr);
2013 imd->has_frame = frame;
2016 ImageWindow *image_new(gint frame)
2020 imd = g_new0(ImageWindow, 1);
2022 imd->top_window = NULL;
2024 imd->title_right = NULL;
2025 imd->title_show_zoom = FALSE;
2027 imd->unknown = TRUE;
2029 imd->has_frame = -1; /* not initialized; for image_set_frame */
2030 imd->top_window_sync = FALSE;
2032 imd->delay_alter_type = ALTER_NONE;
2034 imd->read_ahead_il = NULL;
2035 imd->read_ahead_pixbuf = NULL;
2036 imd->read_ahead_fd = NULL;
2038 imd->completed = FALSE;
2039 imd->state = IMAGE_STATE_NONE;
2041 imd->color_profile_enable = FALSE;
2042 imd->color_profile_input = 0;
2043 imd->color_profile_screen = 0;
2044 imd->color_profile_use_image = FALSE;
2045 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2047 imd->auto_refresh_id = -1;
2048 imd->auto_refresh_interval = -1;
2050 imd->delay_flip = FALSE;
2052 imd->func_update = NULL;
2053 imd->func_complete = NULL;
2054 imd->func_tile_request = NULL;
2055 imd->func_tile_dispose = NULL;
2057 imd->func_button = NULL;
2058 imd->func_scroll = NULL;
2060 imd->orientation = 1;
2062 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2064 image_options_set(imd);
2067 imd->widget = gtk_vbox_new(0, 0);
2069 image_set_frame(imd, frame);
2071 image_set_selectable(imd, 0);
2073 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2074 G_CALLBACK(image_click_cb), imd);
2075 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2076 G_CALLBACK(image_scroll_notify_cb), imd);
2078 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2079 G_CALLBACK(image_scroll_cb), imd);
2081 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2082 G_CALLBACK(image_destroy_cb), imd);
2084 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2085 G_CALLBACK(image_zoom_cb), imd);
2086 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2087 G_CALLBACK(image_render_complete_cb), imd);
2088 g_signal_connect(G_OBJECT(imd->pr), "drag",
2089 G_CALLBACK(image_drag_cb), imd);
2091 image_list = g_list_append(image_list, imd);