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 ExifItem *item = NULL;
340 if (imd->cm) return FALSE;
342 if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
343 imd->color_profile_input < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
347 n = imd->color_profile_input - COLOR_PROFILE_FILE;
348 if (!options->color_profile.input_file[n]) return FALSE;
350 input_type = COLOR_PROFILE_FILE;
351 input_file = options->color_profile.input_file[n];
353 else if (imd->color_profile_input >= COLOR_PROFILE_SRGB &&
354 imd->color_profile_input < COLOR_PROFILE_FILE)
356 input_type = imd->color_profile_input;
364 if (imd->color_profile_screen == 1 &&
365 options->color_profile.screen_file)
367 screen_type = COLOR_PROFILE_FILE;
368 screen_file = options->color_profile.screen_file;
370 else if (imd->color_profile_screen == 0)
372 screen_type = COLOR_PROFILE_SRGB;
379 imd->color_profile_from_image = COLOR_PROFILE_NONE;
381 if (imd->color_profile_use_image && exif)
383 item = exif_get_item(exif, "Exif.Image.InterColorProfile");
387 gchar *interop_index;
389 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
390 if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
391 interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
395 input_type = COLOR_PROFILE_SRGB;
397 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
399 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
401 if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
403 input_type = COLOR_PROFILE_ADOBERGB;
405 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
407 if (debug) printf("Found EXIF ColorSpace of AdobeRGB\n");
410 g_free(interop_index);
414 if (item && exif_item_get_format_id(item) == EXIF_FORMAT_UNDEFINED)
418 if (debug) printf("Found embedded color profile\n");
419 imd->color_profile_from_image = COLOR_PROFILE_MEM;
421 data = (unsigned char *) exif_item_get_data(item, &data_len);
423 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
425 screen_type, screen_file);
430 cm = color_man_new(run_in_bg ? imd : NULL, NULL,
431 input_type, input_file,
432 screen_type, screen_file);
440 cm->incremental_sync = TRUE;
443 imd->cm = (gpointer)cm;
445 if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd);
453 static void image_post_process(ImageWindow *imd, gint clamp)
456 ExifData *exif = NULL;
458 if (!image_get_pixbuf(imd)) return;
460 if (debug) printf("%s image postprocess: %s\n", get_exec_time(), imd->image_fd->name);
462 if (options->image.exif_rotate_enable ||
463 (imd->color_profile_enable && imd->color_profile_use_image) )
465 exif = exif_read_fd(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image));
467 if (options->image.exif_rotate_enable && exif)
471 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
475 /* see http://jpegclub.org/exif_orientation.html
478 888888 888888 88 88 8888888888 88 88 8888888888
479 88 88 88 88 88 88 88 88 88 88 88 88
480 8888 8888 8888 8888 88 8888888888 8888888888 88
486 case EXIF_ORIENTATION_TOP_LEFT:
487 /* normal -- nothing to do */
490 case EXIF_ORIENTATION_TOP_RIGHT:
492 imd->delay_alter_type = ALTER_MIRROR;
494 case EXIF_ORIENTATION_BOTTOM_RIGHT:
496 imd->delay_alter_type = ALTER_ROTATE_180;
498 case EXIF_ORIENTATION_BOTTOM_LEFT:
500 imd->delay_alter_type = ALTER_FLIP;
502 case EXIF_ORIENTATION_LEFT_TOP:
503 /* not implemented -- too wacky to fix in one step */
506 case EXIF_ORIENTATION_RIGHT_TOP:
507 /* rotated -90 (270) */
508 imd->delay_alter_type = ALTER_ROTATE_90;
510 case EXIF_ORIENTATION_RIGHT_BOTTOM:
511 /* not implemented -- too wacky to fix in one step */
514 case EXIF_ORIENTATION_LEFT_BOTTOM:
516 imd->delay_alter_type = ALTER_ROTATE_90_CC;
519 /* The other values are out of range */
524 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
527 if (imd->color_profile_enable)
529 if (!image_post_process_color(imd, 0, exif, TRUE))
531 /* fixme: note error to user */
532 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
537 if (!imd->cm) image_post_process_alter(imd, clamp);
543 static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data)
545 ImageWindow *imd = (ImageWindow *)data;
546 if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h);
547 if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h);
551 void image_alter(ImageWindow *imd, AlterType type)
554 const static gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1};
555 const static gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3};
556 const static gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6};
557 const static gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7};
558 const static gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5};
561 if (!imd || !imd->pr) return;
563 if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
567 case ALTER_ROTATE_90:
568 imd->orientation = rotate_90[imd->orientation];
570 case ALTER_ROTATE_90_CC:
571 imd->orientation = rotate_90_cc[imd->orientation];
573 case ALTER_ROTATE_180:
574 imd->orientation = rotate_180[imd->orientation];
577 imd->orientation = mirror[imd->orientation];
580 imd->orientation = flip[imd->orientation];
582 case ALTER_DESATURATE:
583 imd->desaturate = !imd->desaturate;
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, TRUE);
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, read_exif_for_color_profile);
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;
1326 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1329 color_man_free(imd->cm);
1333 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1334 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1336 if (imd->color_profile_enable)
1338 if (!image_post_process_color(imd, 0, exif, FALSE))
1340 /* fixme: note error to user */
1341 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1347 if (imd->cm || imd->desaturate)
1348 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1350 image_state_set(imd, IMAGE_STATE_IMAGE);
1353 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1355 if (!cd || !info || !g_list_find(cd->list, info)) return;
1357 image_change_real(imd, info->fd, cd, info, zoom);
1360 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1362 if (collection_to_number(imd->collection) >= 0)
1364 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1366 if (info) *info = imd->collection_info;
1370 if (info) *info = NULL;
1372 return imd->collection;
1375 if (info) *info = NULL;
1379 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1381 /* change data for the callbacks directly */
1383 il->data_area_ready = data;
1384 il->data_error = data;
1385 il->data_done = data;
1386 il->data_percent = data;
1389 /* this is more like a move function
1390 * it moves most data from source to imd
1392 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1394 if (imd == source) return;
1396 imd->unknown = source->unknown;
1398 imd->collection = source->collection;
1399 imd->collection_info = source->collection_info;
1400 imd->size = source->size;
1401 imd->mtime = source->mtime;
1403 image_set_fd(imd, image_get_fd(source));
1405 image_loader_free(imd->il);
1410 imd->il = source->il;
1413 image_loader_sync_data(imd->il, imd);
1415 imd->delay_alter_type = source->delay_alter_type;
1416 source->delay_alter_type = ALTER_NONE;
1419 imd->color_profile_enable = source->color_profile_enable;
1420 imd->color_profile_input = source->color_profile_input;
1421 imd->color_profile_screen = source->color_profile_screen;
1422 imd->color_profile_use_image = source->color_profile_use_image;
1423 color_man_free((ColorMan *)imd->cm);
1429 imd->cm = source->cm;
1432 cm = (ColorMan *)imd->cm;
1434 cm->func_done_data = imd;
1437 image_loader_free(imd->read_ahead_il);
1438 imd->read_ahead_il = source->read_ahead_il;
1439 source->read_ahead_il = NULL;
1440 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1442 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1443 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1444 source->read_ahead_pixbuf = NULL;
1446 file_data_unref(imd->read_ahead_fd);
1447 imd->read_ahead_fd = source->read_ahead_fd;
1448 source->read_ahead_fd = NULL;
1450 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1451 imd->prev_pixbuf = source->prev_pixbuf;
1452 source->prev_pixbuf = NULL;
1453 imd->prev_color_row = source->prev_color_row;
1454 source->prev_color_row = -1;
1456 file_data_unref(imd->prev_fd);
1457 imd->prev_fd = source->prev_fd;
1458 source->prev_fd = NULL;
1460 imd->completed = source->completed;
1461 imd->state = source->state;
1462 source->state = IMAGE_STATE_NONE;
1464 imd->orientation = source->orientation;
1465 imd->desaturate = source->desaturate;
1467 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1469 if (imd->cm || imd->desaturate)
1470 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1472 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1478 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1480 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1483 void image_reload(ImageWindow *imd)
1485 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1487 image_change_complete(imd, image_zoom_get(imd), FALSE);
1490 void image_scroll(ImageWindow *imd, gint x, gint y)
1492 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1495 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1496 gdouble x_align, gdouble y_align)
1498 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1501 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1503 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1506 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1508 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1513 void image_alter(ImageWindow *imd, AlterType type)
1515 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1517 if (imd->il || imd->cm)
1519 /* still loading, wait till done */
1520 imd->delay_alter_type = type;
1521 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1523 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1525 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1530 image_alter_real(imd, type, TRUE);
1534 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1536 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1539 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1541 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1544 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1546 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1549 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1551 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1554 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1560 pr = (PixbufRenderer *)imd->pr;
1562 if (!pixbuf_renderer_get_pixbuf(pr) ||
1563 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1567 zoom = (gdouble)pr->window_height / height;
1571 zoom = (gdouble)pr->window_width / width;
1576 zoom = 0.0 - 1.0 / zoom;
1579 pixbuf_renderer_zoom_set(pr, zoom);
1582 gdouble image_zoom_get(ImageWindow *imd)
1584 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1587 gdouble image_zoom_get_real(ImageWindow *imd)
1589 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1592 gchar *image_zoom_get_as_text(ImageWindow *imd)
1600 gchar *approx = " ";
1602 zoom = image_zoom_get(imd);
1603 scale = image_zoom_get_real(imd);
1609 else if (zoom < 0.0)
1613 else if (zoom == 0.0 && scale != 0.0)
1626 if (rint(l) != l) pl = 1;
1627 if (rint(r) != r) pr = 1;
1629 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1632 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1636 if (mode == ZOOM_RESET_ORIGINAL)
1640 else if (mode == ZOOM_RESET_FIT_WINDOW)
1648 zoom = image_zoom_get(imd);
1661 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1663 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1667 image_read_ahead_set(imd, fd);
1671 image_read_ahead_cancel(imd);
1675 static gint image_auto_refresh_cb(gpointer data)
1677 ImageWindow *imd = data;
1680 if (!imd || !image_get_pixbuf(imd) ||
1681 imd->il || !imd->image_fd ||
1682 !options->update_on_time_change) return TRUE;
1684 newtime = filetime(imd->image_fd->path);
1685 if (newtime > 0 && newtime != imd->mtime)
1687 imd->mtime = newtime;
1694 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1696 void image_auto_refresh(ImageWindow *imd, gint interval)
1699 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1701 if (imd->auto_refresh_id > -1)
1703 g_source_remove(imd->auto_refresh_id);
1704 imd->auto_refresh_id = -1;
1705 imd->auto_refresh_interval = -1;
1708 if (interval < 0) return;
1710 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1712 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1713 imd->auto_refresh_interval = interval;
1716 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1718 imd->top_window_sync = allow_sync;
1720 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1723 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1725 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1728 void image_color_profile_set(ImageWindow *imd,
1729 gint input_type, gint screen_type,
1734 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1735 screen_type < 0 || screen_type > 1)
1740 imd->color_profile_input = input_type;
1741 imd->color_profile_screen = screen_type;
1742 imd->color_profile_use_image = use_image;
1745 gint image_color_profile_get(ImageWindow *imd,
1746 gint *input_type, gint *screen_type,
1749 if (!imd) return FALSE;
1751 if (input_type) *input_type = imd->color_profile_input;
1752 if (screen_type) *screen_type = imd->color_profile_screen;
1753 if (use_image) *use_image = imd->color_profile_use_image;
1758 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1762 if (imd->color_profile_enable == enable) return;
1764 imd->color_profile_enable = enable;
1767 gint image_color_profile_get_use(ImageWindow *imd)
1769 if (!imd) return FALSE;
1771 return imd->color_profile_enable;
1774 gint image_color_profile_get_from_image(ImageWindow *imd)
1776 if (!imd) return FALSE;
1778 return imd->color_profile_from_image;
1781 void image_set_delay_flip(ImageWindow *imd, gint delay)
1784 imd->delay_flip == delay) return;
1786 imd->delay_flip = delay;
1788 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1790 if (!imd->delay_flip && imd->il)
1794 pr = PIXBUF_RENDERER(imd->pr);
1795 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1798 image_load_pixbuf_ready(imd);
1802 void image_to_root_window(ImageWindow *imd, gint scaled)
1805 GdkWindow *rootwindow;
1813 pixbuf = image_get_pixbuf(imd);
1814 if (!pixbuf) return;
1816 screen = gtk_widget_get_screen(imd->widget);
1817 rootwindow = gdk_screen_get_root_window(screen);
1818 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1822 width = gdk_screen_width();
1823 height = gdk_screen_height();
1827 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1830 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1832 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1833 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1834 gdk_window_clear(rootwindow);
1836 g_object_unref(pixmap);
1841 void image_select(ImageWindow *imd, gboolean select)
1847 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1848 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1851 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1857 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1863 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1864 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1868 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1869 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1875 *-------------------------------------------------------------------
1877 *-------------------------------------------------------------------
1880 static void image_options_set(ImageWindow *imd)
1882 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1883 "zoom_2pass", options->image.zoom_2pass,
1884 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1885 "dither_quality", options->image.dither_quality,
1886 "scroll_reset", options->image.scroll_reset_method,
1887 "cache_display", options->image.tile_cache_max,
1888 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1889 "window_limit", options->image.limit_window_size,
1890 "window_limit_value", options->image.max_window_size,
1891 "autofit_limit", options->image.limit_autofit_size,
1892 "autofit_limit_value", options->image.max_autofit_size,
1896 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1899 void image_options_sync(void)
1911 image_options_set(imd);
1916 *-------------------------------------------------------------------
1918 *-------------------------------------------------------------------
1921 static void image_free(ImageWindow *imd)
1923 image_list = g_list_remove(image_list, imd);
1927 image_read_ahead_cancel(imd);
1928 image_post_buffer_set(imd, NULL, NULL, -1);
1929 image_auto_refresh(imd, -1);
1931 file_data_unref(imd->image_fd);
1933 g_free(imd->title_right);
1938 static void image_destroy_cb(GtkObject *widget, gpointer data)
1940 ImageWindow *imd = data;
1944 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1946 gtk_paint_flat_box(widget->style,
1949 GTK_FRAME (widget)->shadow_type,
1953 widget->allocation.x + 3, widget->allocation.y + 3,
1954 widget->allocation.width - 6, widget->allocation.height - 6);
1961 void image_set_frame(ImageWindow *imd, gboolean frame)
1965 if (frame == imd->has_frame) return;
1967 gtk_widget_hide(imd->pr);
1971 imd->frame = gtk_frame_new(NULL);
1972 gtk_widget_ref(imd->pr);
1973 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1974 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1975 gtk_widget_unref(imd->pr);
1976 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1977 G_CALLBACK (selectable_frame_expose_cb), NULL);
1979 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1980 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1981 G_CALLBACK(image_focus_in_cb), imd);
1982 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1983 G_CALLBACK(image_focus_out_cb), imd);
1985 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1986 G_CALLBACK(image_focus_expose), imd);
1989 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1990 gtk_widget_show(imd->frame);
1994 gtk_widget_ref(imd->pr);
1997 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1998 gtk_widget_destroy(imd->frame);
2001 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2002 gtk_widget_unref(imd->pr);
2005 gtk_widget_show(imd->pr);
2007 imd->has_frame = frame;
2010 ImageWindow *image_new(gint frame)
2014 imd = g_new0(ImageWindow, 1);
2016 imd->top_window = NULL;
2018 imd->title_right = NULL;
2019 imd->title_show_zoom = FALSE;
2021 imd->unknown = TRUE;
2023 imd->has_frame = -1; /* not initialized; for image_set_frame */
2024 imd->top_window_sync = FALSE;
2026 imd->delay_alter_type = ALTER_NONE;
2028 imd->read_ahead_il = NULL;
2029 imd->read_ahead_pixbuf = NULL;
2030 imd->read_ahead_fd = NULL;
2032 imd->completed = FALSE;
2033 imd->state = IMAGE_STATE_NONE;
2035 imd->color_profile_enable = FALSE;
2036 imd->color_profile_input = 0;
2037 imd->color_profile_screen = 0;
2038 imd->color_profile_use_image = FALSE;
2039 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2041 imd->auto_refresh_id = -1;
2042 imd->auto_refresh_interval = -1;
2044 imd->delay_flip = FALSE;
2046 imd->func_update = NULL;
2047 imd->func_complete = NULL;
2048 imd->func_tile_request = NULL;
2049 imd->func_tile_dispose = NULL;
2051 imd->func_button = NULL;
2052 imd->func_scroll = NULL;
2054 imd->orientation = 1;
2056 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2058 image_options_set(imd);
2061 imd->widget = gtk_vbox_new(0, 0);
2063 image_set_frame(imd, frame);
2065 image_set_selectable(imd, 0);
2067 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2068 G_CALLBACK(image_click_cb), imd);
2069 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2070 G_CALLBACK(image_scroll_notify_cb), imd);
2072 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2073 G_CALLBACK(image_scroll_cb), imd);
2075 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2076 G_CALLBACK(image_destroy_cb), imd);
2078 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2079 G_CALLBACK(image_zoom_cb), imd);
2080 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2081 G_CALLBACK(image_render_complete_cb), imd);
2082 g_signal_connect(G_OBJECT(imd->pr), "drag",
2083 G_CALLBACK(image_drag_cb), imd);
2085 image_list = g_list_append(image_list, imd);