7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
17 #include "image-load.h"
19 #include "color-man.h"
21 #include "image-overlay.h"
23 #include "layout_image.h"
24 #include "pixbuf-renderer.h"
25 #include "pixbuf_util.h"
26 #include "ui_fileops.h"
33 /* size of the image loader buffer (512 bytes x defined number) */
34 #define IMAGE_LOAD_BUFFER_COUNT 8
36 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
37 #define IMAGE_THROTTLE_LARGER_IMAGES 1
39 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
40 #define IMAGE_THROTTLE_FACTOR 32
42 /* the file size at which throttling take place */
43 #define IMAGE_THROTTLE_THRESHOLD 1048576
45 #define IMAGE_AUTO_REFRESH_TIME 3000
48 static GList *image_list = NULL;
51 static void image_update_title(ImageWindow *imd);
52 static void image_post_process(ImageWindow *imd, gint clamp);
53 static void image_read_ahead_start(ImageWindow *imd);
56 *-------------------------------------------------------------------
58 *-------------------------------------------------------------------
61 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
63 ImageWindow *imd = data;
67 imd->func_button(imd, event->button, event->time,
68 event->x, event->y, event->state, imd->data_button);
72 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
74 ImageWindow *imd = data;
77 pixbuf_renderer_get_scaled_size(pr, &width, &height);
81 imd->func_drag(imd, event->button, event->time,
82 event->x, event->y, event->state,
83 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
88 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
90 ImageWindow *imd = data;
92 if (imd->func_scroll_notify && pr->scale)
94 imd->func_scroll_notify(imd,
95 (gint)((gdouble)pr->x_scroll / pr->scale),
96 (gint)((gdouble)pr->y_scroll / pr->scale),
97 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
98 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
99 imd->data_scroll_notify);
103 static void image_update_util(ImageWindow *imd)
105 if (imd->func_update) imd->func_update(imd, imd->data_update);
108 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
110 ImageWindow *imd = data;
112 if (imd->title_show_zoom) image_update_title(imd);
113 if (imd->overlay_show_zoom) image_osd_update(imd);
115 image_update_util(imd);
118 static void image_complete_util(ImageWindow *imd, gint preload)
120 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
122 if (debug) printf("%s image load completed \"%s\" (%s)\n", get_exec_time(),
123 (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") :
124 (imd->image_fd ? imd->image_fd->path : "null"),
125 (preload) ? "preload" : "current");
127 if (!preload) imd->completed = TRUE;
128 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
131 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
133 ImageWindow *imd = data;
135 image_complete_util(imd, FALSE);
138 static void image_state_set(ImageWindow *imd, ImageState state)
140 if (state == IMAGE_STATE_NONE)
148 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
151 static void image_state_unset(ImageWindow *imd, ImageState state)
153 imd->state &= ~state;
154 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
158 *-------------------------------------------------------------------
160 *-------------------------------------------------------------------
163 static void image_update_title(ImageWindow *imd)
167 gchar *collection = NULL;
169 if (!imd->top_window) return;
171 if (imd->collection && collection_to_number(imd->collection) >= 0)
174 name = imd->collection->name;
175 if (!name) name = _("Untitled");
176 collection = g_strdup_printf(" (Collection %s)", name);
179 if (imd->title_show_zoom)
181 gchar *buf = image_zoom_get_as_text(imd);
182 zoom = g_strconcat(" [", buf, "]", NULL);
186 title = g_strdup_printf("%s%s%s%s%s%s",
187 imd->title ? imd->title : "",
188 imd->image_fd ? imd->image_fd->name : "",
190 collection ? collection : "",
191 imd->image_fd ? " - " : "",
192 imd->title_right ? imd->title_right : "");
194 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
202 *-------------------------------------------------------------------
203 * rotation, flip, etc.
204 *-------------------------------------------------------------------
210 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
213 GdkPixbuf *new = NULL;
218 pr = (PixbufRenderer *)imd->pr;
220 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
221 imd->delay_alter_type = ALTER_NONE;
223 if (!pr->pixbuf) return;
225 x = pr->x_scroll + (pr->vis_width / 2);
226 y = pr->y_scroll + (pr->vis_height / 2);
230 case ALTER_ROTATE_90:
231 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
236 case ALTER_ROTATE_90_CC:
237 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
242 case ALTER_ROTATE_180:
243 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
248 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
252 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
255 case ALTER_DESATURATE:
256 pixbuf_desaturate_rect(pr->pixbuf,
257 0, 0, pr->image_width, pr->image_height);
258 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
259 layout_image_overlay_update(layout_find_by_image(imd));
269 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
272 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
276 switch (pr->scroll_reset)
278 case PR_SCROLL_RESET_NOCHANGE:
280 case PR_SCROLL_RESET_CENTER:
281 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
282 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
284 case PR_SCROLL_RESET_TOPLEFT:
291 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
292 (gint)((gdouble)y / pr->scale),
296 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
297 layout_image_overlay_update(layout_find_by_image(imd));
298 if (debug) printf("%s image postprocess done: %s\n", get_exec_time(), imd->image_fd->name);
301 static void image_post_process_alter(ImageWindow *imd, gint clamp)
303 if (imd->delay_alter_type != ALTER_NONE)
305 image_alter_real(imd, imd->delay_alter_type, clamp);
310 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
312 ImageWindow *imd = data;
315 if (type == COLOR_RETURN_IMAGE_CHANGED)
317 if (cm == imd->cm) imd->cm = NULL;
322 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
323 if (debug) printf("%s image postprocess cm done: %s\n", get_exec_time(), imd->image_fd->name);
325 image_post_process_alter(imd, FALSE);
327 image_read_ahead_start(imd);
331 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg)
334 ColorManProfileType input_type;
335 ColorManProfileType screen_type;
336 const gchar *input_file;
337 const gchar *screen_file;
338 unsigned char *profile = NULL;
341 if (imd->cm) return FALSE;
343 if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
344 imd->color_profile_input < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
348 n = imd->color_profile_input - COLOR_PROFILE_FILE;
349 if (!options->color_profile.input_file[n]) return FALSE;
351 input_type = COLOR_PROFILE_FILE;
352 input_file = options->color_profile.input_file[n];
354 else if (imd->color_profile_input >= COLOR_PROFILE_SRGB &&
355 imd->color_profile_input < COLOR_PROFILE_FILE)
357 input_type = imd->color_profile_input;
365 if (imd->color_profile_screen == 1 &&
366 options->color_profile.screen_file)
368 screen_type = COLOR_PROFILE_FILE;
369 screen_file = options->color_profile.screen_file;
371 else if (imd->color_profile_screen == 0)
373 screen_type = COLOR_PROFILE_SRGB;
380 imd->color_profile_from_image = COLOR_PROFILE_NONE;
382 if (imd->color_profile_use_image && exif)
384 profile = exif_get_color_profile(exif, &profile_len);
388 gchar *interop_index;
390 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
391 if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
392 interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
396 input_type = COLOR_PROFILE_SRGB;
398 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
400 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
402 if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
404 input_type = COLOR_PROFILE_ADOBERGB;
406 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
408 if (debug) printf("Found EXIF ColorSpace of AdobeRGB\n");
411 g_free(interop_index);
417 if (debug) printf("Found embedded color profile\n");
418 imd->color_profile_from_image = COLOR_PROFILE_MEM;
420 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
421 profile, profile_len,
422 screen_type, screen_file);
427 cm = color_man_new(run_in_bg ? imd : NULL, NULL,
428 input_type, input_file,
429 screen_type, screen_file);
437 cm->incremental_sync = TRUE;
440 imd->cm = (gpointer)cm;
442 if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd);
450 static void image_post_process(ImageWindow *imd, gint clamp)
453 ExifData *exif = NULL;
455 if (!image_get_pixbuf(imd)) return;
457 if (debug) printf("%s image postprocess: %s\n", get_exec_time(), imd->image_fd->name);
459 if (options->image.exif_rotate_enable ||
460 (imd->color_profile_enable && imd->color_profile_use_image) )
462 exif = exif_read_fd(imd->image_fd);
464 if (options->image.exif_rotate_enable && exif)
468 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
472 /* see http://jpegclub.org/exif_orientation.html
475 888888 888888 88 88 8888888888 88 88 8888888888
476 88 88 88 88 88 88 88 88 88 88 88 88
477 8888 8888 8888 8888 88 8888888888 8888888888 88
483 case EXIF_ORIENTATION_TOP_LEFT:
484 /* normal -- nothing to do */
487 case EXIF_ORIENTATION_TOP_RIGHT:
489 imd->delay_alter_type = ALTER_MIRROR;
491 case EXIF_ORIENTATION_BOTTOM_RIGHT:
493 imd->delay_alter_type = ALTER_ROTATE_180;
495 case EXIF_ORIENTATION_BOTTOM_LEFT:
497 imd->delay_alter_type = ALTER_FLIP;
499 case EXIF_ORIENTATION_LEFT_TOP:
500 /* not implemented -- too wacky to fix in one step */
503 case EXIF_ORIENTATION_RIGHT_TOP:
504 /* rotated -90 (270) */
505 imd->delay_alter_type = ALTER_ROTATE_90;
507 case EXIF_ORIENTATION_RIGHT_BOTTOM:
508 /* not implemented -- too wacky to fix in one step */
511 case EXIF_ORIENTATION_LEFT_BOTTOM:
513 imd->delay_alter_type = ALTER_ROTATE_90_CC;
516 /* The other values are out of range */
521 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
524 if (imd->color_profile_enable)
526 if (!image_post_process_color(imd, 0, exif, TRUE))
528 /* fixme: note error to user */
529 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
534 if (!imd->cm) image_post_process_alter(imd, clamp);
540 static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data)
542 ImageWindow *imd = (ImageWindow *)data;
543 if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h);
544 if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h);
548 void image_alter(ImageWindow *imd, AlterType type)
551 const static gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1};
552 const static gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3};
553 const static gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6};
554 const static gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7};
555 const static gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5};
558 if (!imd || !imd->pr) return;
560 if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
564 case ALTER_ROTATE_90:
565 imd->orientation = rotate_90[imd->orientation];
567 case ALTER_ROTATE_90_CC:
568 imd->orientation = rotate_90_cc[imd->orientation];
570 case ALTER_ROTATE_180:
571 imd->orientation = rotate_180[imd->orientation];
574 imd->orientation = mirror[imd->orientation];
577 imd->orientation = flip[imd->orientation];
579 case ALTER_DESATURATE:
580 imd->desaturate = !imd->desaturate;
583 imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1;
584 imd->desaturate = FALSE;
591 if (type != ALTER_NONE && type != ALTER_DESATURATE)
593 if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd);
594 imd->image_fd->user_orientation = imd->orientation;
598 if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd);
599 imd->image_fd->user_orientation = 0;
602 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
603 if (imd->cm || imd->desaturate)
604 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
606 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
611 *-------------------------------------------------------------------
612 * read ahead (prebuffer)
613 *-------------------------------------------------------------------
616 static void image_read_ahead_cancel(ImageWindow *imd)
618 if (debug) printf("%s read ahead cancelled for :%s\n", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
620 image_loader_free(imd->read_ahead_il);
621 imd->read_ahead_il = NULL;
623 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
624 imd->read_ahead_pixbuf = NULL;
626 file_data_unref(imd->read_ahead_fd);
627 imd->read_ahead_fd = NULL;
630 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
632 ImageWindow *imd = data;
634 if (debug) printf("%s read ahead done for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
636 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
637 if (imd->read_ahead_pixbuf)
639 g_object_ref(imd->read_ahead_pixbuf);
643 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
645 image_loader_free(imd->read_ahead_il);
646 imd->read_ahead_il = NULL;
648 image_complete_util(imd, TRUE);
651 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
653 /* we even treat errors as success, maybe at least some of the file was ok */
654 image_read_ahead_done_cb(il, data);
657 static void image_read_ahead_start(ImageWindow *imd)
659 /* already started ? */
660 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
662 /* still loading ?, do later */
663 if (imd->il /*|| imd->cm*/) return;
665 if (debug) printf("%s read ahead started for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
667 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
669 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
670 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
672 image_read_ahead_cancel(imd);
673 image_complete_util(imd, TRUE);
677 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
679 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
681 image_read_ahead_cancel(imd);
683 imd->read_ahead_fd = file_data_ref(fd);
685 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
687 image_read_ahead_start(imd);
691 *-------------------------------------------------------------------
693 *-------------------------------------------------------------------
696 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
698 file_data_unref(imd->prev_fd);
699 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
703 imd->prev_fd = file_data_ref(fd);
705 g_object_ref(pixbuf);
706 imd->prev_pixbuf = pixbuf;
707 imd->prev_color_row = color_row;
712 imd->prev_pixbuf = NULL;
713 imd->prev_color_row = -1;
716 if (debug) printf("%s post buffer set: %s\n", get_exec_time(), fd ? fd->path : "null");
719 static gint image_post_buffer_get(ImageWindow *imd)
723 if (imd->prev_pixbuf &&
724 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
726 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
727 if (imd->prev_color_row >= 0)
729 ExifData *exif = NULL;
731 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
732 // image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
742 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
743 imd->prev_pixbuf = NULL;
745 file_data_unref(imd->prev_fd);
752 *-------------------------------------------------------------------
754 *-------------------------------------------------------------------
757 static void image_load_pixbuf_ready(ImageWindow *imd)
759 if (image_get_pixbuf(imd) || !imd->il) return;
761 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
764 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
766 ImageWindow *imd = data;
769 pr = (PixbufRenderer *)imd->pr;
771 if (imd->delay_flip &&
772 pr->pixbuf != image_loader_get_pixbuf(il))
777 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
779 pixbuf_renderer_area_changed(pr, x, y, w, h);
782 static void image_load_done_cb(ImageLoader *il, gpointer data)
784 ImageWindow *imd = data;
786 if (debug) printf ("%s image done\n", get_exec_time());
788 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
789 image_state_unset(imd, IMAGE_STATE_LOADING);
791 if (imd->delay_flip &&
792 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
794 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
795 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
798 image_loader_free(imd->il);
801 image_post_process(imd, TRUE);
803 image_read_ahead_start(imd);
806 static void image_load_error_cb(ImageLoader *il, gpointer data)
808 if (debug) printf ("%s image error\n", get_exec_time());
810 /* even on error handle it like it was done,
811 * since we have a pixbuf with _something_ */
813 image_load_done_cb(il, data);
816 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
817 static void image_load_buffer_throttle(ImageLoader *il)
819 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
821 /* Larger image files usually have larger chunks of data per pixel...
822 * So increase the buffer read size so that the rendering chunks called
826 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
830 /* this read ahead is located here merely for the callbacks, above */
832 static gint image_read_ahead_check(ImageWindow *imd)
834 if (!imd->read_ahead_fd) return FALSE;
835 if (imd->il) return FALSE;
837 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
839 image_read_ahead_cancel(imd);
843 if (imd->read_ahead_il)
845 imd->il = imd->read_ahead_il;
846 imd->read_ahead_il = NULL;
848 /* override the old signals */
849 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
850 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
851 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
853 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
854 image_load_buffer_throttle(imd->il);
857 /* do this one directly (probably should add a set func) */
858 imd->il->func_done = image_load_done_cb;
860 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
861 image_state_set(imd, IMAGE_STATE_LOADING);
863 if (!imd->delay_flip)
865 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
868 image_read_ahead_cancel(imd);
871 else if (imd->read_ahead_pixbuf)
873 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
874 g_object_unref(imd->read_ahead_pixbuf);
875 imd->read_ahead_pixbuf = NULL;
877 image_read_ahead_cancel(imd);
879 image_post_process(imd, FALSE);
883 image_read_ahead_cancel(imd);
887 static gint image_load_begin(ImageWindow *imd, FileData *fd)
889 if (debug) printf ("%s image begin \n", get_exec_time());
891 if (imd->il) return FALSE;
893 imd->completed = FALSE;
894 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
896 if (image_post_buffer_get(imd))
898 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
902 if (image_read_ahead_check(imd))
904 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
908 if (!imd->delay_flip && image_get_pixbuf(imd))
912 pr = PIXBUF_RENDERER(imd->pr);
913 if (pr->pixbuf) g_object_unref(pr->pixbuf);
917 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
919 imd->il = image_loader_new(fd);
921 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
922 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
923 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
925 if (!image_loader_start(imd->il, image_load_done_cb, imd))
927 if (debug) printf("image start error\n");
929 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
931 image_loader_free(imd->il);
934 image_complete_util(imd, FALSE);
939 image_state_set(imd, IMAGE_STATE_LOADING);
941 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
942 image_load_buffer_throttle(imd->il);
945 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
950 static void image_reset(ImageWindow *imd)
952 /* stops anything currently being done */
954 if (debug) printf("%s image reset\n", get_exec_time());
956 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
958 image_loader_free(imd->il);
961 color_man_free((ColorMan *)imd->cm);
964 imd->delay_alter_type = ALTER_NONE;
966 image_state_set(imd, IMAGE_STATE_NONE);
970 *-------------------------------------------------------------------
972 *-------------------------------------------------------------------
975 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
979 if (imd->image_fd && isfile(imd->image_fd->path))
983 pr = PIXBUF_RENDERER(imd->pr);
984 pr->zoom = zoom; /* store the zoom, needed by the loader */
986 if (image_load_begin(imd, imd->image_fd))
988 imd->unknown = FALSE;
994 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
995 image_change_pixbuf(imd, pixbuf, zoom);
996 g_object_unref(pixbuf);
1000 imd->size = filesize(imd->image_fd->path);
1001 imd->mtime = filetime(imd->image_fd->path);
1009 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
1010 image_change_pixbuf(imd, pixbuf, zoom);
1011 g_object_unref(pixbuf);
1012 imd->mtime = filetime(imd->image_fd->path);
1016 image_change_pixbuf(imd, NULL, zoom);
1019 imd->unknown = TRUE;
1023 image_update_util(imd);
1026 static void image_change_real(ImageWindow *imd, FileData *fd,
1027 CollectionData *cd, CollectInfo *info, gdouble zoom)
1030 GdkPixbuf *prev_pixbuf = NULL;
1031 FileData *prev_fd = NULL;
1032 gint prev_clear = FALSE;
1033 gint prev_color_row = -1;
1035 imd->collection = cd;
1036 imd->collection_info = info;
1038 pixbuf = image_get_pixbuf(imd);
1040 if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1044 /* current image is not finished */
1049 prev_fd = file_data_ref(imd->image_fd);
1050 prev_pixbuf = pixbuf;
1051 g_object_ref(prev_pixbuf);
1057 cm = (ColorMan *)imd->cm;
1058 prev_color_row = cm->row;
1063 file_data_unref(imd->image_fd);
1064 imd->image_fd = file_data_ref(fd);
1066 image_change_complete(imd, zoom, TRUE);
1070 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
1071 file_data_unref(prev_fd);
1072 g_object_unref(prev_pixbuf);
1074 else if (prev_clear)
1076 image_post_buffer_set(imd, NULL, NULL, -1);
1079 image_update_title(imd);
1080 image_state_set(imd, IMAGE_STATE_IMAGE);
1084 *-------------------------------------------------------------------
1086 *-------------------------------------------------------------------
1089 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1093 widget = imd->widget;
1094 if (!widget->window) return;
1098 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
1099 area, widget, "image_window",
1100 widget->allocation.x, widget->allocation.y,
1101 widget->allocation.width - 1, widget->allocation.height - 1);
1105 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1106 area, widget, "image_window",
1107 widget->allocation.x, widget->allocation.y,
1108 widget->allocation.width - 1, widget->allocation.height - 1);
1112 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1114 ImageWindow *imd = data;
1116 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1120 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1122 ImageWindow *imd = data;
1124 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1125 image_focus_paint(imd, TRUE, NULL);
1130 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1132 ImageWindow *imd = data;
1134 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1135 image_focus_paint(imd, FALSE, NULL);
1140 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1141 gint relative, gint always)
1143 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1146 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1148 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1151 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1153 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1156 void image_overlay_remove(ImageWindow *imd, gint id)
1158 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1161 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1163 ImageWindow *imd = data;
1165 if (imd->func_scroll &&
1166 event && event->type == GDK_SCROLL)
1168 imd->func_scroll(imd, event->direction, event->time,
1169 event->x, event->y, event->state, imd->data_scroll);
1177 *-------------------------------------------------------------------
1179 *-------------------------------------------------------------------
1182 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1183 const gchar *title, const gchar *title_right, gint show_zoom)
1185 imd->top_window = window;
1187 imd->title = g_strdup(title);
1188 g_free(imd->title_right);
1189 imd->title_right = g_strdup(title_right);
1190 imd->title_show_zoom = show_zoom;
1192 if (!options->image.fit_window_to_image) window = NULL;
1194 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1196 image_update_title(imd);
1199 void image_set_update_func(ImageWindow *imd,
1200 void (*func)(ImageWindow *imd, gpointer data),
1203 imd->func_update = func;
1204 imd->data_update = data;
1207 void image_set_complete_func(ImageWindow *imd,
1208 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1211 imd->func_complete = func;
1212 imd->data_complete = data;
1215 void image_set_state_func(ImageWindow *imd,
1216 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1219 imd->func_state = func;
1220 imd->data_state = data;
1224 void image_set_button_func(ImageWindow *imd,
1225 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1228 imd->func_button = func;
1229 imd->data_button = data;
1232 void image_set_drag_func(ImageWindow *imd,
1233 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1236 imd->func_drag = func;
1237 imd->data_drag = data;
1240 void image_set_scroll_func(ImageWindow *imd,
1241 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1244 imd->func_scroll = func;
1245 imd->data_scroll = data;
1248 void image_set_scroll_notify_func(ImageWindow *imd,
1249 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1252 imd->func_scroll_notify = func;
1253 imd->data_scroll_notify = data;
1258 const gchar *image_get_path(ImageWindow *imd)
1260 if (imd->image_fd == NULL) return NULL;
1261 return imd->image_fd->path;
1264 const gchar *image_get_name(ImageWindow *imd)
1266 if (imd->image_fd == NULL) return NULL;
1267 return imd->image_fd->name;
1270 FileData *image_get_fd(ImageWindow *imd)
1272 return imd->image_fd;
1275 /* merely changes path string, does not change the image! */
1276 void image_set_fd(ImageWindow *imd, FileData *fd)
1278 file_data_unref(imd->image_fd);
1279 imd->image_fd = file_data_ref(fd);
1281 image_update_title(imd);
1282 image_state_set(imd, IMAGE_STATE_IMAGE);
1285 /* load a new image */
1287 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1289 if (imd->image_fd == fd) return;
1291 image_change_real(imd, fd, NULL, NULL, zoom);
1294 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1296 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1299 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1302 ExifData *exif = NULL;
1303 gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
1304 gint read_exif_for_orientation = FALSE;
1306 if (imd->image_fd && imd->image_fd->user_orientation)
1307 imd->orientation = imd->image_fd->user_orientation;
1308 else if (options->image.exif_rotate_enable)
1309 read_exif_for_orientation = TRUE;
1311 if (read_exif_for_color_profile || read_exif_for_orientation)
1315 exif = exif_read_fd(imd->image_fd);
1317 if (exif && read_exif_for_orientation)
1319 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1320 imd->orientation = orientation;
1322 imd->orientation = 1;
1323 imd->image_fd->exif_orientation = imd->orientation;
1327 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1330 color_man_free(imd->cm);
1334 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1335 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1337 if (imd->color_profile_enable)
1339 if (!image_post_process_color(imd, 0, exif, FALSE))
1341 /* fixme: note error to user */
1342 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1348 if (imd->cm || imd->desaturate)
1349 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1351 image_state_set(imd, IMAGE_STATE_IMAGE);
1354 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1356 if (!cd || !info || !g_list_find(cd->list, info)) return;
1358 image_change_real(imd, info->fd, cd, info, zoom);
1361 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1363 if (collection_to_number(imd->collection) >= 0)
1365 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1367 if (info) *info = imd->collection_info;
1371 if (info) *info = NULL;
1373 return imd->collection;
1376 if (info) *info = NULL;
1380 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1382 /* change data for the callbacks directly */
1384 il->data_area_ready = data;
1385 il->data_error = data;
1386 il->data_done = data;
1387 il->data_percent = data;
1390 /* this is more like a move function
1391 * it moves most data from source to imd
1393 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1395 if (imd == source) return;
1397 imd->unknown = source->unknown;
1399 imd->collection = source->collection;
1400 imd->collection_info = source->collection_info;
1401 imd->size = source->size;
1402 imd->mtime = source->mtime;
1404 image_set_fd(imd, image_get_fd(source));
1406 image_loader_free(imd->il);
1411 imd->il = source->il;
1414 image_loader_sync_data(imd->il, imd);
1416 imd->delay_alter_type = source->delay_alter_type;
1417 source->delay_alter_type = ALTER_NONE;
1420 imd->color_profile_enable = source->color_profile_enable;
1421 imd->color_profile_input = source->color_profile_input;
1422 imd->color_profile_screen = source->color_profile_screen;
1423 imd->color_profile_use_image = source->color_profile_use_image;
1424 color_man_free((ColorMan *)imd->cm);
1430 imd->cm = source->cm;
1433 cm = (ColorMan *)imd->cm;
1435 cm->func_done_data = imd;
1438 image_loader_free(imd->read_ahead_il);
1439 imd->read_ahead_il = source->read_ahead_il;
1440 source->read_ahead_il = NULL;
1441 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1443 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1444 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1445 source->read_ahead_pixbuf = NULL;
1447 file_data_unref(imd->read_ahead_fd);
1448 imd->read_ahead_fd = source->read_ahead_fd;
1449 source->read_ahead_fd = NULL;
1451 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1452 imd->prev_pixbuf = source->prev_pixbuf;
1453 source->prev_pixbuf = NULL;
1454 imd->prev_color_row = source->prev_color_row;
1455 source->prev_color_row = -1;
1457 file_data_unref(imd->prev_fd);
1458 imd->prev_fd = source->prev_fd;
1459 source->prev_fd = NULL;
1461 imd->completed = source->completed;
1462 imd->state = source->state;
1463 source->state = IMAGE_STATE_NONE;
1465 imd->orientation = source->orientation;
1466 imd->desaturate = source->desaturate;
1468 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1470 if (imd->cm || imd->desaturate)
1471 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1473 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1479 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1481 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1484 void image_reload(ImageWindow *imd)
1486 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1488 image_change_complete(imd, image_zoom_get(imd), FALSE);
1491 void image_scroll(ImageWindow *imd, gint x, gint y)
1493 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1496 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1497 gdouble x_align, gdouble y_align)
1499 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1502 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1504 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1507 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1509 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1514 void image_alter(ImageWindow *imd, AlterType type)
1516 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1518 if (imd->il || imd->cm)
1520 /* still loading, wait till done */
1521 imd->delay_alter_type = type;
1522 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1524 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1526 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1531 image_alter_real(imd, type, TRUE);
1535 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1537 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1540 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1542 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1545 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1547 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1550 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1552 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1555 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1561 pr = (PixbufRenderer *)imd->pr;
1563 if (!pixbuf_renderer_get_pixbuf(pr) ||
1564 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1568 zoom = (gdouble)pr->window_height / height;
1572 zoom = (gdouble)pr->window_width / width;
1577 zoom = 0.0 - 1.0 / zoom;
1580 pixbuf_renderer_zoom_set(pr, zoom);
1583 gdouble image_zoom_get(ImageWindow *imd)
1585 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1588 gdouble image_zoom_get_real(ImageWindow *imd)
1590 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1593 gchar *image_zoom_get_as_text(ImageWindow *imd)
1601 gchar *approx = " ";
1603 zoom = image_zoom_get(imd);
1604 scale = image_zoom_get_real(imd);
1610 else if (zoom < 0.0)
1614 else if (zoom == 0.0 && scale != 0.0)
1627 if (rint(l) != l) pl = 1;
1628 if (rint(r) != r) pr = 1;
1630 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1633 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1637 if (mode == ZOOM_RESET_ORIGINAL)
1641 else if (mode == ZOOM_RESET_FIT_WINDOW)
1649 zoom = image_zoom_get(imd);
1662 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1664 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1668 image_read_ahead_set(imd, fd);
1672 image_read_ahead_cancel(imd);
1676 static gint image_auto_refresh_cb(gpointer data)
1678 ImageWindow *imd = data;
1681 if (!imd || !image_get_pixbuf(imd) ||
1682 imd->il || !imd->image_fd ||
1683 !options->update_on_time_change) return TRUE;
1685 newtime = filetime(imd->image_fd->path);
1686 if (newtime > 0 && newtime != imd->mtime)
1688 imd->mtime = newtime;
1695 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1697 void image_auto_refresh(ImageWindow *imd, gint interval)
1700 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1702 if (imd->auto_refresh_id > -1)
1704 g_source_remove(imd->auto_refresh_id);
1705 imd->auto_refresh_id = -1;
1706 imd->auto_refresh_interval = -1;
1709 if (interval < 0) return;
1711 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1713 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1714 imd->auto_refresh_interval = interval;
1717 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1719 imd->top_window_sync = allow_sync;
1721 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1724 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1726 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1729 void image_color_profile_set(ImageWindow *imd,
1730 gint input_type, gint screen_type,
1735 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1736 screen_type < 0 || screen_type > 1)
1741 imd->color_profile_input = input_type;
1742 imd->color_profile_screen = screen_type;
1743 imd->color_profile_use_image = use_image;
1746 gint image_color_profile_get(ImageWindow *imd,
1747 gint *input_type, gint *screen_type,
1750 if (!imd) return FALSE;
1752 if (input_type) *input_type = imd->color_profile_input;
1753 if (screen_type) *screen_type = imd->color_profile_screen;
1754 if (use_image) *use_image = imd->color_profile_use_image;
1759 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1763 if (imd->color_profile_enable == enable) return;
1765 imd->color_profile_enable = enable;
1768 gint image_color_profile_get_use(ImageWindow *imd)
1770 if (!imd) return FALSE;
1772 return imd->color_profile_enable;
1775 gint image_color_profile_get_from_image(ImageWindow *imd)
1777 if (!imd) return FALSE;
1779 return imd->color_profile_from_image;
1782 void image_set_delay_flip(ImageWindow *imd, gint delay)
1785 imd->delay_flip == delay) return;
1787 imd->delay_flip = delay;
1789 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1791 if (!imd->delay_flip && imd->il)
1795 pr = PIXBUF_RENDERER(imd->pr);
1796 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1799 image_load_pixbuf_ready(imd);
1803 void image_to_root_window(ImageWindow *imd, gint scaled)
1806 GdkWindow *rootwindow;
1814 pixbuf = image_get_pixbuf(imd);
1815 if (!pixbuf) return;
1817 screen = gtk_widget_get_screen(imd->widget);
1818 rootwindow = gdk_screen_get_root_window(screen);
1819 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1823 width = gdk_screen_width();
1824 height = gdk_screen_height();
1828 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1831 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1833 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1834 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1835 gdk_window_clear(rootwindow);
1837 g_object_unref(pixmap);
1842 void image_select(ImageWindow *imd, gboolean select)
1848 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1849 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1852 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1858 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1864 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1865 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1869 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1870 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1876 *-------------------------------------------------------------------
1878 *-------------------------------------------------------------------
1881 static void image_options_set(ImageWindow *imd)
1883 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1884 "zoom_2pass", options->image.zoom_2pass,
1885 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1886 "dither_quality", options->image.dither_quality,
1887 "scroll_reset", options->image.scroll_reset_method,
1888 "cache_display", options->image.tile_cache_max,
1889 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1890 "window_limit", options->image.limit_window_size,
1891 "window_limit_value", options->image.max_window_size,
1892 "autofit_limit", options->image.limit_autofit_size,
1893 "autofit_limit_value", options->image.max_autofit_size,
1897 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1900 void image_options_sync(void)
1912 image_options_set(imd);
1917 *-------------------------------------------------------------------
1919 *-------------------------------------------------------------------
1922 static void image_free(ImageWindow *imd)
1924 image_list = g_list_remove(image_list, imd);
1928 image_read_ahead_cancel(imd);
1929 image_post_buffer_set(imd, NULL, NULL, -1);
1930 image_auto_refresh(imd, -1);
1932 file_data_unref(imd->image_fd);
1934 g_free(imd->title_right);
1939 static void image_destroy_cb(GtkObject *widget, gpointer data)
1941 ImageWindow *imd = data;
1945 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1947 gtk_paint_flat_box(widget->style,
1950 GTK_FRAME (widget)->shadow_type,
1954 widget->allocation.x + 3, widget->allocation.y + 3,
1955 widget->allocation.width - 6, widget->allocation.height - 6);
1962 void image_set_frame(ImageWindow *imd, gboolean frame)
1966 if (frame == imd->has_frame) return;
1968 gtk_widget_hide(imd->pr);
1972 imd->frame = gtk_frame_new(NULL);
1973 gtk_widget_ref(imd->pr);
1974 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1975 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1976 gtk_widget_unref(imd->pr);
1977 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1978 G_CALLBACK (selectable_frame_expose_cb), NULL);
1980 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1981 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1982 G_CALLBACK(image_focus_in_cb), imd);
1983 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1984 G_CALLBACK(image_focus_out_cb), imd);
1986 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1987 G_CALLBACK(image_focus_expose), imd);
1990 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1991 gtk_widget_show(imd->frame);
1995 gtk_widget_ref(imd->pr);
1998 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1999 gtk_widget_destroy(imd->frame);
2002 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2003 gtk_widget_unref(imd->pr);
2006 gtk_widget_show(imd->pr);
2008 imd->has_frame = frame;
2011 ImageWindow *image_new(gint frame)
2015 imd = g_new0(ImageWindow, 1);
2017 imd->top_window = NULL;
2019 imd->title_right = NULL;
2020 imd->title_show_zoom = FALSE;
2022 imd->unknown = TRUE;
2024 imd->has_frame = -1; /* not initialized; for image_set_frame */
2025 imd->top_window_sync = FALSE;
2027 imd->delay_alter_type = ALTER_NONE;
2029 imd->read_ahead_il = NULL;
2030 imd->read_ahead_pixbuf = NULL;
2031 imd->read_ahead_fd = NULL;
2033 imd->completed = FALSE;
2034 imd->state = IMAGE_STATE_NONE;
2036 imd->color_profile_enable = FALSE;
2037 imd->color_profile_input = 0;
2038 imd->color_profile_screen = 0;
2039 imd->color_profile_use_image = FALSE;
2040 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2042 imd->auto_refresh_id = -1;
2043 imd->auto_refresh_interval = -1;
2045 imd->delay_flip = FALSE;
2047 imd->func_update = NULL;
2048 imd->func_complete = NULL;
2049 imd->func_tile_request = NULL;
2050 imd->func_tile_dispose = NULL;
2052 imd->func_button = NULL;
2053 imd->func_scroll = NULL;
2055 imd->orientation = 1;
2057 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2059 image_options_set(imd);
2062 imd->widget = gtk_vbox_new(0, 0);
2064 image_set_frame(imd, frame);
2066 image_set_selectable(imd, 0);
2068 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2069 G_CALLBACK(image_click_cb), imd);
2070 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2071 G_CALLBACK(image_scroll_notify_cb), imd);
2073 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2074 G_CALLBACK(image_scroll_cb), imd);
2076 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2077 G_CALLBACK(image_destroy_cb), imd);
2079 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2080 G_CALLBACK(image_zoom_cb), imd);
2081 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2082 G_CALLBACK(image_render_complete_cb), imd);
2083 g_signal_connect(G_OBJECT(imd->pr), "drag",
2084 G_CALLBACK(image_drag_cb), imd);
2086 image_list = g_list_append(image_list, imd);