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"
22 #include "histogram.h"
23 #include "image-load.h"
24 #include "image-overlay.h"
26 #include "layout_image.h"
27 #include "pixbuf-renderer.h"
28 #include "pixbuf_util.h"
29 #include "ui_fileops.h"
36 /* size of the image loader buffer (512 bytes x defined number) */
37 #define IMAGE_LOAD_BUFFER_COUNT 8
39 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
40 #define IMAGE_THROTTLE_LARGER_IMAGES 1
42 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
43 #define IMAGE_THROTTLE_FACTOR 32
45 /* the file size at which throttling take place */
46 #define IMAGE_THROTTLE_THRESHOLD 1048576
48 #define IMAGE_AUTO_REFRESH_TIME 3000
51 static GList *image_list = NULL;
54 static void image_update_title(ImageWindow *imd);
55 static void image_post_process(ImageWindow *imd, gint clamp);
56 static void image_read_ahead_start(ImageWindow *imd);
59 *-------------------------------------------------------------------
61 *-------------------------------------------------------------------
64 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
66 ImageWindow *imd = data;
70 imd->func_button(imd, event->button, event->time,
71 event->x, event->y, event->state, imd->data_button);
75 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
77 ImageWindow *imd = data;
80 pixbuf_renderer_get_scaled_size(pr, &width, &height);
84 imd->func_drag(imd, event->button, event->time,
85 event->x, event->y, event->state,
86 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
91 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
93 ImageWindow *imd = data;
95 if (imd->func_scroll_notify && pr->scale)
97 imd->func_scroll_notify(imd,
98 (gint)((gdouble)pr->x_scroll / pr->scale),
99 (gint)((gdouble)pr->y_scroll / pr->scale),
100 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
101 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
102 imd->data_scroll_notify);
106 static void image_update_util(ImageWindow *imd)
108 if (imd->func_update) imd->func_update(imd, imd->data_update);
111 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
113 ImageWindow *imd = data;
115 if (imd->title_show_zoom) image_update_title(imd);
116 if (imd->overlay_show_zoom) image_osd_update(imd);
118 image_update_util(imd);
121 static void image_complete_util(ImageWindow *imd, gint preload)
123 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
125 DEBUG_1("%s image load completed \"%s\" (%s)", get_exec_time(),
126 (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") :
127 (imd->image_fd ? imd->image_fd->path : "null"),
128 (preload) ? "preload" : "current");
130 if (!preload) imd->completed = TRUE;
131 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
134 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
136 ImageWindow *imd = data;
138 image_complete_util(imd, FALSE);
141 static void image_state_set(ImageWindow *imd, ImageState state)
143 if (state == IMAGE_STATE_NONE)
151 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
154 static void image_state_unset(ImageWindow *imd, ImageState state)
156 imd->state &= ~state;
157 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
161 *-------------------------------------------------------------------
163 *-------------------------------------------------------------------
166 static void image_update_title(ImageWindow *imd)
170 gchar *collection = NULL;
172 if (!imd->top_window) return;
174 if (imd->collection && collection_to_number(imd->collection) >= 0)
177 name = imd->collection->name;
178 if (!name) name = _("Untitled");
179 collection = g_strdup_printf(" (Collection %s)", name);
182 if (imd->title_show_zoom)
184 gchar *buf = image_zoom_get_as_text(imd);
185 zoom = g_strconcat(" [", buf, "]", NULL);
189 title = g_strdup_printf("%s%s%s%s%s%s",
190 imd->title ? imd->title : "",
191 imd->image_fd ? imd->image_fd->name : "",
193 collection ? collection : "",
194 imd->image_fd ? " - " : "",
195 imd->title_right ? imd->title_right : "");
197 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
205 *-------------------------------------------------------------------
206 * rotation, flip, etc.
207 *-------------------------------------------------------------------
213 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
216 GdkPixbuf *new = NULL;
221 pr = (PixbufRenderer *)imd->pr;
223 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
224 imd->delay_alter_type = ALTER_NONE;
226 if (!pr->pixbuf) return;
228 x = pr->x_scroll + (pr->vis_width / 2);
229 y = pr->y_scroll + (pr->vis_height / 2);
233 case ALTER_ROTATE_90:
234 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
239 case ALTER_ROTATE_90_CC:
240 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
245 case ALTER_ROTATE_180:
246 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
251 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
255 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
258 case ALTER_DESATURATE:
259 pixbuf_desaturate_rect(pr->pixbuf,
260 0, 0, pr->image_width, pr->image_height);
261 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
262 layout_image_overlay_update(layout_find_by_image(imd));
272 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
275 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
279 switch (pr->scroll_reset)
281 case PR_SCROLL_RESET_NOCHANGE:
283 case PR_SCROLL_RESET_CENTER:
284 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
285 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
287 case PR_SCROLL_RESET_TOPLEFT:
294 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
295 (gint)((gdouble)y / pr->scale),
299 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
300 layout_image_overlay_update(layout_find_by_image(imd));
301 DEBUG_1("%s image postprocess done: %s", get_exec_time(), imd->image_fd->name);
304 static void image_post_process_alter(ImageWindow *imd, gint clamp)
306 if (imd->delay_alter_type != ALTER_NONE)
308 image_alter_real(imd, imd->delay_alter_type, clamp);
313 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
315 ImageWindow *imd = data;
318 if (type == COLOR_RETURN_IMAGE_CHANGED)
320 if (cm == imd->cm) imd->cm = NULL;
325 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
326 DEBUG_1("%s image postprocess cm done: %s", get_exec_time(), imd->image_fd->name);
328 image_post_process_alter(imd, FALSE);
330 image_read_ahead_start(imd);
334 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg)
337 ColorManProfileType input_type;
338 ColorManProfileType screen_type;
339 const gchar *input_file;
340 const gchar *screen_file;
341 unsigned char *profile = NULL;
344 if (imd->cm) return FALSE;
346 if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
347 imd->color_profile_input < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
351 n = imd->color_profile_input - COLOR_PROFILE_FILE;
352 if (!options->color_profile.input_file[n]) return FALSE;
354 input_type = COLOR_PROFILE_FILE;
355 input_file = options->color_profile.input_file[n];
357 else if (imd->color_profile_input >= COLOR_PROFILE_SRGB &&
358 imd->color_profile_input < COLOR_PROFILE_FILE)
360 input_type = imd->color_profile_input;
368 if (imd->color_profile_screen == 1 &&
369 options->color_profile.screen_file)
371 screen_type = COLOR_PROFILE_FILE;
372 screen_file = options->color_profile.screen_file;
374 else if (imd->color_profile_screen == 0)
376 screen_type = COLOR_PROFILE_SRGB;
383 imd->color_profile_from_image = COLOR_PROFILE_NONE;
385 if (imd->color_profile_use_image && exif)
387 profile = exif_get_color_profile(exif, &profile_len);
391 gchar *interop_index;
393 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
394 if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
395 interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
399 input_type = COLOR_PROFILE_SRGB;
401 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
403 DEBUG_1("Found EXIF ColorSpace of sRGB");
405 if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
407 input_type = COLOR_PROFILE_ADOBERGB;
409 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
411 DEBUG_1("Found EXIF ColorSpace of AdobeRGB");
414 g_free(interop_index);
420 DEBUG_1("Found embedded color profile");
421 imd->color_profile_from_image = COLOR_PROFILE_MEM;
423 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
424 profile, profile_len,
425 screen_type, screen_file);
430 cm = color_man_new(run_in_bg ? imd : NULL, NULL,
431 input_type, input_file,
432 screen_type, screen_file);
440 cm->incremental_sync = TRUE;
443 imd->cm = (gpointer)cm;
445 if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd);
453 static void image_post_process(ImageWindow *imd, gint clamp)
456 ExifData *exif = NULL;
458 if (!image_get_pixbuf(imd)) return;
460 DEBUG_1("%s image postprocess: %s", get_exec_time(), imd->image_fd->name);
462 if (options->image.exif_rotate_enable ||
463 (imd->color_profile_enable && imd->color_profile_use_image) )
465 exif = exif_read_fd(imd->image_fd);
467 if (options->image.exif_rotate_enable && exif)
471 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
475 /* see http://jpegclub.org/exif_orientation.html
478 888888 888888 88 88 8888888888 88 88 8888888888
479 88 88 88 88 88 88 88 88 88 88 88 88
480 8888 8888 8888 8888 88 8888888888 8888888888 88
486 case EXIF_ORIENTATION_TOP_LEFT:
487 /* normal -- nothing to do */
490 case EXIF_ORIENTATION_TOP_RIGHT:
492 imd->delay_alter_type = ALTER_MIRROR;
494 case EXIF_ORIENTATION_BOTTOM_RIGHT:
496 imd->delay_alter_type = ALTER_ROTATE_180;
498 case EXIF_ORIENTATION_BOTTOM_LEFT:
500 imd->delay_alter_type = ALTER_FLIP;
502 case EXIF_ORIENTATION_LEFT_TOP:
503 /* not implemented -- too wacky to fix in one step */
506 case EXIF_ORIENTATION_RIGHT_TOP:
507 /* rotated -90 (270) */
508 imd->delay_alter_type = ALTER_ROTATE_90;
510 case EXIF_ORIENTATION_RIGHT_BOTTOM:
511 /* not implemented -- too wacky to fix in one step */
514 case EXIF_ORIENTATION_LEFT_BOTTOM:
516 imd->delay_alter_type = ALTER_ROTATE_90_CC;
519 /* The other values are out of range */
524 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
527 if (imd->color_profile_enable)
529 if (!image_post_process_color(imd, 0, exif, TRUE))
531 /* fixme: note error to user */
532 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
537 if (!imd->cm) image_post_process_alter(imd, clamp);
543 static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data)
545 ImageWindow *imd = (ImageWindow *)data;
546 if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h);
547 if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h);
551 void image_alter(ImageWindow *imd, AlterType type)
554 const static gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1};
555 const static gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3};
556 const static gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6};
557 const static gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7};
558 const static gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5};
561 if (!imd || !imd->pr) return;
563 if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
567 case ALTER_ROTATE_90:
568 imd->orientation = rotate_90[imd->orientation];
570 case ALTER_ROTATE_90_CC:
571 imd->orientation = rotate_90_cc[imd->orientation];
573 case ALTER_ROTATE_180:
574 imd->orientation = rotate_180[imd->orientation];
577 imd->orientation = mirror[imd->orientation];
580 imd->orientation = flip[imd->orientation];
582 case ALTER_DESATURATE:
583 imd->desaturate = !imd->desaturate;
586 imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1;
587 imd->desaturate = FALSE;
594 if (type != ALTER_NONE && type != ALTER_DESATURATE)
596 if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd);
597 imd->image_fd->user_orientation = imd->orientation;
601 if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd);
602 imd->image_fd->user_orientation = 0;
605 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
606 if (imd->cm || imd->desaturate)
607 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
609 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
614 *-------------------------------------------------------------------
615 * read ahead (prebuffer)
616 *-------------------------------------------------------------------
619 static void image_read_ahead_cancel(ImageWindow *imd)
621 DEBUG_1("%s read ahead cancelled for :%s", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
623 image_loader_free(imd->read_ahead_il);
624 imd->read_ahead_il = NULL;
626 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
627 imd->read_ahead_pixbuf = NULL;
629 file_data_unref(imd->read_ahead_fd);
630 imd->read_ahead_fd = NULL;
633 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
635 ImageWindow *imd = data;
637 DEBUG_1("%s read ahead done for :%s", get_exec_time(), imd->read_ahead_fd->path);
639 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
640 if (imd->read_ahead_pixbuf)
642 g_object_ref(imd->read_ahead_pixbuf);
646 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
648 image_loader_free(imd->read_ahead_il);
649 imd->read_ahead_il = NULL;
651 image_complete_util(imd, TRUE);
654 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
656 /* we even treat errors as success, maybe at least some of the file was ok */
657 image_read_ahead_done_cb(il, data);
660 static void image_read_ahead_start(ImageWindow *imd)
662 /* already started ? */
663 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
665 /* still loading ?, do later */
666 if (imd->il /*|| imd->cm*/) return;
668 DEBUG_1("%s read ahead started for :%s", get_exec_time(), imd->read_ahead_fd->path);
670 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
672 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
673 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
675 image_read_ahead_cancel(imd);
676 image_complete_util(imd, TRUE);
680 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
682 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
684 image_read_ahead_cancel(imd);
686 imd->read_ahead_fd = file_data_ref(fd);
688 DEBUG_1("read ahead set to :%s", imd->read_ahead_fd->path);
690 image_read_ahead_start(imd);
694 *-------------------------------------------------------------------
696 *-------------------------------------------------------------------
699 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
701 file_data_unref(imd->prev_fd);
702 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
706 imd->prev_fd = file_data_ref(fd);
708 g_object_ref(pixbuf);
709 imd->prev_pixbuf = pixbuf;
710 imd->prev_color_row = color_row;
715 imd->prev_pixbuf = NULL;
716 imd->prev_color_row = -1;
719 DEBUG_1("%s post buffer set: %s", get_exec_time(), fd ? fd->path : "null");
722 static gint image_post_buffer_get(ImageWindow *imd)
726 if (imd->prev_pixbuf &&
727 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
729 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
730 if (imd->prev_color_row >= 0)
732 ExifData *exif = NULL;
734 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
735 // image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
745 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
746 imd->prev_pixbuf = NULL;
748 file_data_unref(imd->prev_fd);
755 *-------------------------------------------------------------------
757 *-------------------------------------------------------------------
760 static void image_load_pixbuf_ready(ImageWindow *imd)
762 if (image_get_pixbuf(imd) || !imd->il) return;
764 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
767 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
769 ImageWindow *imd = data;
772 pr = (PixbufRenderer *)imd->pr;
774 if (imd->delay_flip &&
775 pr->pixbuf != image_loader_get_pixbuf(il))
780 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
782 pixbuf_renderer_area_changed(pr, x, y, w, h);
785 static void image_load_done_cb(ImageLoader *il, gpointer data)
787 ImageWindow *imd = data;
789 DEBUG_1("%s image done", get_exec_time());
791 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
792 image_state_unset(imd, IMAGE_STATE_LOADING);
794 if (imd->delay_flip &&
795 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
797 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
798 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
801 image_loader_free(imd->il);
804 image_post_process(imd, TRUE);
806 image_read_ahead_start(imd);
809 static void image_load_error_cb(ImageLoader *il, gpointer data)
811 DEBUG_1("%s image error", get_exec_time());
813 /* even on error handle it like it was done,
814 * since we have a pixbuf with _something_ */
816 image_load_done_cb(il, data);
819 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
820 static void image_load_buffer_throttle(ImageLoader *il)
822 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
824 /* Larger image files usually have larger chunks of data per pixel...
825 * So increase the buffer read size so that the rendering chunks called
829 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
833 /* this read ahead is located here merely for the callbacks, above */
835 static gint image_read_ahead_check(ImageWindow *imd)
837 if (!imd->read_ahead_fd) return FALSE;
838 if (imd->il) return FALSE;
840 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
842 image_read_ahead_cancel(imd);
846 if (imd->read_ahead_il)
848 imd->il = imd->read_ahead_il;
849 imd->read_ahead_il = NULL;
851 /* override the old signals */
852 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
853 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
854 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
856 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
857 image_load_buffer_throttle(imd->il);
860 /* do this one directly (probably should add a set func) */
861 imd->il->func_done = image_load_done_cb;
863 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
864 image_state_set(imd, IMAGE_STATE_LOADING);
866 if (!imd->delay_flip)
868 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
871 image_read_ahead_cancel(imd);
874 else if (imd->read_ahead_pixbuf)
876 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
877 g_object_unref(imd->read_ahead_pixbuf);
878 imd->read_ahead_pixbuf = NULL;
880 image_read_ahead_cancel(imd);
882 image_post_process(imd, FALSE);
886 image_read_ahead_cancel(imd);
890 static gint image_load_begin(ImageWindow *imd, FileData *fd)
892 DEBUG_1("%s image begin", get_exec_time());
894 if (imd->il) return FALSE;
896 imd->completed = FALSE;
897 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
899 if (image_post_buffer_get(imd))
901 DEBUG_1("from post buffer: %s", imd->image_fd->path);
905 if (image_read_ahead_check(imd))
907 DEBUG_1("from read ahead buffer: %s", imd->image_fd->path);
911 if (!imd->delay_flip && image_get_pixbuf(imd))
915 pr = PIXBUF_RENDERER(imd->pr);
916 if (pr->pixbuf) g_object_unref(pr->pixbuf);
920 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
922 imd->il = image_loader_new(fd);
924 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
925 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
926 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
928 if (!image_loader_start(imd->il, image_load_done_cb, imd))
930 DEBUG_1("image start error");
932 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
934 image_loader_free(imd->il);
937 image_complete_util(imd, FALSE);
942 image_state_set(imd, IMAGE_STATE_LOADING);
944 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
945 image_load_buffer_throttle(imd->il);
948 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
953 static void image_reset(ImageWindow *imd)
955 /* stops anything currently being done */
957 DEBUG_1("%s image reset", get_exec_time());
959 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
961 image_loader_free(imd->il);
964 color_man_free((ColorMan *)imd->cm);
967 imd->delay_alter_type = ALTER_NONE;
969 image_state_set(imd, IMAGE_STATE_NONE);
973 *-------------------------------------------------------------------
975 *-------------------------------------------------------------------
978 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
982 if (imd->image_fd && isfile(imd->image_fd->path))
986 pr = PIXBUF_RENDERER(imd->pr);
987 pr->zoom = zoom; /* store the zoom, needed by the loader */
989 if (image_load_begin(imd, imd->image_fd))
991 imd->unknown = FALSE;
997 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
998 image_change_pixbuf(imd, pixbuf, zoom);
999 g_object_unref(pixbuf);
1001 imd->unknown = TRUE;
1003 imd->size = filesize(imd->image_fd->path);
1004 imd->mtime = filetime(imd->image_fd->path);
1012 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
1013 image_change_pixbuf(imd, pixbuf, zoom);
1014 g_object_unref(pixbuf);
1015 imd->mtime = filetime(imd->image_fd->path);
1019 image_change_pixbuf(imd, NULL, zoom);
1022 imd->unknown = TRUE;
1026 image_update_util(imd);
1029 static void image_change_real(ImageWindow *imd, FileData *fd,
1030 CollectionData *cd, CollectInfo *info, gdouble zoom)
1033 GdkPixbuf *prev_pixbuf = NULL;
1034 FileData *prev_fd = NULL;
1035 gint prev_clear = FALSE;
1036 gint prev_color_row = -1;
1038 imd->collection = cd;
1039 imd->collection_info = info;
1041 pixbuf = image_get_pixbuf(imd);
1043 if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1047 /* current image is not finished */
1052 prev_fd = file_data_ref(imd->image_fd);
1053 prev_pixbuf = pixbuf;
1054 g_object_ref(prev_pixbuf);
1060 cm = (ColorMan *)imd->cm;
1061 prev_color_row = cm->row;
1066 file_data_unref(imd->image_fd);
1067 imd->image_fd = file_data_ref(fd);
1069 image_change_complete(imd, zoom, TRUE);
1073 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
1074 file_data_unref(prev_fd);
1075 g_object_unref(prev_pixbuf);
1077 else if (prev_clear)
1079 image_post_buffer_set(imd, NULL, NULL, -1);
1082 image_update_title(imd);
1083 image_state_set(imd, IMAGE_STATE_IMAGE);
1087 *-------------------------------------------------------------------
1089 *-------------------------------------------------------------------
1092 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1096 widget = imd->widget;
1097 if (!widget->window) return;
1101 gtk_paint_focus(widget->style, widget->window, GTK_STATE_ACTIVE,
1102 area, widget, "image_window",
1103 widget->allocation.x, widget->allocation.y,
1104 widget->allocation.width - 1, widget->allocation.height - 1);
1108 gtk_paint_shadow(widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1109 area, widget, "image_window",
1110 widget->allocation.x, widget->allocation.y,
1111 widget->allocation.width - 1, widget->allocation.height - 1);
1115 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1117 ImageWindow *imd = data;
1119 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1123 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1125 ImageWindow *imd = data;
1127 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1128 image_focus_paint(imd, TRUE, NULL);
1133 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1135 ImageWindow *imd = data;
1137 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1138 image_focus_paint(imd, FALSE, NULL);
1143 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1144 gint relative, gint always)
1146 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1149 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1151 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1154 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1156 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1159 void image_overlay_remove(ImageWindow *imd, gint id)
1161 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1164 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1166 ImageWindow *imd = data;
1168 if (imd->func_scroll &&
1169 event && event->type == GDK_SCROLL)
1171 imd->func_scroll(imd, event->direction, event->time,
1172 event->x, event->y, event->state, imd->data_scroll);
1180 *-------------------------------------------------------------------
1182 *-------------------------------------------------------------------
1185 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1186 const gchar *title, const gchar *title_right, gint show_zoom)
1188 imd->top_window = window;
1190 imd->title = g_strdup(title);
1191 g_free(imd->title_right);
1192 imd->title_right = g_strdup(title_right);
1193 imd->title_show_zoom = show_zoom;
1195 if (!options->image.fit_window_to_image) window = NULL;
1197 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1199 image_update_title(imd);
1202 void image_set_update_func(ImageWindow *imd,
1203 void (*func)(ImageWindow *imd, gpointer data),
1206 imd->func_update = func;
1207 imd->data_update = data;
1210 void image_set_complete_func(ImageWindow *imd,
1211 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1214 imd->func_complete = func;
1215 imd->data_complete = data;
1218 void image_set_state_func(ImageWindow *imd,
1219 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1222 imd->func_state = func;
1223 imd->data_state = data;
1227 void image_set_button_func(ImageWindow *imd,
1228 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1231 imd->func_button = func;
1232 imd->data_button = data;
1235 void image_set_drag_func(ImageWindow *imd,
1236 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1239 imd->func_drag = func;
1240 imd->data_drag = data;
1243 void image_set_scroll_func(ImageWindow *imd,
1244 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1247 imd->func_scroll = func;
1248 imd->data_scroll = data;
1251 void image_set_scroll_notify_func(ImageWindow *imd,
1252 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1255 imd->func_scroll_notify = func;
1256 imd->data_scroll_notify = data;
1261 const gchar *image_get_path(ImageWindow *imd)
1263 if (imd->image_fd == NULL) return NULL;
1264 return imd->image_fd->path;
1267 const gchar *image_get_name(ImageWindow *imd)
1269 if (imd->image_fd == NULL) return NULL;
1270 return imd->image_fd->name;
1273 FileData *image_get_fd(ImageWindow *imd)
1275 return imd->image_fd;
1278 /* merely changes path string, does not change the image! */
1279 void image_set_fd(ImageWindow *imd, FileData *fd)
1281 file_data_unref(imd->image_fd);
1282 imd->image_fd = file_data_ref(fd);
1284 image_update_title(imd);
1285 image_state_set(imd, IMAGE_STATE_IMAGE);
1288 /* load a new image */
1290 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1292 if (imd->image_fd == fd) return;
1294 image_change_real(imd, fd, NULL, NULL, zoom);
1297 gint image_get_image_size(ImageWindow *imd, gint *width, gint *height)
1299 return pixbuf_renderer_get_image_size(PIXBUF_RENDERER(imd->pr), width, height);
1302 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1304 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1307 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1310 ExifData *exif = NULL;
1311 gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
1312 gint read_exif_for_orientation = FALSE;
1314 if (imd->image_fd && imd->image_fd->user_orientation)
1315 imd->orientation = imd->image_fd->user_orientation;
1316 else if (options->image.exif_rotate_enable)
1317 read_exif_for_orientation = TRUE;
1319 if (read_exif_for_color_profile || read_exif_for_orientation)
1323 exif = exif_read_fd(imd->image_fd);
1325 if (exif && read_exif_for_orientation)
1327 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1328 imd->orientation = orientation;
1330 imd->orientation = 1;
1331 imd->image_fd->exif_orientation = imd->orientation;
1335 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1338 color_man_free(imd->cm);
1342 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1343 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1345 if (imd->color_profile_enable)
1347 if (!image_post_process_color(imd, 0, exif, FALSE))
1349 /* fixme: note error to user */
1350 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1356 if (imd->cm || imd->desaturate)
1357 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1359 image_state_set(imd, IMAGE_STATE_IMAGE);
1362 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1364 if (!cd || !info || !g_list_find(cd->list, info)) return;
1366 image_change_real(imd, info->fd, cd, info, zoom);
1369 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1371 if (collection_to_number(imd->collection) >= 0)
1373 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1375 if (info) *info = imd->collection_info;
1379 if (info) *info = NULL;
1381 return imd->collection;
1384 if (info) *info = NULL;
1388 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1390 /* change data for the callbacks directly */
1392 il->data_area_ready = data;
1393 il->data_error = data;
1394 il->data_done = data;
1395 il->data_percent = data;
1398 /* this is more like a move function
1399 * it moves most data from source to imd
1401 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1403 if (imd == source) return;
1405 imd->unknown = source->unknown;
1407 imd->collection = source->collection;
1408 imd->collection_info = source->collection_info;
1409 imd->size = source->size;
1410 imd->mtime = source->mtime;
1412 image_set_fd(imd, image_get_fd(source));
1414 image_loader_free(imd->il);
1419 imd->il = source->il;
1422 image_loader_sync_data(imd->il, imd);
1424 imd->delay_alter_type = source->delay_alter_type;
1425 source->delay_alter_type = ALTER_NONE;
1428 imd->color_profile_enable = source->color_profile_enable;
1429 imd->color_profile_input = source->color_profile_input;
1430 imd->color_profile_screen = source->color_profile_screen;
1431 imd->color_profile_use_image = source->color_profile_use_image;
1432 color_man_free((ColorMan *)imd->cm);
1438 imd->cm = source->cm;
1441 cm = (ColorMan *)imd->cm;
1443 cm->func_done_data = imd;
1446 image_loader_free(imd->read_ahead_il);
1447 imd->read_ahead_il = source->read_ahead_il;
1448 source->read_ahead_il = NULL;
1449 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1451 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1452 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1453 source->read_ahead_pixbuf = NULL;
1455 file_data_unref(imd->read_ahead_fd);
1456 imd->read_ahead_fd = source->read_ahead_fd;
1457 source->read_ahead_fd = NULL;
1459 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1460 imd->prev_pixbuf = source->prev_pixbuf;
1461 source->prev_pixbuf = NULL;
1462 imd->prev_color_row = source->prev_color_row;
1463 source->prev_color_row = -1;
1465 file_data_unref(imd->prev_fd);
1466 imd->prev_fd = source->prev_fd;
1467 source->prev_fd = NULL;
1469 imd->completed = source->completed;
1470 imd->state = source->state;
1471 source->state = IMAGE_STATE_NONE;
1473 imd->orientation = source->orientation;
1474 imd->desaturate = source->desaturate;
1476 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1478 if (imd->cm || imd->desaturate)
1479 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1481 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1487 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1489 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1492 void image_reload(ImageWindow *imd)
1494 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1496 image_change_complete(imd, image_zoom_get(imd), FALSE);
1499 void image_scroll(ImageWindow *imd, gint x, gint y)
1501 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1504 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1505 gdouble x_align, gdouble y_align)
1507 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1510 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1512 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1515 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1517 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1522 void image_alter(ImageWindow *imd, AlterType type)
1524 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1526 if (imd->il || imd->cm)
1528 /* still loading, wait till done */
1529 imd->delay_alter_type = type;
1530 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1532 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1534 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1539 image_alter_real(imd, type, TRUE);
1543 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1545 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1548 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1550 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1553 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1555 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1558 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1560 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1563 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1569 pr = (PixbufRenderer *)imd->pr;
1571 if (!pixbuf_renderer_get_pixbuf(pr) ||
1572 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1576 zoom = (gdouble)pr->window_height / height;
1580 zoom = (gdouble)pr->window_width / width;
1585 zoom = 0.0 - 1.0 / zoom;
1588 pixbuf_renderer_zoom_set(pr, zoom);
1591 gdouble image_zoom_get(ImageWindow *imd)
1593 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1596 gdouble image_zoom_get_real(ImageWindow *imd)
1598 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1601 gchar *image_zoom_get_as_text(ImageWindow *imd)
1609 gchar *approx = " ";
1611 zoom = image_zoom_get(imd);
1612 scale = image_zoom_get_real(imd);
1618 else if (zoom < 0.0)
1622 else if (zoom == 0.0 && scale != 0.0)
1635 if (rint(l) != l) pl = 1;
1636 if (rint(r) != r) pr = 1;
1638 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1641 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1645 if (mode == ZOOM_RESET_ORIGINAL)
1649 else if (mode == ZOOM_RESET_FIT_WINDOW)
1657 zoom = image_zoom_get(imd);
1670 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1672 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1676 image_read_ahead_set(imd, fd);
1680 image_read_ahead_cancel(imd);
1684 static gint image_auto_refresh_cb(gpointer data)
1686 ImageWindow *imd = data;
1689 if (!imd || !image_get_pixbuf(imd) ||
1690 imd->il || !imd->image_fd ||
1691 !options->update_on_time_change) return TRUE;
1693 newtime = filetime(imd->image_fd->path);
1694 if (newtime > 0 && newtime != imd->mtime)
1696 imd->mtime = newtime;
1703 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1705 void image_auto_refresh(ImageWindow *imd, gint interval)
1708 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1710 if (imd->auto_refresh_id > -1)
1712 g_source_remove(imd->auto_refresh_id);
1713 imd->auto_refresh_id = -1;
1714 imd->auto_refresh_interval = -1;
1717 if (interval < 0) return;
1719 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1721 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1722 imd->auto_refresh_interval = interval;
1725 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1727 imd->top_window_sync = allow_sync;
1729 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1732 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1734 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1737 void image_color_profile_set(ImageWindow *imd,
1738 gint input_type, gint screen_type,
1743 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1744 screen_type < 0 || screen_type > 1)
1749 imd->color_profile_input = input_type;
1750 imd->color_profile_screen = screen_type;
1751 imd->color_profile_use_image = use_image;
1754 gint image_color_profile_get(ImageWindow *imd,
1755 gint *input_type, gint *screen_type,
1758 if (!imd) return FALSE;
1760 if (input_type) *input_type = imd->color_profile_input;
1761 if (screen_type) *screen_type = imd->color_profile_screen;
1762 if (use_image) *use_image = imd->color_profile_use_image;
1767 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1771 if (imd->color_profile_enable == enable) return;
1773 imd->color_profile_enable = enable;
1776 gint image_color_profile_get_use(ImageWindow *imd)
1778 if (!imd) return FALSE;
1780 return imd->color_profile_enable;
1783 gint image_color_profile_get_from_image(ImageWindow *imd)
1785 if (!imd) return FALSE;
1787 return imd->color_profile_from_image;
1790 void image_set_delay_flip(ImageWindow *imd, gint delay)
1793 imd->delay_flip == delay) return;
1795 imd->delay_flip = delay;
1797 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1799 if (!imd->delay_flip && imd->il)
1803 pr = PIXBUF_RENDERER(imd->pr);
1804 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1807 image_load_pixbuf_ready(imd);
1811 void image_to_root_window(ImageWindow *imd, gint scaled)
1814 GdkWindow *rootwindow;
1822 pixbuf = image_get_pixbuf(imd);
1823 if (!pixbuf) return;
1825 screen = gtk_widget_get_screen(imd->widget);
1826 rootwindow = gdk_screen_get_root_window(screen);
1827 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1831 width = gdk_screen_width();
1832 height = gdk_screen_height();
1836 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1839 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1841 gdk_pixbuf_render_pixmap_and_mask(pb, &pixmap, NULL, 128);
1842 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1843 gdk_window_clear(rootwindow);
1845 g_object_unref(pixmap);
1850 void image_select(ImageWindow *imd, gboolean select)
1856 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1857 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1860 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1866 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1872 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1873 gtk_container_set_border_width(GTK_CONTAINER(imd->frame), 4);
1877 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1878 gtk_container_set_border_width(GTK_CONTAINER(imd->frame), 0);
1884 *-------------------------------------------------------------------
1886 *-------------------------------------------------------------------
1889 static void image_options_set(ImageWindow *imd)
1891 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1892 "zoom_2pass", options->image.zoom_2pass,
1893 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1894 "dither_quality", options->image.dither_quality,
1895 "scroll_reset", options->image.scroll_reset_method,
1896 "cache_display", options->image.tile_cache_max,
1897 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1898 "window_limit", options->image.limit_window_size,
1899 "window_limit_value", options->image.max_window_size,
1900 "autofit_limit", options->image.limit_autofit_size,
1901 "autofit_limit_value", options->image.max_autofit_size,
1905 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1908 void image_options_sync(void)
1920 image_options_set(imd);
1925 *-------------------------------------------------------------------
1927 *-------------------------------------------------------------------
1930 static void image_free(ImageWindow *imd)
1932 image_list = g_list_remove(image_list, imd);
1936 image_read_ahead_cancel(imd);
1937 image_post_buffer_set(imd, NULL, NULL, -1);
1938 image_auto_refresh(imd, -1);
1940 file_data_unref(imd->image_fd);
1942 g_free(imd->title_right);
1944 if (imd->histogram) histogram_free(imd->histogram);
1949 static void image_destroy_cb(GtkObject *widget, gpointer data)
1951 ImageWindow *imd = data;
1955 gboolean selectable_frame_expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1957 gtk_paint_flat_box(widget->style,
1960 (GTK_FRAME(widget))->shadow_type,
1964 widget->allocation.x + 3, widget->allocation.y + 3,
1965 widget->allocation.width - 6, widget->allocation.height - 6);
1972 void image_set_frame(ImageWindow *imd, gboolean frame)
1976 if (frame == imd->has_frame) return;
1978 gtk_widget_hide(imd->pr);
1982 imd->frame = gtk_frame_new(NULL);
1983 gtk_widget_ref(imd->pr);
1984 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1985 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1986 gtk_widget_unref(imd->pr);
1987 g_signal_connect(G_OBJECT(imd->frame), "expose_event",
1988 G_CALLBACK(selectable_frame_expose_cb), NULL);
1990 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1991 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1992 G_CALLBACK(image_focus_in_cb), imd);
1993 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1994 G_CALLBACK(image_focus_out_cb), imd);
1996 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1997 G_CALLBACK(image_focus_expose), imd);
2000 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
2001 gtk_widget_show(imd->frame);
2005 gtk_widget_ref(imd->pr);
2008 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
2009 gtk_widget_destroy(imd->frame);
2012 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2013 gtk_widget_unref(imd->pr);
2016 gtk_widget_show(imd->pr);
2018 imd->has_frame = frame;
2021 ImageWindow *image_new(gint frame)
2025 imd = g_new0(ImageWindow, 1);
2027 imd->top_window = NULL;
2029 imd->title_right = NULL;
2030 imd->title_show_zoom = FALSE;
2032 imd->unknown = TRUE;
2034 imd->has_frame = -1; /* not initialized; for image_set_frame */
2035 imd->top_window_sync = FALSE;
2037 imd->delay_alter_type = ALTER_NONE;
2039 imd->read_ahead_il = NULL;
2040 imd->read_ahead_pixbuf = NULL;
2041 imd->read_ahead_fd = NULL;
2043 imd->completed = FALSE;
2044 imd->state = IMAGE_STATE_NONE;
2046 imd->color_profile_enable = FALSE;
2047 imd->color_profile_input = 0;
2048 imd->color_profile_screen = 0;
2049 imd->color_profile_use_image = FALSE;
2050 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2052 imd->auto_refresh_id = -1;
2053 imd->auto_refresh_interval = -1;
2055 imd->delay_flip = FALSE;
2057 imd->func_update = NULL;
2058 imd->func_complete = NULL;
2059 imd->func_tile_request = NULL;
2060 imd->func_tile_dispose = NULL;
2062 imd->func_button = NULL;
2063 imd->func_scroll = NULL;
2065 imd->orientation = 1;
2067 imd->histogram_enabled = FALSE; /* TODO: option */
2069 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2071 image_options_set(imd);
2074 imd->widget = gtk_vbox_new(0, 0);
2076 image_set_frame(imd, frame);
2078 image_set_selectable(imd, 0);
2080 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2081 G_CALLBACK(image_click_cb), imd);
2082 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2083 G_CALLBACK(image_scroll_notify_cb), imd);
2085 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2086 G_CALLBACK(image_scroll_cb), imd);
2088 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2089 G_CALLBACK(image_destroy_cb), imd);
2091 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2092 G_CALLBACK(image_zoom_cb), imd);
2093 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2094 G_CALLBACK(image_render_complete_cb), imd);
2095 g_signal_connect(G_OBJECT(imd->pr), "drag",
2096 G_CALLBACK(image_drag_cb), imd);
2098 image_list = g_list_append(image_list, imd);