4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
18 #include "image-load.h"
20 #include "color-man.h"
22 #include "image-overlay.h"
24 #include "layout_image.h"
25 #include "pixbuf-renderer.h"
26 #include "pixbuf_util.h"
27 #include "ui_fileops.h"
34 /* size of the image loader buffer (512 bytes x defined number) */
35 #define IMAGE_LOAD_BUFFER_COUNT 8
37 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
38 #define IMAGE_THROTTLE_LARGER_IMAGES 1
40 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
41 #define IMAGE_THROTTLE_FACTOR 32
43 /* the file size at which throttling take place */
44 #define IMAGE_THROTTLE_THRESHOLD 1048576
46 #define IMAGE_AUTO_REFRESH_TIME 3000
49 static GList *image_list = NULL;
52 static void image_update_title(ImageWindow *imd);
53 static void image_post_process(ImageWindow *imd, gint clamp);
54 static void image_read_ahead_start(ImageWindow *imd);
57 *-------------------------------------------------------------------
59 *-------------------------------------------------------------------
62 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
64 ImageWindow *imd = data;
68 imd->func_button(imd, event->button, event->time,
69 event->x, event->y, event->state, imd->data_button);
73 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
75 ImageWindow *imd = data;
78 pixbuf_renderer_get_scaled_size(pr, &width, &height);
82 imd->func_drag(imd, event->button, event->time,
83 event->x, event->y, event->state,
84 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
89 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
91 ImageWindow *imd = data;
93 if (imd->func_scroll_notify && pr->scale)
95 imd->func_scroll_notify(imd,
96 (gint)((gdouble)pr->x_scroll / pr->scale),
97 (gint)((gdouble)pr->y_scroll / pr->scale),
98 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
99 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
100 imd->data_scroll_notify);
104 static void image_update_util(ImageWindow *imd)
106 if (imd->func_update) imd->func_update(imd, imd->data_update);
109 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
111 ImageWindow *imd = data;
113 if (imd->title_show_zoom) image_update_title(imd);
114 if (imd->overlay_show_zoom) image_osd_update(imd);
116 image_update_util(imd);
119 static void image_complete_util(ImageWindow *imd, gint preload)
121 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
123 if (debug) printf("%s image load completed \"%s\" (%s)\n", get_exec_time(),
124 (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") :
125 (imd->image_fd ? imd->image_fd->path : "null"),
126 (preload) ? "preload" : "current");
128 if (!preload) imd->completed = TRUE;
129 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
132 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
134 ImageWindow *imd = data;
136 image_complete_util(imd, FALSE);
139 static void image_state_set(ImageWindow *imd, ImageState state)
141 if (state == IMAGE_STATE_NONE)
149 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
152 static void image_state_unset(ImageWindow *imd, ImageState state)
154 imd->state &= ~state;
155 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
159 *-------------------------------------------------------------------
161 *-------------------------------------------------------------------
164 static void image_update_title(ImageWindow *imd)
168 gchar *collection = NULL;
170 if (!imd->top_window) return;
172 if (imd->collection && collection_to_number(imd->collection) >= 0)
175 name = imd->collection->name;
176 if (!name) name = _("Untitled");
177 collection = g_strdup_printf(" (Collection %s)", name);
180 if (imd->title_show_zoom)
182 gchar *buf = image_zoom_get_as_text(imd);
183 zoom = g_strconcat(" [", buf, "]", NULL);
187 title = g_strdup_printf("%s%s%s%s%s%s",
188 imd->title ? imd->title : "",
189 imd->image_fd ? imd->image_fd->name : "",
191 collection ? collection : "",
192 imd->image_fd ? " - " : "",
193 imd->title_right ? imd->title_right : "");
195 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
203 *-------------------------------------------------------------------
204 * rotation, flip, etc.
205 *-------------------------------------------------------------------
211 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
214 GdkPixbuf *new = NULL;
219 pr = (PixbufRenderer *)imd->pr;
221 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
222 imd->delay_alter_type = ALTER_NONE;
224 if (!pr->pixbuf) return;
226 x = pr->x_scroll + (pr->vis_width / 2);
227 y = pr->y_scroll + (pr->vis_height / 2);
231 case ALTER_ROTATE_90:
232 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
237 case ALTER_ROTATE_90_CC:
238 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
243 case ALTER_ROTATE_180:
244 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
249 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
253 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
256 case ALTER_DESATURATE:
257 pixbuf_desaturate_rect(pr->pixbuf,
258 0, 0, pr->image_width, pr->image_height);
259 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
260 layout_image_overlay_update(layout_find_by_image(imd));
270 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
273 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
277 switch (pr->scroll_reset)
279 case PR_SCROLL_RESET_NOCHANGE:
281 case PR_SCROLL_RESET_CENTER:
282 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
283 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
285 case PR_SCROLL_RESET_TOPLEFT:
292 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
293 (gint)((gdouble)y / pr->scale),
297 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
298 layout_image_overlay_update(layout_find_by_image(imd));
299 if (debug) printf("%s image postprocess done: %s\n", get_exec_time(), imd->image_fd->name);
302 static void image_post_process_alter(ImageWindow *imd, gint clamp)
304 if (imd->delay_alter_type != ALTER_NONE)
306 image_alter_real(imd, imd->delay_alter_type, clamp);
311 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
313 ImageWindow *imd = data;
316 if (type == COLOR_RETURN_IMAGE_CHANGED)
318 if (cm == imd->cm) imd->cm = NULL;
323 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
324 if (debug) printf("%s image postprocess cm done: %s\n", get_exec_time(), imd->image_fd->name);
326 image_post_process_alter(imd, FALSE);
328 image_read_ahead_start(imd);
332 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg)
335 ColorManProfileType input_type;
336 ColorManProfileType screen_type;
337 const gchar *input_file;
338 const gchar *screen_file;
339 unsigned char *profile = NULL;
342 if (imd->cm) return FALSE;
344 if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
345 imd->color_profile_input < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
349 n = imd->color_profile_input - COLOR_PROFILE_FILE;
350 if (!options->color_profile.input_file[n]) return FALSE;
352 input_type = COLOR_PROFILE_FILE;
353 input_file = options->color_profile.input_file[n];
355 else if (imd->color_profile_input >= COLOR_PROFILE_SRGB &&
356 imd->color_profile_input < COLOR_PROFILE_FILE)
358 input_type = imd->color_profile_input;
366 if (imd->color_profile_screen == 1 &&
367 options->color_profile.screen_file)
369 screen_type = COLOR_PROFILE_FILE;
370 screen_file = options->color_profile.screen_file;
372 else if (imd->color_profile_screen == 0)
374 screen_type = COLOR_PROFILE_SRGB;
381 imd->color_profile_from_image = COLOR_PROFILE_NONE;
383 if (imd->color_profile_use_image && exif)
385 profile = exif_get_color_profile(exif, &profile_len);
389 gchar *interop_index;
391 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
392 if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
393 interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
397 input_type = COLOR_PROFILE_SRGB;
399 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
401 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
403 if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
405 input_type = COLOR_PROFILE_ADOBERGB;
407 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
409 if (debug) printf("Found EXIF ColorSpace of AdobeRGB\n");
412 g_free(interop_index);
418 if (debug) printf("Found embedded color profile\n");
419 imd->color_profile_from_image = COLOR_PROFILE_MEM;
421 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
422 profile, profile_len,
423 screen_type, screen_file);
428 cm = color_man_new(run_in_bg ? imd : NULL, NULL,
429 input_type, input_file,
430 screen_type, screen_file);
438 cm->incremental_sync = TRUE;
441 imd->cm = (gpointer)cm;
443 if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd);
451 static void image_post_process(ImageWindow *imd, gint clamp)
454 ExifData *exif = NULL;
456 if (!image_get_pixbuf(imd)) return;
458 if (debug) printf("%s image postprocess: %s\n", get_exec_time(), imd->image_fd->name);
460 if (options->image.exif_rotate_enable ||
461 (imd->color_profile_enable && imd->color_profile_use_image) )
463 exif = exif_read_fd(imd->image_fd);
465 if (options->image.exif_rotate_enable && exif)
469 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
473 /* see http://jpegclub.org/exif_orientation.html
476 888888 888888 88 88 8888888888 88 88 8888888888
477 88 88 88 88 88 88 88 88 88 88 88 88
478 8888 8888 8888 8888 88 8888888888 8888888888 88
484 case EXIF_ORIENTATION_TOP_LEFT:
485 /* normal -- nothing to do */
488 case EXIF_ORIENTATION_TOP_RIGHT:
490 imd->delay_alter_type = ALTER_MIRROR;
492 case EXIF_ORIENTATION_BOTTOM_RIGHT:
494 imd->delay_alter_type = ALTER_ROTATE_180;
496 case EXIF_ORIENTATION_BOTTOM_LEFT:
498 imd->delay_alter_type = ALTER_FLIP;
500 case EXIF_ORIENTATION_LEFT_TOP:
501 /* not implemented -- too wacky to fix in one step */
504 case EXIF_ORIENTATION_RIGHT_TOP:
505 /* rotated -90 (270) */
506 imd->delay_alter_type = ALTER_ROTATE_90;
508 case EXIF_ORIENTATION_RIGHT_BOTTOM:
509 /* not implemented -- too wacky to fix in one step */
512 case EXIF_ORIENTATION_LEFT_BOTTOM:
514 imd->delay_alter_type = ALTER_ROTATE_90_CC;
517 /* The other values are out of range */
522 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
525 if (imd->color_profile_enable)
527 if (!image_post_process_color(imd, 0, exif, TRUE))
529 /* fixme: note error to user */
530 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
535 if (!imd->cm) image_post_process_alter(imd, clamp);
541 static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data)
543 ImageWindow *imd = (ImageWindow *)data;
544 if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h);
545 if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h);
549 void image_alter(ImageWindow *imd, AlterType type)
552 const static gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1};
553 const static gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3};
554 const static gint rotate_180[] = {1, 3, 4, 1, 2, 7, 8, 5, 6};
555 const static gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7};
556 const static gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5};
559 if (!imd || !imd->pr) return;
561 if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
565 case ALTER_ROTATE_90:
566 imd->orientation = rotate_90[imd->orientation];
568 case ALTER_ROTATE_90_CC:
569 imd->orientation = rotate_90_cc[imd->orientation];
571 case ALTER_ROTATE_180:
572 imd->orientation = rotate_180[imd->orientation];
575 imd->orientation = mirror[imd->orientation];
578 imd->orientation = flip[imd->orientation];
580 case ALTER_DESATURATE:
581 imd->desaturate = !imd->desaturate;
584 imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1;
585 imd->desaturate = FALSE;
592 if (type != ALTER_NONE && type != ALTER_DESATURATE)
594 if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd);
595 imd->image_fd->user_orientation = imd->orientation;
599 if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd);
600 imd->image_fd->user_orientation = 0;
603 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
604 if (imd->cm || imd->desaturate)
605 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
607 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
612 *-------------------------------------------------------------------
613 * read ahead (prebuffer)
614 *-------------------------------------------------------------------
617 static void image_read_ahead_cancel(ImageWindow *imd)
619 if (debug) printf("%s read ahead cancelled for :%s\n", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
621 image_loader_free(imd->read_ahead_il);
622 imd->read_ahead_il = NULL;
624 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
625 imd->read_ahead_pixbuf = NULL;
627 file_data_unref(imd->read_ahead_fd);
628 imd->read_ahead_fd = NULL;
631 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
633 ImageWindow *imd = data;
635 if (debug) printf("%s read ahead done for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
637 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
638 if (imd->read_ahead_pixbuf)
640 g_object_ref(imd->read_ahead_pixbuf);
644 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
646 image_loader_free(imd->read_ahead_il);
647 imd->read_ahead_il = NULL;
649 image_complete_util(imd, TRUE);
652 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
654 /* we even treat errors as success, maybe at least some of the file was ok */
655 image_read_ahead_done_cb(il, data);
658 static void image_read_ahead_start(ImageWindow *imd)
660 /* already started ? */
661 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
663 /* still loading ?, do later */
664 if (imd->il /*|| imd->cm*/) return;
666 if (debug) printf("%s read ahead started for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
668 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
670 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
671 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
673 image_read_ahead_cancel(imd);
674 image_complete_util(imd, TRUE);
678 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
680 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
682 image_read_ahead_cancel(imd);
684 imd->read_ahead_fd = file_data_ref(fd);
686 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
688 image_read_ahead_start(imd);
692 *-------------------------------------------------------------------
694 *-------------------------------------------------------------------
697 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
699 file_data_unref(imd->prev_fd);
700 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
704 imd->prev_fd = file_data_ref(fd);
706 g_object_ref(pixbuf);
707 imd->prev_pixbuf = pixbuf;
708 imd->prev_color_row = color_row;
713 imd->prev_pixbuf = NULL;
714 imd->prev_color_row = -1;
717 if (debug) printf("%s post buffer set: %s\n", get_exec_time(), fd ? fd->path : "null");
720 static gint image_post_buffer_get(ImageWindow *imd)
724 if (imd->prev_pixbuf &&
725 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
727 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
728 if (imd->prev_color_row >= 0)
730 ExifData *exif = NULL;
732 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
733 // image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
743 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
744 imd->prev_pixbuf = NULL;
746 file_data_unref(imd->prev_fd);
753 *-------------------------------------------------------------------
755 *-------------------------------------------------------------------
758 static void image_load_pixbuf_ready(ImageWindow *imd)
760 if (image_get_pixbuf(imd) || !imd->il) return;
762 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
765 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
767 ImageWindow *imd = data;
770 pr = (PixbufRenderer *)imd->pr;
772 if (imd->delay_flip &&
773 pr->pixbuf != image_loader_get_pixbuf(il))
778 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
780 pixbuf_renderer_area_changed(pr, x, y, w, h);
783 static void image_load_done_cb(ImageLoader *il, gpointer data)
785 ImageWindow *imd = data;
787 if (debug) printf ("%s image done\n", get_exec_time());
789 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
790 image_state_unset(imd, IMAGE_STATE_LOADING);
792 if (imd->delay_flip &&
793 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
795 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
796 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
799 image_loader_free(imd->il);
802 image_post_process(imd, TRUE);
804 image_read_ahead_start(imd);
807 static void image_load_error_cb(ImageLoader *il, gpointer data)
809 if (debug) printf ("%s image error\n", get_exec_time());
811 /* even on error handle it like it was done,
812 * since we have a pixbuf with _something_ */
814 image_load_done_cb(il, data);
817 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
818 static void image_load_buffer_throttle(ImageLoader *il)
820 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
822 /* Larger image files usually have larger chunks of data per pixel...
823 * So increase the buffer read size so that the rendering chunks called
827 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
831 /* this read ahead is located here merely for the callbacks, above */
833 static gint image_read_ahead_check(ImageWindow *imd)
835 if (!imd->read_ahead_fd) return FALSE;
836 if (imd->il) return FALSE;
838 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
840 image_read_ahead_cancel(imd);
844 if (imd->read_ahead_il)
846 imd->il = imd->read_ahead_il;
847 imd->read_ahead_il = NULL;
849 /* override the old signals */
850 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
851 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
852 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
854 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
855 image_load_buffer_throttle(imd->il);
858 /* do this one directly (probably should add a set func) */
859 imd->il->func_done = image_load_done_cb;
861 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
862 image_state_set(imd, IMAGE_STATE_LOADING);
864 if (!imd->delay_flip)
866 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
869 image_read_ahead_cancel(imd);
872 else if (imd->read_ahead_pixbuf)
874 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
875 g_object_unref(imd->read_ahead_pixbuf);
876 imd->read_ahead_pixbuf = NULL;
878 image_read_ahead_cancel(imd);
880 image_post_process(imd, FALSE);
884 image_read_ahead_cancel(imd);
888 static gint image_load_begin(ImageWindow *imd, FileData *fd)
890 if (debug) printf ("%s image begin \n", get_exec_time());
892 if (imd->il) return FALSE;
894 imd->completed = FALSE;
895 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
897 if (image_post_buffer_get(imd))
899 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
903 if (image_read_ahead_check(imd))
905 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
909 if (!imd->delay_flip && image_get_pixbuf(imd))
913 pr = PIXBUF_RENDERER(imd->pr);
914 if (pr->pixbuf) g_object_unref(pr->pixbuf);
918 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
920 imd->il = image_loader_new(fd);
922 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
923 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
924 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
926 if (!image_loader_start(imd->il, image_load_done_cb, imd))
928 if (debug) printf("image start error\n");
930 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
932 image_loader_free(imd->il);
935 image_complete_util(imd, FALSE);
940 image_state_set(imd, IMAGE_STATE_LOADING);
942 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
943 image_load_buffer_throttle(imd->il);
946 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
951 static void image_reset(ImageWindow *imd)
953 /* stops anything currently being done */
955 if (debug) printf("%s image reset\n", get_exec_time());
957 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
959 image_loader_free(imd->il);
962 color_man_free((ColorMan *)imd->cm);
965 imd->delay_alter_type = ALTER_NONE;
967 image_state_set(imd, IMAGE_STATE_NONE);
971 *-------------------------------------------------------------------
973 *-------------------------------------------------------------------
976 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
980 if (imd->image_fd && isfile(imd->image_fd->path))
984 pr = PIXBUF_RENDERER(imd->pr);
985 pr->zoom = zoom; /* store the zoom, needed by the loader */
987 if (image_load_begin(imd, imd->image_fd))
989 imd->unknown = FALSE;
995 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
996 image_change_pixbuf(imd, pixbuf, zoom);
997 g_object_unref(pixbuf);
1001 imd->size = filesize(imd->image_fd->path);
1002 imd->mtime = filetime(imd->image_fd->path);
1010 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
1011 image_change_pixbuf(imd, pixbuf, zoom);
1012 g_object_unref(pixbuf);
1013 imd->mtime = filetime(imd->image_fd->path);
1017 image_change_pixbuf(imd, NULL, zoom);
1020 imd->unknown = TRUE;
1024 image_update_util(imd);
1027 static void image_change_real(ImageWindow *imd, FileData *fd,
1028 CollectionData *cd, CollectInfo *info, gdouble zoom)
1031 GdkPixbuf *prev_pixbuf = NULL;
1032 FileData *prev_fd = NULL;
1033 gint prev_clear = FALSE;
1034 gint prev_color_row = -1;
1036 imd->collection = cd;
1037 imd->collection_info = info;
1039 pixbuf = image_get_pixbuf(imd);
1041 if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1045 /* current image is not finished */
1050 prev_fd = file_data_ref(imd->image_fd);
1051 prev_pixbuf = pixbuf;
1052 g_object_ref(prev_pixbuf);
1058 cm = (ColorMan *)imd->cm;
1059 prev_color_row = cm->row;
1064 file_data_unref(imd->image_fd);
1065 imd->image_fd = file_data_ref(fd);
1067 image_change_complete(imd, zoom, TRUE);
1071 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
1072 file_data_unref(prev_fd);
1073 g_object_unref(prev_pixbuf);
1075 else if (prev_clear)
1077 image_post_buffer_set(imd, NULL, NULL, -1);
1080 image_update_title(imd);
1081 image_state_set(imd, IMAGE_STATE_IMAGE);
1085 *-------------------------------------------------------------------
1087 *-------------------------------------------------------------------
1090 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1094 widget = imd->widget;
1095 if (!widget->window) return;
1099 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
1100 area, widget, "image_window",
1101 widget->allocation.x, widget->allocation.y,
1102 widget->allocation.width - 1, widget->allocation.height - 1);
1106 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1107 area, widget, "image_window",
1108 widget->allocation.x, widget->allocation.y,
1109 widget->allocation.width - 1, widget->allocation.height - 1);
1113 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1115 ImageWindow *imd = data;
1117 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1121 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1123 ImageWindow *imd = data;
1125 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1126 image_focus_paint(imd, TRUE, NULL);
1131 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1133 ImageWindow *imd = data;
1135 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1136 image_focus_paint(imd, FALSE, NULL);
1141 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1142 gint relative, gint always)
1144 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1147 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1149 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1152 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1154 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1157 void image_overlay_remove(ImageWindow *imd, gint id)
1159 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1162 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1164 ImageWindow *imd = data;
1166 if (imd->func_scroll &&
1167 event && event->type == GDK_SCROLL)
1169 imd->func_scroll(imd, event->direction, event->time,
1170 event->x, event->y, event->state, imd->data_scroll);
1178 *-------------------------------------------------------------------
1180 *-------------------------------------------------------------------
1183 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1184 const gchar *title, const gchar *title_right, gint show_zoom)
1186 imd->top_window = window;
1188 imd->title = g_strdup(title);
1189 g_free(imd->title_right);
1190 imd->title_right = g_strdup(title_right);
1191 imd->title_show_zoom = show_zoom;
1193 if (!options->image.fit_window_to_image) window = NULL;
1195 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1197 image_update_title(imd);
1200 void image_set_update_func(ImageWindow *imd,
1201 void (*func)(ImageWindow *imd, gpointer data),
1204 imd->func_update = func;
1205 imd->data_update = data;
1208 void image_set_complete_func(ImageWindow *imd,
1209 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1212 imd->func_complete = func;
1213 imd->data_complete = data;
1216 void image_set_state_func(ImageWindow *imd,
1217 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1220 imd->func_state = func;
1221 imd->data_state = data;
1225 void image_set_button_func(ImageWindow *imd,
1226 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1229 imd->func_button = func;
1230 imd->data_button = data;
1233 void image_set_drag_func(ImageWindow *imd,
1234 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1237 imd->func_drag = func;
1238 imd->data_drag = data;
1241 void image_set_scroll_func(ImageWindow *imd,
1242 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1245 imd->func_scroll = func;
1246 imd->data_scroll = data;
1249 void image_set_scroll_notify_func(ImageWindow *imd,
1250 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1253 imd->func_scroll_notify = func;
1254 imd->data_scroll_notify = data;
1259 const gchar *image_get_path(ImageWindow *imd)
1261 if (imd->image_fd == NULL) return NULL;
1262 return imd->image_fd->path;
1265 const gchar *image_get_name(ImageWindow *imd)
1267 if (imd->image_fd == NULL) return NULL;
1268 return imd->image_fd->name;
1271 FileData *image_get_fd(ImageWindow *imd)
1273 return imd->image_fd;
1276 /* merely changes path string, does not change the image! */
1277 void image_set_fd(ImageWindow *imd, FileData *fd)
1279 file_data_unref(imd->image_fd);
1280 imd->image_fd = file_data_ref(fd);
1282 image_update_title(imd);
1283 image_state_set(imd, IMAGE_STATE_IMAGE);
1286 /* load a new image */
1288 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1290 if (imd->image_fd == fd) return;
1292 image_change_real(imd, fd, NULL, NULL, zoom);
1295 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1297 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1300 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1303 ExifData *exif = NULL;
1304 gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
1305 gint read_exif_for_orientation = FALSE;
1307 if (imd->image_fd && imd->image_fd->user_orientation)
1308 imd->orientation = imd->image_fd->user_orientation;
1309 else if (options->image.exif_rotate_enable)
1310 read_exif_for_orientation = TRUE;
1312 if (read_exif_for_color_profile || read_exif_for_orientation)
1316 exif = exif_read_fd(imd->image_fd);
1318 if (exif && read_exif_for_orientation)
1320 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1321 imd->orientation = orientation;
1323 imd->orientation = 1;
1324 imd->image_fd->exif_orientation = imd->orientation;
1328 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1331 color_man_free(imd->cm);
1335 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1336 pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1338 if (imd->color_profile_enable)
1340 if (!image_post_process_color(imd, 0, exif, FALSE))
1342 /* fixme: note error to user */
1343 // image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1349 if (imd->cm || imd->desaturate)
1350 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1352 image_state_set(imd, IMAGE_STATE_IMAGE);
1355 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1357 if (!cd || !info || !g_list_find(cd->list, info)) return;
1359 image_change_real(imd, info->fd, cd, info, zoom);
1362 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1364 if (collection_to_number(imd->collection) >= 0)
1366 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1368 if (info) *info = imd->collection_info;
1372 if (info) *info = NULL;
1374 return imd->collection;
1377 if (info) *info = NULL;
1381 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1383 /* change data for the callbacks directly */
1385 il->data_area_ready = data;
1386 il->data_error = data;
1387 il->data_done = data;
1388 il->data_percent = data;
1391 /* this is more like a move function
1392 * it moves most data from source to imd
1394 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1396 if (imd == source) return;
1398 imd->unknown = source->unknown;
1400 imd->collection = source->collection;
1401 imd->collection_info = source->collection_info;
1402 imd->size = source->size;
1403 imd->mtime = source->mtime;
1405 image_set_fd(imd, image_get_fd(source));
1407 image_loader_free(imd->il);
1412 imd->il = source->il;
1415 image_loader_sync_data(imd->il, imd);
1417 imd->delay_alter_type = source->delay_alter_type;
1418 source->delay_alter_type = ALTER_NONE;
1421 imd->color_profile_enable = source->color_profile_enable;
1422 imd->color_profile_input = source->color_profile_input;
1423 imd->color_profile_screen = source->color_profile_screen;
1424 imd->color_profile_use_image = source->color_profile_use_image;
1425 color_man_free((ColorMan *)imd->cm);
1431 imd->cm = source->cm;
1434 cm = (ColorMan *)imd->cm;
1436 cm->func_done_data = imd;
1439 image_loader_free(imd->read_ahead_il);
1440 imd->read_ahead_il = source->read_ahead_il;
1441 source->read_ahead_il = NULL;
1442 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1444 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1445 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1446 source->read_ahead_pixbuf = NULL;
1448 file_data_unref(imd->read_ahead_fd);
1449 imd->read_ahead_fd = source->read_ahead_fd;
1450 source->read_ahead_fd = NULL;
1452 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1453 imd->prev_pixbuf = source->prev_pixbuf;
1454 source->prev_pixbuf = NULL;
1455 imd->prev_color_row = source->prev_color_row;
1456 source->prev_color_row = -1;
1458 file_data_unref(imd->prev_fd);
1459 imd->prev_fd = source->prev_fd;
1460 source->prev_fd = NULL;
1462 imd->completed = source->completed;
1463 imd->state = source->state;
1464 source->state = IMAGE_STATE_NONE;
1466 imd->orientation = source->orientation;
1467 imd->desaturate = source->desaturate;
1469 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1471 if (imd->cm || imd->desaturate)
1472 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1474 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1480 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1482 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1485 void image_reload(ImageWindow *imd)
1487 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1489 image_change_complete(imd, image_zoom_get(imd), FALSE);
1492 void image_scroll(ImageWindow *imd, gint x, gint y)
1494 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1497 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1498 gdouble x_align, gdouble y_align)
1500 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1503 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1505 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1508 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1510 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1515 void image_alter(ImageWindow *imd, AlterType type)
1517 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1519 if (imd->il || imd->cm)
1521 /* still loading, wait till done */
1522 imd->delay_alter_type = type;
1523 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1525 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1527 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1532 image_alter_real(imd, type, TRUE);
1536 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1538 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1541 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1543 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1546 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1548 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1551 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1553 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1556 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1562 pr = (PixbufRenderer *)imd->pr;
1564 if (!pixbuf_renderer_get_pixbuf(pr) ||
1565 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1569 zoom = (gdouble)pr->window_height / height;
1573 zoom = (gdouble)pr->window_width / width;
1578 zoom = 0.0 - 1.0 / zoom;
1581 pixbuf_renderer_zoom_set(pr, zoom);
1584 gdouble image_zoom_get(ImageWindow *imd)
1586 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1589 gdouble image_zoom_get_real(ImageWindow *imd)
1591 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1594 gchar *image_zoom_get_as_text(ImageWindow *imd)
1602 gchar *approx = " ";
1604 zoom = image_zoom_get(imd);
1605 scale = image_zoom_get_real(imd);
1611 else if (zoom < 0.0)
1615 else if (zoom == 0.0 && scale != 0.0)
1628 if (rint(l) != l) pl = 1;
1629 if (rint(r) != r) pr = 1;
1631 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1634 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1638 if (mode == ZOOM_RESET_ORIGINAL)
1642 else if (mode == ZOOM_RESET_FIT_WINDOW)
1650 zoom = image_zoom_get(imd);
1663 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1665 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1669 image_read_ahead_set(imd, fd);
1673 image_read_ahead_cancel(imd);
1677 static gint image_auto_refresh_cb(gpointer data)
1679 ImageWindow *imd = data;
1682 if (!imd || !image_get_pixbuf(imd) ||
1683 imd->il || !imd->image_fd ||
1684 !options->update_on_time_change) return TRUE;
1686 newtime = filetime(imd->image_fd->path);
1687 if (newtime > 0 && newtime != imd->mtime)
1689 imd->mtime = newtime;
1696 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1698 void image_auto_refresh(ImageWindow *imd, gint interval)
1701 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1703 if (imd->auto_refresh_id > -1)
1705 g_source_remove(imd->auto_refresh_id);
1706 imd->auto_refresh_id = -1;
1707 imd->auto_refresh_interval = -1;
1710 if (interval < 0) return;
1712 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1714 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1715 imd->auto_refresh_interval = interval;
1718 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1720 imd->top_window_sync = allow_sync;
1722 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1725 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1727 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1730 void image_color_profile_set(ImageWindow *imd,
1731 gint input_type, gint screen_type,
1736 if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1737 screen_type < 0 || screen_type > 1)
1742 imd->color_profile_input = input_type;
1743 imd->color_profile_screen = screen_type;
1744 imd->color_profile_use_image = use_image;
1747 gint image_color_profile_get(ImageWindow *imd,
1748 gint *input_type, gint *screen_type,
1751 if (!imd) return FALSE;
1753 if (input_type) *input_type = imd->color_profile_input;
1754 if (screen_type) *screen_type = imd->color_profile_screen;
1755 if (use_image) *use_image = imd->color_profile_use_image;
1760 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1764 if (imd->color_profile_enable == enable) return;
1766 imd->color_profile_enable = enable;
1769 gint image_color_profile_get_use(ImageWindow *imd)
1771 if (!imd) return FALSE;
1773 return imd->color_profile_enable;
1776 gint image_color_profile_get_from_image(ImageWindow *imd)
1778 if (!imd) return FALSE;
1780 return imd->color_profile_from_image;
1783 void image_set_delay_flip(ImageWindow *imd, gint delay)
1786 imd->delay_flip == delay) return;
1788 imd->delay_flip = delay;
1790 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1792 if (!imd->delay_flip && imd->il)
1796 pr = PIXBUF_RENDERER(imd->pr);
1797 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1800 image_load_pixbuf_ready(imd);
1804 void image_to_root_window(ImageWindow *imd, gint scaled)
1807 GdkWindow *rootwindow;
1815 pixbuf = image_get_pixbuf(imd);
1816 if (!pixbuf) return;
1818 screen = gtk_widget_get_screen(imd->widget);
1819 rootwindow = gdk_screen_get_root_window(screen);
1820 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1824 width = gdk_screen_width();
1825 height = gdk_screen_height();
1829 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1832 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1834 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1835 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1836 gdk_window_clear(rootwindow);
1838 g_object_unref(pixmap);
1843 void image_select(ImageWindow *imd, gboolean select)
1849 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1850 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1853 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1859 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1865 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1866 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1870 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1871 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1877 *-------------------------------------------------------------------
1879 *-------------------------------------------------------------------
1882 static void image_options_set(ImageWindow *imd)
1884 g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1885 "zoom_2pass", options->image.zoom_2pass,
1886 "zoom_expand", options->image.zoom_to_fit_allow_expand,
1887 "dither_quality", options->image.dither_quality,
1888 "scroll_reset", options->image.scroll_reset_method,
1889 "cache_display", options->image.tile_cache_max,
1890 "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1891 "window_limit", options->image.limit_window_size,
1892 "window_limit_value", options->image.max_window_size,
1893 "autofit_limit", options->image.limit_autofit_size,
1894 "autofit_limit_value", options->image.max_autofit_size,
1898 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1901 void image_options_sync(void)
1913 image_options_set(imd);
1918 *-------------------------------------------------------------------
1920 *-------------------------------------------------------------------
1923 static void image_free(ImageWindow *imd)
1925 image_list = g_list_remove(image_list, imd);
1929 image_read_ahead_cancel(imd);
1930 image_post_buffer_set(imd, NULL, NULL, -1);
1931 image_auto_refresh(imd, -1);
1933 file_data_unref(imd->image_fd);
1935 g_free(imd->title_right);
1940 static void image_destroy_cb(GtkObject *widget, gpointer data)
1942 ImageWindow *imd = data;
1946 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1948 gtk_paint_flat_box(widget->style,
1951 GTK_FRAME (widget)->shadow_type,
1955 widget->allocation.x + 3, widget->allocation.y + 3,
1956 widget->allocation.width - 6, widget->allocation.height - 6);
1963 void image_set_frame(ImageWindow *imd, gboolean frame)
1967 if (frame == imd->has_frame) return;
1969 gtk_widget_hide(imd->pr);
1973 imd->frame = gtk_frame_new(NULL);
1974 gtk_widget_ref(imd->pr);
1975 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1976 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1977 gtk_widget_unref(imd->pr);
1978 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1979 G_CALLBACK (selectable_frame_expose_cb), NULL);
1981 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1982 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1983 G_CALLBACK(image_focus_in_cb), imd);
1984 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1985 G_CALLBACK(image_focus_out_cb), imd);
1987 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1988 G_CALLBACK(image_focus_expose), imd);
1991 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1992 gtk_widget_show(imd->frame);
1996 gtk_widget_ref(imd->pr);
1999 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
2000 gtk_widget_destroy(imd->frame);
2003 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2004 gtk_widget_unref(imd->pr);
2007 gtk_widget_show(imd->pr);
2009 imd->has_frame = frame;
2012 ImageWindow *image_new(gint frame)
2016 imd = g_new0(ImageWindow, 1);
2018 imd->top_window = NULL;
2020 imd->title_right = NULL;
2021 imd->title_show_zoom = FALSE;
2023 imd->unknown = TRUE;
2025 imd->has_frame = -1; /* not initialized; for image_set_frame */
2026 imd->top_window_sync = FALSE;
2028 imd->delay_alter_type = ALTER_NONE;
2030 imd->read_ahead_il = NULL;
2031 imd->read_ahead_pixbuf = NULL;
2032 imd->read_ahead_fd = NULL;
2034 imd->completed = FALSE;
2035 imd->state = IMAGE_STATE_NONE;
2037 imd->color_profile_enable = FALSE;
2038 imd->color_profile_input = 0;
2039 imd->color_profile_screen = 0;
2040 imd->color_profile_use_image = FALSE;
2041 imd->color_profile_from_image = COLOR_PROFILE_NONE;
2043 imd->auto_refresh_id = -1;
2044 imd->auto_refresh_interval = -1;
2046 imd->delay_flip = FALSE;
2048 imd->func_update = NULL;
2049 imd->func_complete = NULL;
2050 imd->func_tile_request = NULL;
2051 imd->func_tile_dispose = NULL;
2053 imd->func_button = NULL;
2054 imd->func_scroll = NULL;
2056 imd->orientation = 1;
2058 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2060 image_options_set(imd);
2063 imd->widget = gtk_vbox_new(0, 0);
2065 image_set_frame(imd, frame);
2067 image_set_selectable(imd, 0);
2069 g_signal_connect(G_OBJECT(imd->pr), "clicked",
2070 G_CALLBACK(image_click_cb), imd);
2071 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2072 G_CALLBACK(image_scroll_notify_cb), imd);
2074 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2075 G_CALLBACK(image_scroll_cb), imd);
2077 g_signal_connect(G_OBJECT(imd->pr), "destroy",
2078 G_CALLBACK(image_destroy_cb), imd);
2080 g_signal_connect(G_OBJECT(imd->pr), "zoom",
2081 G_CALLBACK(image_zoom_cb), imd);
2082 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2083 G_CALLBACK(image_render_complete_cb), imd);
2084 g_signal_connect(G_OBJECT(imd->pr), "drag",
2085 G_CALLBACK(image_drag_cb), imd);
2087 image_list = g_list_append(image_list, imd);