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;
590 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
591 if (imd->cm || imd->desaturate)
592 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
594 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
599 *-------------------------------------------------------------------
600 * read ahead (prebuffer)
601 *-------------------------------------------------------------------
604 static void image_read_ahead_cancel(ImageWindow *imd)
606 if (debug) printf("%s read ahead cancelled for :%s\n", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
608 image_loader_free(imd->read_ahead_il);
609 imd->read_ahead_il = NULL;
611 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
612 imd->read_ahead_pixbuf = NULL;
614 file_data_unref(imd->read_ahead_fd);
615 imd->read_ahead_fd = NULL;
618 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
620 ImageWindow *imd = data;
622 if (debug) printf("%s read ahead done for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
624 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
625 if (imd->read_ahead_pixbuf)
627 g_object_ref(imd->read_ahead_pixbuf);
631 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
633 image_loader_free(imd->read_ahead_il);
634 imd->read_ahead_il = NULL;
636 image_complete_util(imd, TRUE);
639 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
641 /* we even treat errors as success, maybe at least some of the file was ok */
642 image_read_ahead_done_cb(il, data);
645 static void image_read_ahead_start(ImageWindow *imd)
647 /* already started ? */
648 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
650 /* still loading ?, do later */
651 if (imd->il /*|| imd->cm*/) return;
653 if (debug) printf("%s read ahead started for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
655 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
657 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
658 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
660 image_read_ahead_cancel(imd);
661 image_complete_util(imd, TRUE);
665 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
667 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
669 image_read_ahead_cancel(imd);
671 imd->read_ahead_fd = file_data_ref(fd);
673 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
675 image_read_ahead_start(imd);
679 *-------------------------------------------------------------------
681 *-------------------------------------------------------------------
684 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
686 file_data_unref(imd->prev_fd);
687 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
691 imd->prev_fd = file_data_ref(fd);
693 g_object_ref(pixbuf);
694 imd->prev_pixbuf = pixbuf;
695 imd->prev_color_row = color_row;
700 imd->prev_pixbuf = NULL;
701 imd->prev_color_row = -1;
704 if (debug) printf("%s post buffer set: %s\n", get_exec_time(), fd ? fd->path : "null");
707 static gint image_post_buffer_get(ImageWindow *imd)
711 if (imd->prev_pixbuf &&
712 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
714 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
715 if (imd->prev_color_row >= 0)
717 ExifData *exif = NULL;
719 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd, TRUE);
720 // image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
730 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
731 imd->prev_pixbuf = NULL;
733 file_data_unref(imd->prev_fd);
740 *-------------------------------------------------------------------
742 *-------------------------------------------------------------------
745 static void image_load_pixbuf_ready(ImageWindow *imd)
747 if (image_get_pixbuf(imd) || !imd->il) return;
749 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
752 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
754 ImageWindow *imd = data;
757 pr = (PixbufRenderer *)imd->pr;
759 if (imd->delay_flip &&
760 pr->pixbuf != image_loader_get_pixbuf(il))
765 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
767 pixbuf_renderer_area_changed(pr, x, y, w, h);
770 static void image_load_done_cb(ImageLoader *il, gpointer data)
772 ImageWindow *imd = data;
774 if (debug) printf ("%s image done\n", get_exec_time());
776 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
777 image_state_unset(imd, IMAGE_STATE_LOADING);
779 if (imd->delay_flip &&
780 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
782 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
783 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
786 image_loader_free(imd->il);
789 image_post_process(imd, TRUE);
791 image_read_ahead_start(imd);
794 static void image_load_error_cb(ImageLoader *il, gpointer data)
796 if (debug) printf ("%s image error\n", get_exec_time());
798 /* even on error handle it like it was done,
799 * since we have a pixbuf with _something_ */
801 image_load_done_cb(il, data);
804 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
805 static void image_load_buffer_throttle(ImageLoader *il)
807 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
809 /* Larger image files usually have larger chunks of data per pixel...
810 * So increase the buffer read size so that the rendering chunks called
814 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
818 /* this read ahead is located here merely for the callbacks, above */
820 static gint image_read_ahead_check(ImageWindow *imd)
822 if (!imd->read_ahead_fd) return FALSE;
823 if (imd->il) return FALSE;
825 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
827 image_read_ahead_cancel(imd);
831 if (imd->read_ahead_il)
833 imd->il = imd->read_ahead_il;
834 imd->read_ahead_il = NULL;
836 /* override the old signals */
837 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
838 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
839 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
841 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
842 image_load_buffer_throttle(imd->il);
845 /* do this one directly (probably should add a set func) */
846 imd->il->func_done = image_load_done_cb;
848 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
849 image_state_set(imd, IMAGE_STATE_LOADING);
851 if (!imd->delay_flip)
853 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
856 image_read_ahead_cancel(imd);
859 else if (imd->read_ahead_pixbuf)
861 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
862 g_object_unref(imd->read_ahead_pixbuf);
863 imd->read_ahead_pixbuf = NULL;
865 image_read_ahead_cancel(imd);
867 image_post_process(imd, FALSE);
871 image_read_ahead_cancel(imd);
875 static gint image_load_begin(ImageWindow *imd, FileData *fd)
877 if (debug) printf ("%s image begin \n", get_exec_time());
879 if (imd->il) return FALSE;
881 imd->completed = FALSE;
882 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
884 if (image_post_buffer_get(imd))
886 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
890 if (image_read_ahead_check(imd))
892 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
896 if (!imd->delay_flip && image_get_pixbuf(imd))
900 pr = PIXBUF_RENDERER(imd->pr);
901 if (pr->pixbuf) g_object_unref(pr->pixbuf);
905 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
907 imd->il = image_loader_new(fd);
909 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
910 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
911 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
913 if (!image_loader_start(imd->il, image_load_done_cb, imd))
915 if (debug) printf("image start error\n");
917 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
919 image_loader_free(imd->il);
922 image_complete_util(imd, FALSE);
927 image_state_set(imd, IMAGE_STATE_LOADING);
929 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
930 image_load_buffer_throttle(imd->il);
933 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
938 static void image_reset(ImageWindow *imd)
940 /* stops anything currently being done */
942 if (debug) printf("%s image reset\n", get_exec_time());
944 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
946 image_loader_free(imd->il);
949 color_man_free((ColorMan *)imd->cm);
952 imd->delay_alter_type = ALTER_NONE;
954 image_state_set(imd, IMAGE_STATE_NONE);
958 *-------------------------------------------------------------------
960 *-------------------------------------------------------------------
963 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
967 if (imd->image_fd && isfile(imd->image_fd->path))
971 pr = PIXBUF_RENDERER(imd->pr);
972 pr->zoom = zoom; /* store the zoom, needed by the loader */
974 if (image_load_begin(imd, imd->image_fd))
976 imd->unknown = FALSE;
982 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
983 image_change_pixbuf(imd, pixbuf, zoom);
984 g_object_unref(pixbuf);
988 imd->size = filesize(imd->image_fd->path);
989 imd->mtime = filetime(imd->image_fd->path);
997 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
998 image_change_pixbuf(imd, pixbuf, zoom);
999 g_object_unref(pixbuf);
1000 imd->mtime = filetime(imd->image_fd->path);
1004 image_change_pixbuf(imd, NULL, zoom);
1007 imd->unknown = TRUE;
1011 image_update_util(imd);
1014 static void image_change_real(ImageWindow *imd, FileData *fd,
1015 CollectionData *cd, CollectInfo *info, gdouble zoom)
1018 GdkPixbuf *prev_pixbuf = NULL;
1019 FileData *prev_fd = NULL;
1020 gint prev_clear = FALSE;
1021 gint prev_color_row = -1;
1023 imd->collection = cd;
1024 imd->collection_info = info;
1026 pixbuf = image_get_pixbuf(imd);
1028 if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1032 /* current image is not finished */
1037 prev_fd = file_data_ref(imd->image_fd);
1038 prev_pixbuf = pixbuf;
1039 g_object_ref(prev_pixbuf);
1045 cm = (ColorMan *)imd->cm;
1046 prev_color_row = cm->row;
1051 file_data_unref(imd->image_fd);
1052 imd->image_fd = file_data_ref(fd);
1054 image_change_complete(imd, zoom, TRUE);
1058 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
1059 file_data_unref(prev_fd);
1060 g_object_unref(prev_pixbuf);
1062 else if (prev_clear)
1064 image_post_buffer_set(imd, NULL, NULL, -1);
1067 image_update_title(imd);
1068 image_state_set(imd, IMAGE_STATE_IMAGE);
1072 *-------------------------------------------------------------------
1074 *-------------------------------------------------------------------
1077 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1081 widget = imd->widget;
1082 if (!widget->window) return;
1086 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
1087 area, widget, "image_window",
1088 widget->allocation.x, widget->allocation.y,
1089 widget->allocation.width - 1, widget->allocation.height - 1);
1093 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1094 area, widget, "image_window",
1095 widget->allocation.x, widget->allocation.y,
1096 widget->allocation.width - 1, widget->allocation.height - 1);
1100 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1102 ImageWindow *imd = data;
1104 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1108 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1110 ImageWindow *imd = data;
1112 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1113 image_focus_paint(imd, TRUE, NULL);
1118 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1120 ImageWindow *imd = data;
1122 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1123 image_focus_paint(imd, FALSE, NULL);
1128 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1129 gint relative, gint always)
1131 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1134 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1136 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1139 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1141 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1144 void image_overlay_remove(ImageWindow *imd, gint id)
1146 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1149 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1151 ImageWindow *imd = data;
1153 if (imd->func_scroll &&
1154 event && event->type == GDK_SCROLL)
1156 imd->func_scroll(imd, event->direction, event->time,
1157 event->x, event->y, event->state, imd->data_scroll);
1165 *-------------------------------------------------------------------
1167 *-------------------------------------------------------------------
1170 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1171 const gchar *title, const gchar *title_right, gint show_zoom)
1173 imd->top_window = window;
1175 imd->title = g_strdup(title);
1176 g_free(imd->title_right);
1177 imd->title_right = g_strdup(title_right);
1178 imd->title_show_zoom = show_zoom;
1180 if (!options->image.fit_window_to_image) window = NULL;
1182 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1184 image_update_title(imd);
1187 void image_set_update_func(ImageWindow *imd,
1188 void (*func)(ImageWindow *imd, gpointer data),
1191 imd->func_update = func;
1192 imd->data_update = data;
1195 void image_set_complete_func(ImageWindow *imd,
1196 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1199 imd->func_complete = func;
1200 imd->data_complete = data;
1203 void image_set_state_func(ImageWindow *imd,
1204 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1207 imd->func_state = func;
1208 imd->data_state = data;
1212 void image_set_button_func(ImageWindow *imd,
1213 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1216 imd->func_button = func;
1217 imd->data_button = data;
1220 void image_set_drag_func(ImageWindow *imd,
1221 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1224 imd->func_drag = func;
1225 imd->data_drag = data;
1228 void image_set_scroll_func(ImageWindow *imd,
1229 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1232 imd->func_scroll = func;
1233 imd->data_scroll = data;
1236 void image_set_scroll_notify_func(ImageWindow *imd,
1237 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1240 imd->func_scroll_notify = func;
1241 imd->data_scroll_notify = data;
1246 const gchar *image_get_path(ImageWindow *imd)
1248 if (imd->image_fd == NULL) return NULL;
1249 return imd->image_fd->path;
1252 const gchar *image_get_name(ImageWindow *imd)
1254 if (imd->image_fd == NULL) return NULL;
1255 return imd->image_fd->name;
1258 FileData *image_get_fd(ImageWindow *imd)
1260 return imd->image_fd;
1263 /* merely changes path string, does not change the image! */
1264 void image_set_fd(ImageWindow *imd, FileData *fd)
1266 file_data_unref(imd->image_fd);
1267 imd->image_fd = file_data_ref(fd);
1269 image_update_title(imd);
1270 image_state_set(imd, IMAGE_STATE_IMAGE);
1273 /* load a new image */
1275 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1277 if (imd->image_fd == fd) return;
1279 image_change_real(imd, fd, NULL, NULL, zoom);
1282 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1284 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1287 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1290 ExifData *exif = NULL;
1293 if (options->image.exif_rotate_enable ||
1294 (imd->color_profile_enable && imd->color_profile_use_image) )
1296 exif = exif_read_fd(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image));
1299 if (options->image.exif_rotate_enable && exif && exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1300 imd->orientation = orientation;
1302 imd->orientation = 1;
1304 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1307 color_man_free(imd->cm);
1311 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1312 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1314 if (imd->color_profile_enable)
1316 if (!image_post_process_color(imd, 0, exif, FALSE))
1318 /* fixme: note error to user */
1319 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1325 if (imd->cm || imd->desaturate)
1326 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1328 image_state_set(imd, IMAGE_STATE_IMAGE);
1331 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1333 if (!cd || !info || !g_list_find(cd->list, info)) return;
1335 image_change_real(imd, info->fd, cd, info, zoom);
1338 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1340 if (collection_to_number(imd->collection) >= 0)
1342 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1344 if (info) *info = imd->collection_info;
1348 if (info) *info = NULL;
1350 return imd->collection;
1353 if (info) *info = NULL;
1357 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1359 /* change data for the callbacks directly */
1361 il->data_area_ready = data;
1362 il->data_error = data;
1363 il->data_done = data;
1364 il->data_percent = data;
1367 /* this is more like a move function
1368 * it moves most data from source to imd
1370 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1372 if (imd == source) return;
1374 imd->unknown = source->unknown;
1376 imd->collection = source->collection;
1377 imd->collection_info = source->collection_info;
1378 imd->size = source->size;
1379 imd->mtime = source->mtime;
1381 image_set_fd(imd, image_get_fd(source));
1383 image_loader_free(imd->il);
1388 imd->il = source->il;
1391 image_loader_sync_data(imd->il, imd);
1393 imd->delay_alter_type = source->delay_alter_type;
1394 source->delay_alter_type = ALTER_NONE;
1397 imd->color_profile_enable = source->color_profile_enable;
1398 imd->color_profile_input = source->color_profile_input;
1399 imd->color_profile_screen = source->color_profile_screen;
1400 imd->color_profile_use_image = source->color_profile_use_image;
1401 color_man_free((ColorMan *)imd->cm);
1407 imd->cm = source->cm;
1410 cm = (ColorMan *)imd->cm;
1412 cm->func_done_data = imd;
1415 image_loader_free(imd->read_ahead_il);
1416 imd->read_ahead_il = source->read_ahead_il;
1417 source->read_ahead_il = NULL;
1418 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1420 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1421 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1422 source->read_ahead_pixbuf = NULL;
1424 file_data_unref(imd->read_ahead_fd);
1425 imd->read_ahead_fd = source->read_ahead_fd;
1426 source->read_ahead_fd = NULL;
1428 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1429 imd->prev_pixbuf = source->prev_pixbuf;
1430 source->prev_pixbuf = NULL;
1431 imd->prev_color_row = source->prev_color_row;
1432 source->prev_color_row = -1;
1434 file_data_unref(imd->prev_fd);
1435 imd->prev_fd = source->prev_fd;
1436 source->prev_fd = NULL;
1438 imd->completed = source->completed;
1439 imd->state = source->state;
1440 source->state = IMAGE_STATE_NONE;
1442 imd->orientation = source->orientation;
1443 imd->desaturate = source->desaturate;
1445 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1447 if (imd->cm || imd->desaturate)
1448 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1450 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1456 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1458 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1461 void image_reload(ImageWindow *imd)
1463 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1465 image_change_complete(imd, image_zoom_get(imd), FALSE);
1468 void image_scroll(ImageWindow *imd, gint x, gint y)
1470 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1473 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1474 gdouble x_align, gdouble y_align)
1476 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1479 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1481 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1484 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1486 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1491 void image_alter(ImageWindow *imd, AlterType type)
1493 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1495 if (imd->il || imd->cm)
1497 /* still loading, wait till done */
1498 imd->delay_alter_type = type;
1499 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1501 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1503 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1508 image_alter_real(imd, type, TRUE);
1512 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1514 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1517 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1519 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1522 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1524 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1527 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1529 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1532 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1538 pr = (PixbufRenderer *)imd->pr;
1540 if (!pixbuf_renderer_get_pixbuf(pr) ||
1541 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1545 zoom = (gdouble)pr->window_height / height;
1549 zoom = (gdouble)pr->window_width / width;
1554 zoom = 0.0 - 1.0 / zoom;
1557 pixbuf_renderer_zoom_set(pr, zoom);
1560 gdouble image_zoom_get(ImageWindow *imd)
1562 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1565 gdouble image_zoom_get_real(ImageWindow *imd)
1567 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1570 gchar *image_zoom_get_as_text(ImageWindow *imd)
1578 gchar *approx = " ";
1580 zoom = image_zoom_get(imd);
1581 scale = image_zoom_get_real(imd);
1587 else if (zoom < 0.0)
1591 else if (zoom == 0.0 && scale != 0.0)
1604 if (rint(l) != l) pl = 1;
1605 if (rint(r) != r) pr = 1;
1607 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1610 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1614 if (mode == ZOOM_RESET_ORIGINAL)
1618 else if (mode == ZOOM_RESET_FIT_WINDOW)
1626 zoom = image_zoom_get(imd);
1639 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1641 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1645 image_read_ahead_set(imd, fd);
1649 image_read_ahead_cancel(imd);
1653 static gint image_auto_refresh_cb(gpointer data)
1655 ImageWindow *imd = data;
1658 if (!imd || !image_get_pixbuf(imd) ||
1659 imd->il || !imd->image_fd ||
1660 !options->update_on_time_change) return TRUE;
1662 newtime = filetime(imd->image_fd->path);
1663 if (newtime > 0 && newtime != imd->mtime)
1665 imd->mtime = newtime;
1672 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1674 void image_auto_refresh(ImageWindow *imd, gint interval)
1677 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1679 if (imd->auto_refresh_id > -1)
1681 g_source_remove(imd->auto_refresh_id);
1682 imd->auto_refresh_id = -1;
1683 imd->auto_refresh_interval = -1;
1686 if (interval < 0) return;
1688 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1690 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1691 imd->auto_refresh_interval = interval;
1694 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1696 imd->top_window_sync = allow_sync;
1698 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1701 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1703 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1706 void image_color_profile_set(ImageWindow *imd,
1707 gint input_type, gint screen_type,
1712 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1713 screen_type < 0 || screen_type > 1)
1718 imd->color_profile_input = input_type;
1719 imd->color_profile_screen = screen_type;
1720 imd->color_profile_use_image = use_image;
1723 gint image_color_profile_get(ImageWindow *imd,
1724 gint *input_type, gint *screen_type,
1727 if (!imd) return FALSE;
1729 if (input_type) *input_type = imd->color_profile_input;
1730 if (screen_type) *screen_type = imd->color_profile_screen;
1731 if (use_image) *use_image = imd->color_profile_use_image;
1736 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1740 if (imd->color_profile_enable == enable) return;
1742 imd->color_profile_enable = enable;
1745 gint image_color_profile_get_use(ImageWindow *imd)
1747 if (!imd) return FALSE;
1749 return imd->color_profile_enable;
1752 gint image_color_profile_get_from_image(ImageWindow *imd)
1754 if (!imd) return FALSE;
1756 return imd->color_profile_from_image;
1759 void image_set_delay_flip(ImageWindow *imd, gint delay)
1762 imd->delay_flip == delay) return;
1764 imd->delay_flip = delay;
1766 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1768 if (!imd->delay_flip && imd->il)
1772 pr = PIXBUF_RENDERER(imd->pr);
1773 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1776 image_load_pixbuf_ready(imd);
1780 void image_to_root_window(ImageWindow *imd, gint scaled)
1783 GdkWindow *rootwindow;
1791 pixbuf = image_get_pixbuf(imd);
1792 if (!pixbuf) return;
1794 screen = gtk_widget_get_screen(imd->widget);
1795 rootwindow = gdk_screen_get_root_window(screen);
1796 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1800 width = gdk_screen_width();
1801 height = gdk_screen_height();
1805 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1808 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1810 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1811 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1812 gdk_window_clear(rootwindow);
1814 g_object_unref(pixmap);
1819 void image_select(ImageWindow *imd, gboolean select)
1825 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1826 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1829 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1835 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1841 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1842 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1846 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1847 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1853 *-------------------------------------------------------------------
1855 *-------------------------------------------------------------------
1858 static void image_options_set(ImageWindow *imd)
1860 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1861 "zoom_2pass", options->image.zoom_2pass,
1862 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1863 "dither_quality", options->image.dither_quality,
1864 "scroll_reset", options->image.scroll_reset_method,
1865 "cache_display", options->image.tile_cache_max,
1866 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1867 "window_limit", options->image.limit_window_size,
1868 "window_limit_value", options->image.max_window_size,
1869 "autofit_limit", options->image.limit_autofit_size,
1870 "autofit_limit_value", options->image.max_autofit_size,
1874 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1877 void image_options_sync(void)
1889 image_options_set(imd);
1894 *-------------------------------------------------------------------
1896 *-------------------------------------------------------------------
1899 static void image_free(ImageWindow *imd)
1901 image_list = g_list_remove(image_list, imd);
1905 image_read_ahead_cancel(imd);
1906 image_post_buffer_set(imd, NULL, NULL, -1);
1907 image_auto_refresh(imd, -1);
1909 file_data_unref(imd->image_fd);
1911 g_free(imd->title_right);
1916 static void image_destroy_cb(GtkObject *widget, gpointer data)
1918 ImageWindow *imd = data;
1922 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1924 gtk_paint_flat_box(widget->style,
1927 GTK_FRAME (widget)->shadow_type,
1931 widget->allocation.x + 3, widget->allocation.y + 3,
1932 widget->allocation.width - 6, widget->allocation.height - 6);
1939 void image_set_frame(ImageWindow *imd, gboolean frame)
1943 if (frame == imd->has_frame) return;
1945 gtk_widget_hide(imd->pr);
1949 imd->frame = gtk_frame_new(NULL);
1950 gtk_widget_ref(imd->pr);
1951 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1952 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1953 gtk_widget_unref(imd->pr);
1954 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1955 G_CALLBACK (selectable_frame_expose_cb), NULL);
1957 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1958 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1959 G_CALLBACK(image_focus_in_cb), imd);
1960 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1961 G_CALLBACK(image_focus_out_cb), imd);
1963 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1964 G_CALLBACK(image_focus_expose), imd);
1967 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1968 gtk_widget_show(imd->frame);
1972 gtk_widget_ref(imd->pr);
1975 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1976 gtk_widget_destroy(imd->frame);
1979 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
1980 gtk_widget_unref(imd->pr);
1983 gtk_widget_show(imd->pr);
1985 imd->has_frame = frame;
1988 ImageWindow *image_new(gint frame)
1992 imd = g_new0(ImageWindow, 1);
1994 imd->top_window = NULL;
1996 imd->title_right = NULL;
1997 imd->title_show_zoom = FALSE;
1999 imd->unknown = TRUE;
2001 imd->has_frame = -1; /* not initialized; for image_set_frame */
2002 imd->top_window_sync = FALSE;
2004 imd->delay_alter_type = ALTER_NONE;
2006 imd->read_ahead_il = NULL;
2007 imd->read_ahead_pixbuf = NULL;
2008 imd->read_ahead_fd = NULL;
2010 imd->completed = FALSE;
2011 imd->state = IMAGE_STATE_NONE;
2013 imd->color_profile_enable = FALSE;
2014 imd->color_profile_input = 0;
2015 imd->color_profile_screen = 0;
2016 imd->color_profile_use_image = FALSE;
2017 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2019 imd->auto_refresh_id = -1;
2020 imd->auto_refresh_interval = -1;
2022 imd->delay_flip = FALSE;
2024 imd->func_update = NULL;
2025 imd->func_complete = NULL;
2026 imd->func_tile_request = NULL;
2027 imd->func_tile_dispose = NULL;
2029 imd->func_button = NULL;
2030 imd->func_scroll = NULL;
2032 imd->orientation = 1;
2034 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2036 image_options_set(imd);
2039 imd->widget = gtk_vbox_new(0, 0);
2041 image_set_frame(imd, frame);
2043 image_set_selectable(imd, 0);
2045 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2046 G_CALLBACK(image_click_cb), imd);
2047 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2048 G_CALLBACK(image_scroll_notify_cb), imd);
2050 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2051 G_CALLBACK(image_scroll_cb), imd);
2053 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2054 G_CALLBACK(image_destroy_cb), imd);
2056 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2057 G_CALLBACK(image_zoom_cb), imd);
2058 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2059 G_CALLBACK(image_render_complete_cb), imd);
2060 g_signal_connect(G_OBJECT(imd->pr), "drag",
2061 G_CALLBACK(image_drag_cb), imd);
2063 image_list = g_list_append(image_list, imd);