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!
18 #include "image-load.h"
20 #include "color-man.h"
22 #include "histogram.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)\n", 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\n", 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\n", 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\n");
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\n");
413 g_free(interop_index);
419 DEBUG_1("Found embedded color profile\n");
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\n", 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)
553 const static gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1};
554 const static gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3};
555 const static gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6};
556 const static gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7};
557 const static gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5};
560 if (!imd || !imd->pr) return;
562 if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
566 case ALTER_ROTATE_90:
567 imd->orientation = rotate_90[imd->orientation];
569 case ALTER_ROTATE_90_CC:
570 imd->orientation = rotate_90_cc[imd->orientation];
572 case ALTER_ROTATE_180:
573 imd->orientation = rotate_180[imd->orientation];
576 imd->orientation = mirror[imd->orientation];
579 imd->orientation = flip[imd->orientation];
581 case ALTER_DESATURATE:
582 imd->desaturate = !imd->desaturate;
585 imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1;
586 imd->desaturate = FALSE;
593 if (type != ALTER_NONE && type != ALTER_DESATURATE)
595 if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd);
596 imd->image_fd->user_orientation = imd->orientation;
600 if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd);
601 imd->image_fd->user_orientation = 0;
604 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
605 if (imd->cm || imd->desaturate)
606 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
608 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
613 *-------------------------------------------------------------------
614 * read ahead (prebuffer)
615 *-------------------------------------------------------------------
618 static void image_read_ahead_cancel(ImageWindow *imd)
620 DEBUG_1("%s read ahead cancelled for :%s\n", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
622 image_loader_free(imd->read_ahead_il);
623 imd->read_ahead_il = NULL;
625 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
626 imd->read_ahead_pixbuf = NULL;
628 file_data_unref(imd->read_ahead_fd);
629 imd->read_ahead_fd = NULL;
632 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
634 ImageWindow *imd = data;
636 DEBUG_1("%s read ahead done for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
638 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
639 if (imd->read_ahead_pixbuf)
641 g_object_ref(imd->read_ahead_pixbuf);
645 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
647 image_loader_free(imd->read_ahead_il);
648 imd->read_ahead_il = NULL;
650 image_complete_util(imd, TRUE);
653 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
655 /* we even treat errors as success, maybe at least some of the file was ok */
656 image_read_ahead_done_cb(il, data);
659 static void image_read_ahead_start(ImageWindow *imd)
661 /* already started ? */
662 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
664 /* still loading ?, do later */
665 if (imd->il /*|| imd->cm*/) return;
667 DEBUG_1("%s read ahead started for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
669 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
671 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
672 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
674 image_read_ahead_cancel(imd);
675 image_complete_util(imd, TRUE);
679 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
681 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
683 image_read_ahead_cancel(imd);
685 imd->read_ahead_fd = file_data_ref(fd);
687 DEBUG_1("read ahead set to :%s\n", imd->read_ahead_fd->path);
689 image_read_ahead_start(imd);
693 *-------------------------------------------------------------------
695 *-------------------------------------------------------------------
698 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
700 file_data_unref(imd->prev_fd);
701 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
705 imd->prev_fd = file_data_ref(fd);
707 g_object_ref(pixbuf);
708 imd->prev_pixbuf = pixbuf;
709 imd->prev_color_row = color_row;
714 imd->prev_pixbuf = NULL;
715 imd->prev_color_row = -1;
718 DEBUG_1("%s post buffer set: %s\n", get_exec_time(), fd ? fd->path : "null");
721 static gint image_post_buffer_get(ImageWindow *imd)
725 if (imd->prev_pixbuf &&
726 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
728 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
729 if (imd->prev_color_row >= 0)
731 ExifData *exif = NULL;
733 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
734 // image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
744 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
745 imd->prev_pixbuf = NULL;
747 file_data_unref(imd->prev_fd);
754 *-------------------------------------------------------------------
756 *-------------------------------------------------------------------
759 static void image_load_pixbuf_ready(ImageWindow *imd)
761 if (image_get_pixbuf(imd) || !imd->il) return;
763 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
766 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
768 ImageWindow *imd = data;
771 pr = (PixbufRenderer *)imd->pr;
773 if (imd->delay_flip &&
774 pr->pixbuf != image_loader_get_pixbuf(il))
779 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
781 pixbuf_renderer_area_changed(pr, x, y, w, h);
784 static void image_load_done_cb(ImageLoader *il, gpointer data)
786 ImageWindow *imd = data;
788 DEBUG_1 ("%s image done\n", get_exec_time());
790 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
791 image_state_unset(imd, IMAGE_STATE_LOADING);
793 if (imd->delay_flip &&
794 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
796 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
797 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
800 image_loader_free(imd->il);
803 image_post_process(imd, TRUE);
805 image_read_ahead_start(imd);
808 static void image_load_error_cb(ImageLoader *il, gpointer data)
810 DEBUG_1 ("%s image error\n", get_exec_time());
812 /* even on error handle it like it was done,
813 * since we have a pixbuf with _something_ */
815 image_load_done_cb(il, data);
818 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
819 static void image_load_buffer_throttle(ImageLoader *il)
821 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
823 /* Larger image files usually have larger chunks of data per pixel...
824 * So increase the buffer read size so that the rendering chunks called
828 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
832 /* this read ahead is located here merely for the callbacks, above */
834 static gint image_read_ahead_check(ImageWindow *imd)
836 if (!imd->read_ahead_fd) return FALSE;
837 if (imd->il) return FALSE;
839 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
841 image_read_ahead_cancel(imd);
845 if (imd->read_ahead_il)
847 imd->il = imd->read_ahead_il;
848 imd->read_ahead_il = NULL;
850 /* override the old signals */
851 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
852 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
853 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
855 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
856 image_load_buffer_throttle(imd->il);
859 /* do this one directly (probably should add a set func) */
860 imd->il->func_done = image_load_done_cb;
862 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
863 image_state_set(imd, IMAGE_STATE_LOADING);
865 if (!imd->delay_flip)
867 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
870 image_read_ahead_cancel(imd);
873 else if (imd->read_ahead_pixbuf)
875 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
876 g_object_unref(imd->read_ahead_pixbuf);
877 imd->read_ahead_pixbuf = NULL;
879 image_read_ahead_cancel(imd);
881 image_post_process(imd, FALSE);
885 image_read_ahead_cancel(imd);
889 static gint image_load_begin(ImageWindow *imd, FileData *fd)
891 DEBUG_1 ("%s image begin \n", get_exec_time());
893 if (imd->il) return FALSE;
895 imd->completed = FALSE;
896 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
898 if (image_post_buffer_get(imd))
900 DEBUG_1("from post buffer: %s\n", imd->image_fd->path);
904 if (image_read_ahead_check(imd))
906 DEBUG_1("from read ahead buffer: %s\n", imd->image_fd->path);
910 if (!imd->delay_flip && image_get_pixbuf(imd))
914 pr = PIXBUF_RENDERER(imd->pr);
915 if (pr->pixbuf) g_object_unref(pr->pixbuf);
919 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
921 imd->il = image_loader_new(fd);
923 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
924 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
925 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
927 if (!image_loader_start(imd->il, image_load_done_cb, imd))
929 DEBUG_1("image start error\n");
931 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
933 image_loader_free(imd->il);
936 image_complete_util(imd, FALSE);
941 image_state_set(imd, IMAGE_STATE_LOADING);
943 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
944 image_load_buffer_throttle(imd->il);
947 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
952 static void image_reset(ImageWindow *imd)
954 /* stops anything currently being done */
956 DEBUG_1("%s image reset\n", get_exec_time());
958 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
960 image_loader_free(imd->il);
963 color_man_free((ColorMan *)imd->cm);
966 imd->delay_alter_type = ALTER_NONE;
968 image_state_set(imd, IMAGE_STATE_NONE);
972 *-------------------------------------------------------------------
974 *-------------------------------------------------------------------
977 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
981 if (imd->image_fd && isfile(imd->image_fd->path))
985 pr = PIXBUF_RENDERER(imd->pr);
986 pr->zoom = zoom; /* store the zoom, needed by the loader */
988 if (image_load_begin(imd, imd->image_fd))
990 imd->unknown = FALSE;
996 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
997 image_change_pixbuf(imd, pixbuf, zoom);
998 g_object_unref(pixbuf);
1000 imd->unknown = TRUE;
1002 imd->size = filesize(imd->image_fd->path);
1003 imd->mtime = filetime(imd->image_fd->path);
1011 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
1012 image_change_pixbuf(imd, pixbuf, zoom);
1013 g_object_unref(pixbuf);
1014 imd->mtime = filetime(imd->image_fd->path);
1018 image_change_pixbuf(imd, NULL, zoom);
1021 imd->unknown = TRUE;
1025 image_update_util(imd);
1028 static void image_change_real(ImageWindow *imd, FileData *fd,
1029 CollectionData *cd, CollectInfo *info, gdouble zoom)
1032 GdkPixbuf *prev_pixbuf = NULL;
1033 FileData *prev_fd = NULL;
1034 gint prev_clear = FALSE;
1035 gint prev_color_row = -1;
1037 imd->collection = cd;
1038 imd->collection_info = info;
1040 pixbuf = image_get_pixbuf(imd);
1042 if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1046 /* current image is not finished */
1051 prev_fd = file_data_ref(imd->image_fd);
1052 prev_pixbuf = pixbuf;
1053 g_object_ref(prev_pixbuf);
1059 cm = (ColorMan *)imd->cm;
1060 prev_color_row = cm->row;
1065 file_data_unref(imd->image_fd);
1066 imd->image_fd = file_data_ref(fd);
1068 image_change_complete(imd, zoom, TRUE);
1072 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
1073 file_data_unref(prev_fd);
1074 g_object_unref(prev_pixbuf);
1076 else if (prev_clear)
1078 image_post_buffer_set(imd, NULL, NULL, -1);
1081 image_update_title(imd);
1082 image_state_set(imd, IMAGE_STATE_IMAGE);
1086 *-------------------------------------------------------------------
1088 *-------------------------------------------------------------------
1091 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1095 widget = imd->widget;
1096 if (!widget->window) return;
1100 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
1101 area, widget, "image_window",
1102 widget->allocation.x, widget->allocation.y,
1103 widget->allocation.width - 1, widget->allocation.height - 1);
1107 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1108 area, widget, "image_window",
1109 widget->allocation.x, widget->allocation.y,
1110 widget->allocation.width - 1, widget->allocation.height - 1);
1114 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1116 ImageWindow *imd = data;
1118 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1122 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1124 ImageWindow *imd = data;
1126 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1127 image_focus_paint(imd, TRUE, NULL);
1132 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1134 ImageWindow *imd = data;
1136 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1137 image_focus_paint(imd, FALSE, NULL);
1142 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1143 gint relative, gint always)
1145 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1148 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1150 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1153 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1155 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1158 void image_overlay_remove(ImageWindow *imd, gint id)
1160 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1163 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1165 ImageWindow *imd = data;
1167 if (imd->func_scroll &&
1168 event && event->type == GDK_SCROLL)
1170 imd->func_scroll(imd, event->direction, event->time,
1171 event->x, event->y, event->state, imd->data_scroll);
1179 *-------------------------------------------------------------------
1181 *-------------------------------------------------------------------
1184 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1185 const gchar *title, const gchar *title_right, gint show_zoom)
1187 imd->top_window = window;
1189 imd->title = g_strdup(title);
1190 g_free(imd->title_right);
1191 imd->title_right = g_strdup(title_right);
1192 imd->title_show_zoom = show_zoom;
1194 if (!options->image.fit_window_to_image) window = NULL;
1196 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1198 image_update_title(imd);
1201 void image_set_update_func(ImageWindow *imd,
1202 void (*func)(ImageWindow *imd, gpointer data),
1205 imd->func_update = func;
1206 imd->data_update = data;
1209 void image_set_complete_func(ImageWindow *imd,
1210 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1213 imd->func_complete = func;
1214 imd->data_complete = data;
1217 void image_set_state_func(ImageWindow *imd,
1218 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1221 imd->func_state = func;
1222 imd->data_state = data;
1226 void image_set_button_func(ImageWindow *imd,
1227 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1230 imd->func_button = func;
1231 imd->data_button = data;
1234 void image_set_drag_func(ImageWindow *imd,
1235 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1238 imd->func_drag = func;
1239 imd->data_drag = data;
1242 void image_set_scroll_func(ImageWindow *imd,
1243 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1246 imd->func_scroll = func;
1247 imd->data_scroll = data;
1250 void image_set_scroll_notify_func(ImageWindow *imd,
1251 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1254 imd->func_scroll_notify = func;
1255 imd->data_scroll_notify = data;
1260 const gchar *image_get_path(ImageWindow *imd)
1262 if (imd->image_fd == NULL) return NULL;
1263 return imd->image_fd->path;
1266 const gchar *image_get_name(ImageWindow *imd)
1268 if (imd->image_fd == NULL) return NULL;
1269 return imd->image_fd->name;
1272 FileData *image_get_fd(ImageWindow *imd)
1274 return imd->image_fd;
1277 /* merely changes path string, does not change the image! */
1278 void image_set_fd(ImageWindow *imd, FileData *fd)
1280 file_data_unref(imd->image_fd);
1281 imd->image_fd = file_data_ref(fd);
1283 image_update_title(imd);
1284 image_state_set(imd, IMAGE_STATE_IMAGE);
1287 /* load a new image */
1289 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1291 if (imd->image_fd == fd) return;
1293 image_change_real(imd, fd, NULL, NULL, zoom);
1296 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1298 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1301 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1304 ExifData *exif = NULL;
1305 gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
1306 gint read_exif_for_orientation = FALSE;
1308 if (imd->image_fd && imd->image_fd->user_orientation)
1309 imd->orientation = imd->image_fd->user_orientation;
1310 else if (options->image.exif_rotate_enable)
1311 read_exif_for_orientation = TRUE;
1313 if (read_exif_for_color_profile || read_exif_for_orientation)
1317 exif = exif_read_fd(imd->image_fd);
1319 if (exif && read_exif_for_orientation)
1321 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1322 imd->orientation = orientation;
1324 imd->orientation = 1;
1325 imd->image_fd->exif_orientation = imd->orientation;
1329 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1332 color_man_free(imd->cm);
1336 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1337 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1339 if (imd->color_profile_enable)
1341 if (!image_post_process_color(imd, 0, exif, FALSE))
1343 /* fixme: note error to user */
1344 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1350 if (imd->cm || imd->desaturate)
1351 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1353 image_state_set(imd, IMAGE_STATE_IMAGE);
1356 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1358 if (!cd || !info || !g_list_find(cd->list, info)) return;
1360 image_change_real(imd, info->fd, cd, info, zoom);
1363 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1365 if (collection_to_number(imd->collection) >= 0)
1367 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1369 if (info) *info = imd->collection_info;
1373 if (info) *info = NULL;
1375 return imd->collection;
1378 if (info) *info = NULL;
1382 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1384 /* change data for the callbacks directly */
1386 il->data_area_ready = data;
1387 il->data_error = data;
1388 il->data_done = data;
1389 il->data_percent = data;
1392 /* this is more like a move function
1393 * it moves most data from source to imd
1395 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1397 if (imd == source) return;
1399 imd->unknown = source->unknown;
1401 imd->collection = source->collection;
1402 imd->collection_info = source->collection_info;
1403 imd->size = source->size;
1404 imd->mtime = source->mtime;
1406 image_set_fd(imd, image_get_fd(source));
1408 image_loader_free(imd->il);
1413 imd->il = source->il;
1416 image_loader_sync_data(imd->il, imd);
1418 imd->delay_alter_type = source->delay_alter_type;
1419 source->delay_alter_type = ALTER_NONE;
1422 imd->color_profile_enable = source->color_profile_enable;
1423 imd->color_profile_input = source->color_profile_input;
1424 imd->color_profile_screen = source->color_profile_screen;
1425 imd->color_profile_use_image = source->color_profile_use_image;
1426 color_man_free((ColorMan *)imd->cm);
1432 imd->cm = source->cm;
1435 cm = (ColorMan *)imd->cm;
1437 cm->func_done_data = imd;
1440 image_loader_free(imd->read_ahead_il);
1441 imd->read_ahead_il = source->read_ahead_il;
1442 source->read_ahead_il = NULL;
1443 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1445 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1446 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1447 source->read_ahead_pixbuf = NULL;
1449 file_data_unref(imd->read_ahead_fd);
1450 imd->read_ahead_fd = source->read_ahead_fd;
1451 source->read_ahead_fd = NULL;
1453 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1454 imd->prev_pixbuf = source->prev_pixbuf;
1455 source->prev_pixbuf = NULL;
1456 imd->prev_color_row = source->prev_color_row;
1457 source->prev_color_row = -1;
1459 file_data_unref(imd->prev_fd);
1460 imd->prev_fd = source->prev_fd;
1461 source->prev_fd = NULL;
1463 imd->completed = source->completed;
1464 imd->state = source->state;
1465 source->state = IMAGE_STATE_NONE;
1467 imd->orientation = source->orientation;
1468 imd->desaturate = source->desaturate;
1470 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1472 if (imd->cm || imd->desaturate)
1473 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1475 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1481 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1483 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1486 void image_reload(ImageWindow *imd)
1488 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1490 image_change_complete(imd, image_zoom_get(imd), FALSE);
1493 void image_scroll(ImageWindow *imd, gint x, gint y)
1495 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1498 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1499 gdouble x_align, gdouble y_align)
1501 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1504 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1506 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1509 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1511 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1516 void image_alter(ImageWindow *imd, AlterType type)
1518 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1520 if (imd->il || imd->cm)
1522 /* still loading, wait till done */
1523 imd->delay_alter_type = type;
1524 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1526 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1528 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1533 image_alter_real(imd, type, TRUE);
1537 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1539 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1542 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1544 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1547 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1549 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1552 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1554 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1557 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1563 pr = (PixbufRenderer *)imd->pr;
1565 if (!pixbuf_renderer_get_pixbuf(pr) ||
1566 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1570 zoom = (gdouble)pr->window_height / height;
1574 zoom = (gdouble)pr->window_width / width;
1579 zoom = 0.0 - 1.0 / zoom;
1582 pixbuf_renderer_zoom_set(pr, zoom);
1585 gdouble image_zoom_get(ImageWindow *imd)
1587 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1590 gdouble image_zoom_get_real(ImageWindow *imd)
1592 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1595 gchar *image_zoom_get_as_text(ImageWindow *imd)
1603 gchar *approx = " ";
1605 zoom = image_zoom_get(imd);
1606 scale = image_zoom_get_real(imd);
1612 else if (zoom < 0.0)
1616 else if (zoom == 0.0 && scale != 0.0)
1629 if (rint(l) != l) pl = 1;
1630 if (rint(r) != r) pr = 1;
1632 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1635 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1639 if (mode == ZOOM_RESET_ORIGINAL)
1643 else if (mode == ZOOM_RESET_FIT_WINDOW)
1651 zoom = image_zoom_get(imd);
1664 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1666 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1670 image_read_ahead_set(imd, fd);
1674 image_read_ahead_cancel(imd);
1678 static gint image_auto_refresh_cb(gpointer data)
1680 ImageWindow *imd = data;
1683 if (!imd || !image_get_pixbuf(imd) ||
1684 imd->il || !imd->image_fd ||
1685 !options->update_on_time_change) return TRUE;
1687 newtime = filetime(imd->image_fd->path);
1688 if (newtime > 0 && newtime != imd->mtime)
1690 imd->mtime = newtime;
1697 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1699 void image_auto_refresh(ImageWindow *imd, gint interval)
1702 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1704 if (imd->auto_refresh_id > -1)
1706 g_source_remove(imd->auto_refresh_id);
1707 imd->auto_refresh_id = -1;
1708 imd->auto_refresh_interval = -1;
1711 if (interval < 0) return;
1713 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1715 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1716 imd->auto_refresh_interval = interval;
1719 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1721 imd->top_window_sync = allow_sync;
1723 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1726 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1728 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1731 void image_color_profile_set(ImageWindow *imd,
1732 gint input_type, gint screen_type,
1737 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1738 screen_type < 0 || screen_type > 1)
1743 imd->color_profile_input = input_type;
1744 imd->color_profile_screen = screen_type;
1745 imd->color_profile_use_image = use_image;
1748 gint image_color_profile_get(ImageWindow *imd,
1749 gint *input_type, gint *screen_type,
1752 if (!imd) return FALSE;
1754 if (input_type) *input_type = imd->color_profile_input;
1755 if (screen_type) *screen_type = imd->color_profile_screen;
1756 if (use_image) *use_image = imd->color_profile_use_image;
1761 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1765 if (imd->color_profile_enable == enable) return;
1767 imd->color_profile_enable = enable;
1770 gint image_color_profile_get_use(ImageWindow *imd)
1772 if (!imd) return FALSE;
1774 return imd->color_profile_enable;
1777 gint image_color_profile_get_from_image(ImageWindow *imd)
1779 if (!imd) return FALSE;
1781 return imd->color_profile_from_image;
1784 void image_set_delay_flip(ImageWindow *imd, gint delay)
1787 imd->delay_flip == delay) return;
1789 imd->delay_flip = delay;
1791 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1793 if (!imd->delay_flip && imd->il)
1797 pr = PIXBUF_RENDERER(imd->pr);
1798 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1801 image_load_pixbuf_ready(imd);
1805 void image_to_root_window(ImageWindow *imd, gint scaled)
1808 GdkWindow *rootwindow;
1816 pixbuf = image_get_pixbuf(imd);
1817 if (!pixbuf) return;
1819 screen = gtk_widget_get_screen(imd->widget);
1820 rootwindow = gdk_screen_get_root_window(screen);
1821 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1825 width = gdk_screen_width();
1826 height = gdk_screen_height();
1830 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1833 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1835 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1836 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1837 gdk_window_clear(rootwindow);
1839 g_object_unref(pixmap);
1844 void image_select(ImageWindow *imd, gboolean select)
1850 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1851 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1854 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1860 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1866 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1867 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1871 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1872 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1878 *-------------------------------------------------------------------
1880 *-------------------------------------------------------------------
1883 static void image_options_set(ImageWindow *imd)
1885 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1886 "zoom_2pass", options->image.zoom_2pass,
1887 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1888 "dither_quality", options->image.dither_quality,
1889 "scroll_reset", options->image.scroll_reset_method,
1890 "cache_display", options->image.tile_cache_max,
1891 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1892 "window_limit", options->image.limit_window_size,
1893 "window_limit_value", options->image.max_window_size,
1894 "autofit_limit", options->image.limit_autofit_size,
1895 "autofit_limit_value", options->image.max_autofit_size,
1899 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1902 void image_options_sync(void)
1914 image_options_set(imd);
1919 *-------------------------------------------------------------------
1921 *-------------------------------------------------------------------
1924 static void image_free(ImageWindow *imd)
1926 image_list = g_list_remove(image_list, imd);
1930 image_read_ahead_cancel(imd);
1931 image_post_buffer_set(imd, NULL, NULL, -1);
1932 image_auto_refresh(imd, -1);
1934 file_data_unref(imd->image_fd);
1936 g_free(imd->title_right);
1938 if (imd->histogram) histogram_free(imd->histogram);
1943 static void image_destroy_cb(GtkObject *widget, gpointer data)
1945 ImageWindow *imd = data;
1949 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1951 gtk_paint_flat_box(widget->style,
1954 GTK_FRAME (widget)->shadow_type,
1958 widget->allocation.x + 3, widget->allocation.y + 3,
1959 widget->allocation.width - 6, widget->allocation.height - 6);
1966 void image_set_frame(ImageWindow *imd, gboolean frame)
1970 if (frame == imd->has_frame) return;
1972 gtk_widget_hide(imd->pr);
1976 imd->frame = gtk_frame_new(NULL);
1977 gtk_widget_ref(imd->pr);
1978 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1979 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1980 gtk_widget_unref(imd->pr);
1981 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1982 G_CALLBACK (selectable_frame_expose_cb), NULL);
1984 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1985 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1986 G_CALLBACK(image_focus_in_cb), imd);
1987 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1988 G_CALLBACK(image_focus_out_cb), imd);
1990 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1991 G_CALLBACK(image_focus_expose), imd);
1994 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1995 gtk_widget_show(imd->frame);
1999 gtk_widget_ref(imd->pr);
2002 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
2003 gtk_widget_destroy(imd->frame);
2006 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2007 gtk_widget_unref(imd->pr);
2010 gtk_widget_show(imd->pr);
2012 imd->has_frame = frame;
2015 ImageWindow *image_new(gint frame)
2019 imd = g_new0(ImageWindow, 1);
2021 imd->top_window = NULL;
2023 imd->title_right = NULL;
2024 imd->title_show_zoom = FALSE;
2026 imd->unknown = TRUE;
2028 imd->has_frame = -1; /* not initialized; for image_set_frame */
2029 imd->top_window_sync = FALSE;
2031 imd->delay_alter_type = ALTER_NONE;
2033 imd->read_ahead_il = NULL;
2034 imd->read_ahead_pixbuf = NULL;
2035 imd->read_ahead_fd = NULL;
2037 imd->completed = FALSE;
2038 imd->state = IMAGE_STATE_NONE;
2040 imd->color_profile_enable = FALSE;
2041 imd->color_profile_input = 0;
2042 imd->color_profile_screen = 0;
2043 imd->color_profile_use_image = FALSE;
2044 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2046 imd->auto_refresh_id = -1;
2047 imd->auto_refresh_interval = -1;
2049 imd->delay_flip = FALSE;
2051 imd->func_update = NULL;
2052 imd->func_complete = NULL;
2053 imd->func_tile_request = NULL;
2054 imd->func_tile_dispose = NULL;
2056 imd->func_button = NULL;
2057 imd->func_scroll = NULL;
2059 imd->orientation = 1;
2061 imd->histogram_enabled = FALSE; /* TODO: option */
2063 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2065 image_options_set(imd);
2068 imd->widget = gtk_vbox_new(0, 0);
2070 image_set_frame(imd, frame);
2072 image_set_selectable(imd, 0);
2074 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2075 G_CALLBACK(image_click_cb), imd);
2076 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2077 G_CALLBACK(image_scroll_notify_cb), imd);
2079 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2080 G_CALLBACK(image_scroll_cb), imd);
2082 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2083 G_CALLBACK(image_destroy_cb), imd);
2085 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2086 G_CALLBACK(image_zoom_cb), imd);
2087 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2088 G_CALLBACK(image_render_complete_cb), imd);
2089 g_signal_connect(G_OBJECT(imd->pr), "drag",
2090 G_CALLBACK(image_drag_cb), imd);
2092 image_list = g_list_append(image_list, imd);