read color profiles from jpeg also with Exiv2
[geeqie.git] / src / image.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
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!
10  */
11
12
13 #include "main.h"
14 #include "image.h"
15
16
17 #include "image-load.h"
18 #include "collect.h"
19 #include "color-man.h"
20 #include "exif.h"
21 #include "image-overlay.h"
22 #include "layout.h"
23 #include "layout_image.h"
24 #include "pixbuf-renderer.h"
25 #include "pixbuf_util.h"
26 #include "ui_fileops.h"
27
28 #include "filelist.h"
29
30 #include <math.h>
31
32
33 /* size of the image loader buffer (512 bytes x defined number) */
34 #define IMAGE_LOAD_BUFFER_COUNT 8
35
36 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
37 #define IMAGE_THROTTLE_LARGER_IMAGES 1
38
39 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
40 #define IMAGE_THROTTLE_FACTOR 32
41
42 /* the file size at which throttling take place */
43 #define IMAGE_THROTTLE_THRESHOLD 1048576
44
45 #define IMAGE_AUTO_REFRESH_TIME 3000
46
47
48 static GList *image_list = NULL;
49
50
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);
54
55 /*
56  *-------------------------------------------------------------------
57  * 'signals'
58  *-------------------------------------------------------------------
59  */
60
61 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
62 {
63         ImageWindow *imd = data;
64
65         if (imd->func_button)
66                 {
67                 imd->func_button(imd, event->button, event->time,
68                                  event->x, event->y, event->state, imd->data_button);
69                 }
70 }
71
72 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
73 {
74         ImageWindow *imd = data;
75         gint width, height;
76
77         pixbuf_renderer_get_scaled_size(pr, &width, &height);
78
79         if (imd->func_drag)
80                 {
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,
84                                  imd->data_button);
85                 }
86 }
87
88 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
89 {
90         ImageWindow *imd = data;
91
92         if (imd->func_scroll_notify && pr->scale)
93                 {
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);
100                 }
101 }
102
103 static void image_update_util(ImageWindow *imd)
104 {
105         if (imd->func_update) imd->func_update(imd, imd->data_update);
106 }
107
108 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
109 {
110         ImageWindow *imd = data;
111
112         if (imd->title_show_zoom) image_update_title(imd);
113         if (imd->overlay_show_zoom) image_osd_update(imd);
114
115         image_update_util(imd);
116 }
117
118 static void image_complete_util(ImageWindow *imd, gint preload)
119 {
120         if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
121
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");
126
127         if (!preload) imd->completed = TRUE;
128         if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
129 }
130
131 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
132 {
133         ImageWindow *imd = data;
134
135         image_complete_util(imd, FALSE);
136 }
137
138 static void image_state_set(ImageWindow *imd, ImageState state)
139 {
140         if (state == IMAGE_STATE_NONE)
141                 {
142                 imd->state = state;
143                 }
144         else
145                 {
146                 imd->state |= state;
147                 }
148         if (imd->func_state) imd->func_state(imd, state, imd->data_state);
149 }
150
151 static void image_state_unset(ImageWindow *imd, ImageState state)
152 {
153         imd->state &= ~state;
154         if (imd->func_state) imd->func_state(imd, state, imd->data_state);
155 }
156
157 /*
158  *-------------------------------------------------------------------
159  * misc
160  *-------------------------------------------------------------------
161  */
162
163 static void image_update_title(ImageWindow *imd)
164 {
165         gchar *title = NULL;
166         gchar *zoom = NULL;
167         gchar *collection = NULL;
168
169         if (!imd->top_window) return;
170
171         if (imd->collection && collection_to_number(imd->collection) >= 0)
172                 {
173                 const gchar *name;
174                 name = imd->collection->name;
175                 if (!name) name = _("Untitled");
176                 collection = g_strdup_printf(" (Collection %s)", name);
177                 }
178
179         if (imd->title_show_zoom)
180                 {
181                 gchar *buf = image_zoom_get_as_text(imd);
182                 zoom = g_strconcat(" [", buf, "]", NULL);
183                 g_free(buf);
184                 }
185
186         title = g_strdup_printf("%s%s%s%s%s%s",
187                 imd->title ? imd->title : "",
188                 imd->image_fd ? imd->image_fd->name : "",
189                 zoom ? zoom : "",
190                 collection ? collection : "",
191                 imd->image_fd ? " - " : "",
192                 imd->title_right ? imd->title_right : "");
193
194         gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
195
196         g_free(title);
197         g_free(zoom);
198         g_free(collection);
199 }
200
201 /*
202  *-------------------------------------------------------------------
203  * rotation, flip, etc.
204  *-------------------------------------------------------------------
205  */
206
207
208 #if 0
209
210 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
211 {
212         PixbufRenderer *pr;
213         GdkPixbuf *new = NULL;
214         gint exif_rotate;
215         gint x, y;
216         gint t;
217
218         pr = (PixbufRenderer *)imd->pr;
219
220         exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
221         imd->delay_alter_type = ALTER_NONE;
222
223         if (!pr->pixbuf) return;
224
225         x = pr->x_scroll + (pr->vis_width / 2);
226         y = pr->y_scroll + (pr->vis_height / 2);
227
228         switch (type)
229                 {
230                 case ALTER_ROTATE_90:
231                         new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
232                         t = x;
233                         x = pr->height - y;
234                         y = t;
235                         break;
236                 case ALTER_ROTATE_90_CC:
237                         new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
238                         t = x;
239                         x = y;
240                         y = pr->width - t;
241                         break;
242                 case ALTER_ROTATE_180:
243                         new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
244                         x = pr->width - x;
245                         y = pr->height - y;
246                         break;
247                 case ALTER_MIRROR:
248                         new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
249                         x = pr->width - x;
250                         break;
251                 case ALTER_FLIP:
252                         new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
253                         y = pr->height - y;
254                         break;
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));
260                         break;
261                 case ALTER_NONE:
262                 default:
263                         return;
264                         break;
265                 }
266
267         if (!new) return;
268
269         pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
270         g_object_unref(new);
271
272         if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
273                 {
274                 if (exif_rotate)
275                         {
276                         switch (pr->scroll_reset)
277                                 {
278                                 case PR_SCROLL_RESET_NOCHANGE:
279                                         break;
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);
283                                         break;
284                                 case PR_SCROLL_RESET_TOPLEFT:
285                                 default:
286                                         x = 0;
287                                         y = 0;
288                                         break;
289                                 }
290                         }
291                 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
292                                                     (gint)((gdouble)y / pr->scale),
293                                                     0.50, 0.50);
294                 }
295
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);
299 }
300
301 static void image_post_process_alter(ImageWindow *imd, gint clamp)
302 {
303         if (imd->delay_alter_type != ALTER_NONE)
304                 {
305                 image_alter_real(imd, imd->delay_alter_type, clamp);
306                 }
307 }
308
309
310 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
311 {
312         ImageWindow *imd = data;
313
314         color_man_free(cm);
315         if (type == COLOR_RETURN_IMAGE_CHANGED)
316                 {
317                 if (cm == imd->cm) imd->cm = NULL;
318                 return;
319                 }
320
321         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);
324
325         image_post_process_alter(imd, FALSE);
326
327         image_read_ahead_start(imd);
328 }
329 #endif
330
331 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg)
332 {
333         ColorMan *cm;
334         ColorManProfileType input_type;
335         ColorManProfileType screen_type;
336         const gchar *input_file;
337         const gchar *screen_file;
338         unsigned char *profile = NULL;
339         guint profile_len;
340
341         if (imd->cm) return FALSE;
342
343         if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
344             imd->color_profile_input <  COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
345                 {
346                 gint n;
347
348                 n = imd->color_profile_input - COLOR_PROFILE_FILE;
349                 if (!options->color_profile.input_file[n]) return FALSE;
350
351                 input_type = COLOR_PROFILE_FILE;
352                 input_file = options->color_profile.input_file[n];
353                 }
354         else if (imd->color_profile_input >= COLOR_PROFILE_SRGB &&
355                  imd->color_profile_input <  COLOR_PROFILE_FILE)
356                 {
357                 input_type = imd->color_profile_input;
358                 input_file = NULL;
359                 }
360         else
361                 {
362                 return FALSE;
363                 }
364
365         if (imd->color_profile_screen == 1 &&
366             options->color_profile.screen_file)
367                 {
368                 screen_type = COLOR_PROFILE_FILE;
369                 screen_file = options->color_profile.screen_file;
370                 }
371         else if (imd->color_profile_screen == 0)
372                 {
373                 screen_type = COLOR_PROFILE_SRGB;
374                 screen_file = NULL;
375                 }
376         else
377                 {
378                 return FALSE;
379                 }
380         imd->color_profile_from_image = COLOR_PROFILE_NONE;
381
382         if (imd->color_profile_use_image && exif)
383                 {
384                 profile = exif_get_color_profile(exif, &profile_len);
385                 if (!profile)
386                         {
387                         gint cs;
388                         gchar *interop_index;
389
390                         /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
391                         if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
392                         interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
393
394                         if (cs == 1)
395                                 {
396                                 input_type = COLOR_PROFILE_SRGB;
397                                 input_file = NULL;
398                                 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
399
400                                 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
401                                 }
402                         if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
403                                 {
404                                 input_type = COLOR_PROFILE_ADOBERGB;
405                                 input_file = NULL;
406                                 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
407
408                                 if (debug) printf("Found EXIF ColorSpace of AdobeRGB\n");
409                                 }
410
411                         g_free(interop_index);
412                         }
413                 }
414
415         if (profile)
416                 {
417                 if (debug) printf("Found embedded color profile\n");
418                 imd->color_profile_from_image = COLOR_PROFILE_MEM;
419
420                 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
421                                             profile, profile_len,
422                                             screen_type, screen_file);
423                 g_free(profile);
424                 }
425         else
426                 {
427                 cm = color_man_new(run_in_bg ? imd : NULL, NULL,
428                                    input_type, input_file,
429                                    screen_type, screen_file);
430                 }
431
432         if (cm)
433                 {
434                 if (start_row > 0)
435                         {
436                         cm->row = start_row;
437                         cm->incremental_sync = TRUE;
438                         }
439
440                 imd->cm = (gpointer)cm;
441 #if 0
442                 if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd);
443 #endif
444                 return TRUE;
445                 }
446
447         return FALSE;
448 }
449
450 static void image_post_process(ImageWindow *imd, gint clamp)
451 {
452 #if 0
453         ExifData *exif = NULL;
454
455         if (!image_get_pixbuf(imd)) return;
456
457         if (debug) printf("%s image postprocess: %s\n", get_exec_time(), imd->image_fd->name);
458
459         if (options->image.exif_rotate_enable ||
460             (imd->color_profile_enable && imd->color_profile_use_image) )
461                 {
462                 exif = exif_read_fd(imd->image_fd);
463                 }
464         if (options->image.exif_rotate_enable && exif)
465                 {
466                 gint orientation;
467
468                 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
469                         {
470                         gint rotate = TRUE;
471
472                         /* see http://jpegclub.org/exif_orientation.html
473                           1        2       3      4         5            6           7          8
474
475                         888888  888888      88  88      8888888888  88                  88  8888888888
476                         88          88      88  88      88  88      88  88          88  88      88  88
477                         8888      8888    8888  8888    88          8888888888  8888888888          88
478                         88          88      88  88
479                         88          88  888888  888888
480                         */
481                         switch (orientation)
482                                 {
483                                 case EXIF_ORIENTATION_TOP_LEFT:
484                                         /* normal -- nothing to do */
485                                         rotate = FALSE;
486                                         break;
487                                 case EXIF_ORIENTATION_TOP_RIGHT:
488                                         /* mirrored */
489                                         imd->delay_alter_type = ALTER_MIRROR;
490                                         break;
491                                 case EXIF_ORIENTATION_BOTTOM_RIGHT:
492                                         /* upside down */
493                                         imd->delay_alter_type = ALTER_ROTATE_180;
494                                         break;
495                                 case EXIF_ORIENTATION_BOTTOM_LEFT:
496                                         /* flipped */
497                                         imd->delay_alter_type = ALTER_FLIP;
498                                         break;
499                                 case EXIF_ORIENTATION_LEFT_TOP:
500                                         /* not implemented -- too wacky to fix in one step */
501                                         rotate = FALSE;
502                                         break;
503                                 case EXIF_ORIENTATION_RIGHT_TOP:
504                                         /* rotated -90 (270) */
505                                         imd->delay_alter_type = ALTER_ROTATE_90;
506                                         break;
507                                 case EXIF_ORIENTATION_RIGHT_BOTTOM:
508                                         /* not implemented -- too wacky to fix in one step */
509                                         rotate = FALSE;
510                                         break;
511                                 case EXIF_ORIENTATION_LEFT_BOTTOM:
512                                         /* rotated 90 */
513                                         imd->delay_alter_type = ALTER_ROTATE_90_CC;
514                                         break;
515                                 default:
516                                         /* The other values are out of range */
517                                         rotate = FALSE;
518                                         break;
519                                 }
520
521                         if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
522                         }
523                 }
524         if (imd->color_profile_enable)
525                 {
526                 if (!image_post_process_color(imd, 0, exif, TRUE))
527                         {
528                         /* fixme: note error to user */
529                         image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
530                         }
531                 }
532
533
534         if (!imd->cm) image_post_process_alter(imd, clamp);
535
536         exif_free(exif);
537 #endif
538 }
539
540 static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pixbuf, gint x, gint y, gint w, gint h, gpointer data)
541 {
542         ImageWindow *imd = (ImageWindow *)data;
543         if (imd->cm) color_man_correct_region(imd->cm, *pixbuf, x, y, w, h);
544         if (imd->desaturate) pixbuf_desaturate_rect(*pixbuf, x, y, w, h);
545
546 }
547
548 void image_alter(ImageWindow *imd, AlterType type)
549 {
550
551         const static gint rotate_90[]    = {1,   6, 7, 8, 5, 2, 3, 4, 1};
552         const static gint rotate_90_cc[] = {1,   8, 5, 6, 7, 4, 1, 2, 3};
553         const static gint rotate_180[]   = {1,   3, 4, 1, 2, 7, 8, 5, 6};
554         const static gint mirror[]       = {1,   2, 1, 4, 3, 6, 5, 8, 7};
555         const static gint flip[]         = {1,   4, 3, 2, 1, 8, 7, 6, 5};
556
557
558         if (!imd || !imd->pr) return;
559
560         if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
561
562         switch (type)
563                 {
564                 case ALTER_ROTATE_90:
565                         imd->orientation = rotate_90[imd->orientation];
566                         break;
567                 case ALTER_ROTATE_90_CC:
568                         imd->orientation = rotate_90_cc[imd->orientation];
569                         break;
570                 case ALTER_ROTATE_180:
571                         imd->orientation = rotate_180[imd->orientation];
572                         break;
573                 case ALTER_MIRROR:
574                         imd->orientation = mirror[imd->orientation];
575                         break;
576                 case ALTER_FLIP:
577                         imd->orientation = flip[imd->orientation];
578                         break;
579                 case ALTER_DESATURATE:
580                         imd->desaturate = !imd->desaturate;
581                         break;
582                 case ALTER_NONE:
583                         imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1;
584                         imd->desaturate = FALSE;
585                         break;
586                 default:
587                         return;
588                         break;
589                 }
590
591         if (type != ALTER_NONE && type != ALTER_DESATURATE)
592                 {
593                 if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd);
594                 imd->image_fd->user_orientation = imd->orientation;
595                 }
596         else
597                 {
598                 if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd);
599                 imd->image_fd->user_orientation = 0;
600                 }
601
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) );
605         else
606                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
607 }
608
609
610 /*
611  *-------------------------------------------------------------------
612  * read ahead (prebuffer)
613  *-------------------------------------------------------------------
614  */
615
616 static void image_read_ahead_cancel(ImageWindow *imd)
617 {
618         if (debug) printf("%s read ahead cancelled for :%s\n", get_exec_time(), imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
619
620         image_loader_free(imd->read_ahead_il);
621         imd->read_ahead_il = NULL;
622
623         if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
624         imd->read_ahead_pixbuf = NULL;
625
626         file_data_unref(imd->read_ahead_fd);
627         imd->read_ahead_fd = NULL;
628 }
629
630 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
631 {
632         ImageWindow *imd = data;
633
634         if (debug) printf("%s read ahead done for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
635
636         imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
637         if (imd->read_ahead_pixbuf)
638                 {
639                 g_object_ref(imd->read_ahead_pixbuf);
640                 }
641         else
642                 {
643                 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
644                 }
645         image_loader_free(imd->read_ahead_il);
646         imd->read_ahead_il = NULL;
647
648         image_complete_util(imd, TRUE);
649 }
650
651 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
652 {
653         /* we even treat errors as success, maybe at least some of the file was ok */
654         image_read_ahead_done_cb(il, data);
655 }
656
657 static void image_read_ahead_start(ImageWindow *imd)
658 {
659         /* already started ? */
660         if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
661
662         /* still loading ?, do later */
663         if (imd->il /*|| imd->cm*/) return;
664
665         if (debug) printf("%s read ahead started for :%s\n", get_exec_time(), imd->read_ahead_fd->path);
666
667         imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
668
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))
671                 {
672                 image_read_ahead_cancel(imd);
673                 image_complete_util(imd, TRUE);
674                 }
675 }
676
677 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
678 {
679         if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
680
681         image_read_ahead_cancel(imd);
682
683         imd->read_ahead_fd = file_data_ref(fd);
684
685         if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
686
687         image_read_ahead_start(imd);
688 }
689
690 /*
691  *-------------------------------------------------------------------
692  * post buffering
693  *-------------------------------------------------------------------
694  */
695
696 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
697 {
698         file_data_unref(imd->prev_fd);
699         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
700
701         if (fd && pixbuf)
702                 {
703                 imd->prev_fd = file_data_ref(fd);
704
705                 g_object_ref(pixbuf);
706                 imd->prev_pixbuf = pixbuf;
707                 imd->prev_color_row = color_row;
708                 }
709         else
710                 {
711                 imd->prev_fd = NULL;
712                 imd->prev_pixbuf = NULL;
713                 imd->prev_color_row = -1;
714                 }
715
716         if (debug) printf("%s post buffer set: %s\n", get_exec_time(), fd ? fd->path : "null");
717 }
718
719 static gint image_post_buffer_get(ImageWindow *imd)
720 {
721         gint success;
722
723         if (imd->prev_pixbuf &&
724             imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
725                 {
726                 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
727                 if (imd->prev_color_row >= 0)
728                         {
729                         ExifData *exif = NULL;
730
731                         if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
732 //                      image_post_process_color(imd, imd->prev_color_row, exif, TRUE);
733                         exif_free(exif);
734                         }
735                 success = TRUE;
736                 }
737         else
738                 {
739                 success = FALSE;
740                 }
741
742         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
743         imd->prev_pixbuf = NULL;
744
745         file_data_unref(imd->prev_fd);
746         imd->prev_fd = NULL;
747
748         return success;
749 }
750
751 /*
752  *-------------------------------------------------------------------
753  * loading
754  *-------------------------------------------------------------------
755  */
756
757 static void image_load_pixbuf_ready(ImageWindow *imd)
758 {
759         if (image_get_pixbuf(imd) || !imd->il) return;
760
761         image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
762 }
763
764 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
765 {
766         ImageWindow *imd = data;
767         PixbufRenderer *pr;
768
769         pr = (PixbufRenderer *)imd->pr;
770
771         if (imd->delay_flip &&
772             pr->pixbuf != image_loader_get_pixbuf(il))
773                 {
774                 return;
775                 }
776
777         if (!pr->pixbuf) image_load_pixbuf_ready(imd);
778
779         pixbuf_renderer_area_changed(pr, x, y, w, h);
780 }
781
782 static void image_load_done_cb(ImageLoader *il, gpointer data)
783 {
784         ImageWindow *imd = data;
785
786         if (debug) printf ("%s image done\n", get_exec_time());
787
788         g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
789         image_state_unset(imd, IMAGE_STATE_LOADING);
790
791         if (imd->delay_flip &&
792             image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
793                 {
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));
796                 }
797
798         image_loader_free(imd->il);
799         imd->il = NULL;
800
801         image_post_process(imd, TRUE);
802
803         image_read_ahead_start(imd);
804 }
805
806 static void image_load_error_cb(ImageLoader *il, gpointer data)
807 {
808         if (debug) printf ("%s image error\n", get_exec_time());
809
810         /* even on error handle it like it was done,
811          * since we have a pixbuf with _something_ */
812
813         image_load_done_cb(il, data);
814 }
815
816 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
817 static void image_load_buffer_throttle(ImageLoader *il)
818 {
819         if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
820
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
823          * are also larger.
824          */
825
826         image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
827 }
828 #endif
829
830 /* this read ahead is located here merely for the callbacks, above */
831
832 static gint image_read_ahead_check(ImageWindow *imd)
833 {
834         if (!imd->read_ahead_fd) return FALSE;
835         if (imd->il) return FALSE;
836
837         if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
838                 {
839                 image_read_ahead_cancel(imd);
840                 return FALSE;
841                 }
842
843         if (imd->read_ahead_il)
844                 {
845                 imd->il = imd->read_ahead_il;
846                 imd->read_ahead_il = NULL;
847
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);
852
853 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
854                 image_load_buffer_throttle(imd->il);
855 #endif
856
857                 /* do this one directly (probably should add a set func) */
858                 imd->il->func_done = image_load_done_cb;
859
860                 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
861                 image_state_set(imd, IMAGE_STATE_LOADING);
862
863                 if (!imd->delay_flip)
864                         {
865                         image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
866                         }
867
868                 image_read_ahead_cancel(imd);
869                 return TRUE;
870                 }
871         else if (imd->read_ahead_pixbuf)
872                 {
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;
876
877                 image_read_ahead_cancel(imd);
878
879                 image_post_process(imd, FALSE);
880                 return TRUE;
881                 }
882
883         image_read_ahead_cancel(imd);
884         return FALSE;
885 }
886
887 static gint image_load_begin(ImageWindow *imd, FileData *fd)
888 {
889         if (debug) printf ("%s image begin \n", get_exec_time());
890
891         if (imd->il) return FALSE;
892
893         imd->completed = FALSE;
894         g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
895
896         if (image_post_buffer_get(imd))
897                 {
898                 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
899                 return TRUE;
900                 }
901
902         if (image_read_ahead_check(imd))
903                 {
904                 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
905                 return TRUE;
906                 }
907
908         if (!imd->delay_flip && image_get_pixbuf(imd))
909                 {
910                 PixbufRenderer *pr;
911
912                 pr = PIXBUF_RENDERER(imd->pr);
913                 if (pr->pixbuf) g_object_unref(pr->pixbuf);
914                 pr->pixbuf = NULL;
915                 }
916
917         g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
918
919         imd->il = image_loader_new(fd);
920
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);
924
925         if (!image_loader_start(imd->il, image_load_done_cb, imd))
926                 {
927                 if (debug) printf("image start error\n");
928
929                 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
930
931                 image_loader_free(imd->il);
932                 imd->il = NULL;
933
934                 image_complete_util(imd, FALSE);
935
936                 return FALSE;
937                 }
938
939         image_state_set(imd, IMAGE_STATE_LOADING);
940
941 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
942         image_load_buffer_throttle(imd->il);
943 #endif
944
945         if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
946
947         return TRUE;
948 }
949
950 static void image_reset(ImageWindow *imd)
951 {
952         /* stops anything currently being done */
953
954         if (debug) printf("%s image reset\n", get_exec_time());
955
956         g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
957
958         image_loader_free(imd->il);
959         imd->il = NULL;
960
961         color_man_free((ColorMan *)imd->cm);
962         imd->cm = NULL;
963
964         imd->delay_alter_type = ALTER_NONE;
965
966         image_state_set(imd, IMAGE_STATE_NONE);
967 }
968
969 /*
970  *-------------------------------------------------------------------
971  * image changer
972  *-------------------------------------------------------------------
973  */
974
975 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
976 {
977         image_reset(imd);
978
979         if (imd->image_fd && isfile(imd->image_fd->path))
980                 {
981                 PixbufRenderer *pr;
982
983                 pr = PIXBUF_RENDERER(imd->pr);
984                 pr->zoom = zoom;        /* store the zoom, needed by the loader */
985
986                 if (image_load_begin(imd, imd->image_fd))
987                         {
988                         imd->unknown = FALSE;
989                         }
990                 else
991                         {
992                         GdkPixbuf *pixbuf;
993
994                         pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
995                         image_change_pixbuf(imd, pixbuf, zoom);
996                         g_object_unref(pixbuf);
997
998                         imd->unknown = TRUE;
999                         }
1000                 imd->size = filesize(imd->image_fd->path);
1001                 imd->mtime = filetime(imd->image_fd->path);
1002                 }
1003         else
1004                 {
1005                 if (imd->image_fd)
1006                         {
1007                         GdkPixbuf *pixbuf;
1008
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);
1013                         }
1014                 else
1015                         {
1016                         image_change_pixbuf(imd, NULL, zoom);
1017                         imd->mtime = 0;
1018                         }
1019                 imd->unknown = TRUE;
1020                 imd->size = 0;
1021                 }
1022
1023         image_update_util(imd);
1024 }
1025
1026 static void image_change_real(ImageWindow *imd, FileData *fd,
1027                               CollectionData *cd, CollectInfo *info, gdouble zoom)
1028 {
1029         GdkPixbuf *pixbuf;
1030         GdkPixbuf *prev_pixbuf = NULL;
1031         FileData *prev_fd = NULL;
1032         gint prev_clear = FALSE;
1033         gint prev_color_row = -1;
1034
1035         imd->collection = cd;
1036         imd->collection_info = info;
1037
1038         pixbuf = image_get_pixbuf(imd);
1039
1040         if (options->image.enable_read_ahead && imd->image_fd && pixbuf)
1041                 {
1042                 if (imd->il)
1043                         {
1044                         /* current image is not finished */
1045                         prev_clear = TRUE;
1046                         }
1047                 else
1048                         {
1049                         prev_fd = file_data_ref(imd->image_fd);
1050                         prev_pixbuf = pixbuf;
1051                         g_object_ref(prev_pixbuf);
1052
1053                         if (imd->cm)
1054                                 {
1055                                 ColorMan *cm;
1056
1057                                 cm = (ColorMan *)imd->cm;
1058                                 prev_color_row = cm->row;
1059                                 }
1060                         }
1061                 }
1062
1063         file_data_unref(imd->image_fd);
1064         imd->image_fd = file_data_ref(fd);
1065
1066         image_change_complete(imd, zoom, TRUE);
1067
1068         if (prev_pixbuf)
1069                 {
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);
1073                 }
1074         else if (prev_clear)
1075                 {
1076                 image_post_buffer_set(imd, NULL, NULL, -1);
1077                 }
1078
1079         image_update_title(imd);
1080         image_state_set(imd, IMAGE_STATE_IMAGE);
1081 }
1082
1083 /*
1084  *-------------------------------------------------------------------
1085  * focus stuff
1086  *-------------------------------------------------------------------
1087  */
1088
1089 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
1090 {
1091         GtkWidget *widget;
1092
1093         widget = imd->widget;
1094         if (!widget->window) return;
1095
1096         if (has_focus)
1097                 {
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);
1102                 }
1103         else
1104                 {
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);
1109                 }
1110 }
1111
1112 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1113 {
1114         ImageWindow *imd = data;
1115
1116         image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1117         return TRUE;
1118 }
1119
1120 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1121 {
1122         ImageWindow *imd = data;
1123
1124         GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1125         image_focus_paint(imd, TRUE, NULL);
1126
1127         return TRUE;
1128 }
1129
1130 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1131 {
1132         ImageWindow *imd = data;
1133
1134         GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1135         image_focus_paint(imd, FALSE, NULL);
1136
1137         return TRUE;
1138 }
1139
1140 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1141                        gint relative, gint always)
1142 {
1143         return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1144 }
1145
1146 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1147 {
1148         pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1149 }
1150
1151 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1152 {
1153         return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1154 }
1155
1156 void image_overlay_remove(ImageWindow *imd, gint id)
1157 {
1158         pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1159 }
1160
1161 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1162 {
1163         ImageWindow *imd = data;
1164
1165         if (imd->func_scroll &&
1166             event && event->type == GDK_SCROLL)
1167                 {
1168                 imd->func_scroll(imd, event->direction, event->time,
1169                                  event->x, event->y, event->state, imd->data_scroll);
1170                 return TRUE;
1171                 }
1172
1173         return FALSE;
1174 }
1175
1176 /*
1177  *-------------------------------------------------------------------
1178  * public interface
1179  *-------------------------------------------------------------------
1180  */
1181
1182 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1183                          const gchar *title, const gchar *title_right, gint show_zoom)
1184 {
1185         imd->top_window = window;
1186         g_free(imd->title);
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;
1191
1192         if (!options->image.fit_window_to_image) window = NULL;
1193
1194         pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1195
1196         image_update_title(imd);
1197 }
1198
1199 void image_set_update_func(ImageWindow *imd,
1200                            void (*func)(ImageWindow *imd, gpointer data),
1201                            gpointer data)
1202 {
1203         imd->func_update = func;
1204         imd->data_update = data;
1205 }
1206
1207 void image_set_complete_func(ImageWindow *imd,
1208                              void (*func)(ImageWindow *imd, gint preload, gpointer data),
1209                              gpointer data)
1210 {
1211         imd->func_complete = func;
1212         imd->data_complete = data;
1213 }
1214
1215 void image_set_state_func(ImageWindow *imd,
1216                         void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1217                         gpointer data)
1218 {
1219         imd->func_state = func;
1220         imd->data_state = data;
1221 }
1222
1223
1224 void image_set_button_func(ImageWindow *imd,
1225                            void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1226                            gpointer data)
1227 {
1228         imd->func_button = func;
1229         imd->data_button = data;
1230 }
1231
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),
1234                            gpointer data)
1235 {
1236         imd->func_drag = func;
1237         imd->data_drag = data;
1238 }
1239
1240 void image_set_scroll_func(ImageWindow *imd,
1241                            void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1242                            gpointer data)
1243 {
1244         imd->func_scroll = func;
1245         imd->data_scroll = data;
1246 }
1247
1248 void image_set_scroll_notify_func(ImageWindow *imd,
1249                                   void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1250                                   gpointer data)
1251 {
1252         imd->func_scroll_notify = func;
1253         imd->data_scroll_notify = data;
1254 }
1255
1256 /* path, name */
1257
1258 const gchar *image_get_path(ImageWindow *imd)
1259 {
1260         if (imd->image_fd == NULL) return NULL;
1261         return imd->image_fd->path;
1262 }
1263
1264 const gchar *image_get_name(ImageWindow *imd)
1265 {
1266         if (imd->image_fd == NULL) return NULL;
1267         return imd->image_fd->name;
1268 }
1269
1270 FileData *image_get_fd(ImageWindow *imd)
1271 {
1272         return imd->image_fd;
1273 }
1274
1275 /* merely changes path string, does not change the image! */
1276 void image_set_fd(ImageWindow *imd, FileData *fd)
1277 {
1278         file_data_unref(imd->image_fd);
1279         imd->image_fd = file_data_ref(fd);
1280
1281         image_update_title(imd);
1282         image_state_set(imd, IMAGE_STATE_IMAGE);
1283 }
1284
1285 /* load a new image */
1286
1287 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1288 {
1289         if (imd->image_fd == fd) return;
1290
1291         image_change_real(imd, fd, NULL, NULL, zoom);
1292 }
1293
1294 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1295 {
1296         return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1297 }
1298
1299 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1300 {
1301
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;
1305
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;
1310
1311         if (read_exif_for_color_profile || read_exif_for_orientation)
1312                 {
1313                 gint orientation;
1314
1315                 exif = exif_read_fd(imd->image_fd);
1316
1317                 if (exif && read_exif_for_orientation)
1318                         {
1319                         if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1320                                 imd->orientation = orientation;
1321                         else
1322                                 imd->orientation = 1;
1323                         imd->image_fd->exif_orientation = imd->orientation;
1324                         }
1325                 }
1326
1327         pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1328         if (imd->cm)
1329                 {
1330                 color_man_free(imd->cm);
1331                 imd->cm = NULL;
1332                 }
1333
1334         pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1335         pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1336
1337         if (imd->color_profile_enable)
1338                 {
1339                 if (!image_post_process_color(imd, 0, exif, FALSE))
1340                         {
1341                         /* fixme: note error to user */
1342 //                      image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1343                         }
1344                 }
1345
1346         exif_free(exif);
1347
1348         if (imd->cm || imd->desaturate)
1349                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1350
1351         image_state_set(imd, IMAGE_STATE_IMAGE);
1352 }
1353
1354 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1355 {
1356         if (!cd || !info || !g_list_find(cd->list, info)) return;
1357
1358         image_change_real(imd, info->fd, cd, info, zoom);
1359 }
1360
1361 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1362 {
1363         if (collection_to_number(imd->collection) >= 0)
1364                 {
1365                 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1366                         {
1367                         if (info) *info = imd->collection_info;
1368                         }
1369                 else
1370                         {
1371                         if (info) *info = NULL;
1372                         }
1373                 return imd->collection;
1374                 }
1375
1376         if (info) *info = NULL;
1377         return NULL;
1378 }
1379
1380 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1381 {
1382         /* change data for the callbacks directly */
1383
1384         il->data_area_ready = data;
1385         il->data_error = data;
1386         il->data_done = data;
1387         il->data_percent = data;
1388 }
1389
1390 /* this is more like a move function
1391  * it moves most data from source to imd
1392  */
1393 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1394 {
1395         if (imd == source) return;
1396
1397         imd->unknown = source->unknown;
1398
1399         imd->collection = source->collection;
1400         imd->collection_info = source->collection_info;
1401         imd->size = source->size;
1402         imd->mtime = source->mtime;
1403
1404         image_set_fd(imd, image_get_fd(source));
1405
1406         image_loader_free(imd->il);
1407         imd->il = NULL;
1408
1409         if (source->il)
1410                 {
1411                 imd->il = source->il;
1412                 source->il = NULL;
1413
1414                 image_loader_sync_data(imd->il, imd);
1415
1416                 imd->delay_alter_type = source->delay_alter_type;
1417                 source->delay_alter_type = ALTER_NONE;
1418                 }
1419
1420         imd->color_profile_enable = source->color_profile_enable;
1421         imd->color_profile_input = source->color_profile_input;
1422         imd->color_profile_screen = source->color_profile_screen;
1423         imd->color_profile_use_image = source->color_profile_use_image;
1424         color_man_free((ColorMan *)imd->cm);
1425         imd->cm = NULL;
1426         if (source->cm)
1427                 {
1428                 ColorMan *cm;
1429
1430                 imd->cm = source->cm;
1431                 source->cm = NULL;
1432
1433                 cm = (ColorMan *)imd->cm;
1434                 cm->imd = imd;
1435                 cm->func_done_data = imd;
1436                 }
1437
1438         image_loader_free(imd->read_ahead_il);
1439         imd->read_ahead_il = source->read_ahead_il;
1440         source->read_ahead_il = NULL;
1441         if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1442
1443         if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1444         imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1445         source->read_ahead_pixbuf = NULL;
1446
1447         file_data_unref(imd->read_ahead_fd);
1448         imd->read_ahead_fd = source->read_ahead_fd;
1449         source->read_ahead_fd = NULL;
1450
1451         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1452         imd->prev_pixbuf = source->prev_pixbuf;
1453         source->prev_pixbuf = NULL;
1454         imd->prev_color_row = source->prev_color_row;
1455         source->prev_color_row = -1;
1456
1457         file_data_unref(imd->prev_fd);
1458         imd->prev_fd = source->prev_fd;
1459         source->prev_fd = NULL;
1460
1461         imd->completed = source->completed;
1462         imd->state = source->state;
1463         source->state = IMAGE_STATE_NONE;
1464
1465         imd->orientation = source->orientation;
1466         imd->desaturate = source->desaturate;
1467
1468         pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1469
1470         if (imd->cm || imd->desaturate)
1471                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1472         else
1473                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1474
1475 }
1476
1477 /* manipulation */
1478
1479 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1480 {
1481         pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1482 }
1483
1484 void image_reload(ImageWindow *imd)
1485 {
1486         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1487
1488         image_change_complete(imd, image_zoom_get(imd), FALSE);
1489 }
1490
1491 void image_scroll(ImageWindow *imd, gint x, gint y)
1492 {
1493         pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1494 }
1495
1496 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1497                            gdouble x_align, gdouble y_align)
1498 {
1499         pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1500 }
1501
1502 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1503 {
1504         pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1505 }
1506
1507 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1508 {
1509         pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1510 }
1511
1512
1513 #if 0
1514 void image_alter(ImageWindow *imd, AlterType type)
1515 {
1516         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1517
1518         if (imd->il || imd->cm)
1519                 {
1520                 /* still loading, wait till done */
1521                 imd->delay_alter_type = type;
1522                 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1523
1524                 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1525                         {
1526                         image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1527                         }
1528                 return;
1529                 }
1530
1531         image_alter_real(imd, type, TRUE);
1532 }
1533 #endif
1534
1535 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1536 {
1537         pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1538 }
1539
1540 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1541 {
1542         pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1543 }
1544
1545 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1546 {
1547         pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1548 }
1549
1550 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1551 {
1552         pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1553 }
1554
1555 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1556 {
1557         PixbufRenderer *pr;
1558         gdouble zoom;
1559         gint width, height;
1560
1561         pr = (PixbufRenderer *)imd->pr;
1562
1563         if (!pixbuf_renderer_get_pixbuf(pr) ||
1564             !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1565
1566         if (vertical)
1567                 {
1568                 zoom = (gdouble)pr->window_height / height;
1569                 }
1570         else
1571                 {
1572                 zoom = (gdouble)pr->window_width / width;
1573                 }
1574
1575         if (zoom < 1.0)
1576                 {
1577                 zoom = 0.0 - 1.0 / zoom;
1578                 }
1579
1580         pixbuf_renderer_zoom_set(pr, zoom);
1581 }
1582
1583 gdouble image_zoom_get(ImageWindow *imd)
1584 {
1585         return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1586 }
1587
1588 gdouble image_zoom_get_real(ImageWindow *imd)
1589 {
1590         return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1591 }
1592
1593 gchar *image_zoom_get_as_text(ImageWindow *imd)
1594 {
1595         gdouble zoom;
1596         gdouble scale;
1597         gdouble l = 1.0;
1598         gdouble r = 1.0;
1599         gint pl = 0;
1600         gint pr = 0;
1601         gchar *approx = " ";
1602
1603         zoom = image_zoom_get(imd);
1604         scale = image_zoom_get_real(imd);
1605
1606         if (zoom > 0.0)
1607                 {
1608                 l = zoom;
1609                 }
1610         else if (zoom < 0.0)
1611                 {
1612                 r = 0.0 - zoom;
1613                 }
1614         else if (zoom == 0.0 && scale != 0.0)
1615                 {
1616                 if (scale >= 1.0)
1617                         {
1618                         l = scale;
1619                         }
1620                 else
1621                         {
1622                         r = 1.0 / scale;
1623                         }
1624                 approx = "~";
1625                 }
1626
1627         if (rint(l) != l) pl = 1;
1628         if (rint(r) != r) pr = 1;
1629
1630         return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1631 }
1632
1633 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1634 {
1635         gdouble zoom;
1636
1637         if (mode == ZOOM_RESET_ORIGINAL)
1638                 {
1639                 zoom = 1.0;
1640                 }
1641         else if (mode == ZOOM_RESET_FIT_WINDOW)
1642                 {
1643                 zoom = 0.0;
1644                 }
1645         else
1646                 {
1647                 if (imd)
1648                         {
1649                         zoom = image_zoom_get(imd);
1650                         }
1651                 else
1652                         {
1653                         zoom = 1.0;
1654                         }
1655                 }
1656
1657         return zoom;
1658 }
1659
1660 /* read ahead */
1661
1662 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1663 {
1664         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1665
1666         if (fd)
1667                 {
1668                 image_read_ahead_set(imd, fd);
1669                 }
1670         else
1671                 {
1672                 image_read_ahead_cancel(imd);
1673                 }
1674 }
1675
1676 static gint image_auto_refresh_cb(gpointer data)
1677 {
1678         ImageWindow *imd = data;
1679         time_t newtime;
1680
1681         if (!imd || !image_get_pixbuf(imd) ||
1682             imd->il || !imd->image_fd ||
1683             !options->update_on_time_change) return TRUE;
1684
1685         newtime = filetime(imd->image_fd->path);
1686         if (newtime > 0 && newtime != imd->mtime)
1687                 {
1688                 imd->mtime = newtime;
1689                 image_reload(imd);
1690                 }
1691
1692         return TRUE;
1693 }
1694
1695 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1696
1697 void image_auto_refresh(ImageWindow *imd, gint interval)
1698 {
1699         if (!imd) return;
1700         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1701
1702         if (imd->auto_refresh_id > -1)
1703                 {
1704                 g_source_remove(imd->auto_refresh_id);
1705                 imd->auto_refresh_id = -1;
1706                 imd->auto_refresh_interval = -1;
1707                 }
1708
1709         if (interval < 0) return;
1710
1711         if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1712
1713         imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1714         imd->auto_refresh_interval = interval;
1715 }
1716
1717 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1718 {
1719         imd->top_window_sync = allow_sync;
1720
1721         g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1722 }
1723
1724 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1725 {
1726         pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1727 }
1728
1729 void image_color_profile_set(ImageWindow *imd,
1730                              gint input_type, gint screen_type,
1731                              gint use_image)
1732 {
1733         if (!imd) return;
1734
1735         if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1736             screen_type < 0 || screen_type > 1)
1737                 {
1738                 return;
1739                 }
1740
1741         imd->color_profile_input = input_type;
1742         imd->color_profile_screen = screen_type;
1743         imd->color_profile_use_image = use_image;
1744 }
1745
1746 gint image_color_profile_get(ImageWindow *imd,
1747                              gint *input_type, gint *screen_type,
1748                              gint *use_image)
1749 {
1750         if (!imd) return FALSE;
1751
1752         if (input_type) *input_type = imd->color_profile_input;
1753         if (screen_type) *screen_type = imd->color_profile_screen;
1754         if (use_image) *use_image = imd->color_profile_use_image;
1755
1756         return TRUE;
1757 }
1758
1759 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1760 {
1761         if (!imd) return;
1762
1763         if (imd->color_profile_enable == enable) return;
1764
1765         imd->color_profile_enable = enable;
1766 }
1767
1768 gint image_color_profile_get_use(ImageWindow *imd)
1769 {
1770         if (!imd) return FALSE;
1771
1772         return imd->color_profile_enable;
1773 }
1774
1775 gint image_color_profile_get_from_image(ImageWindow *imd)
1776 {
1777         if (!imd) return FALSE;
1778
1779         return imd->color_profile_from_image;
1780 }
1781
1782 void image_set_delay_flip(ImageWindow *imd, gint delay)
1783 {
1784         if (!imd ||
1785             imd->delay_flip == delay) return;
1786
1787         imd->delay_flip = delay;
1788
1789         g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1790
1791         if (!imd->delay_flip && imd->il)
1792                 {
1793                 PixbufRenderer *pr;
1794
1795                 pr = PIXBUF_RENDERER(imd->pr);
1796                 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1797                 pr->pixbuf = NULL;
1798
1799                 image_load_pixbuf_ready(imd);
1800                 }
1801 }
1802
1803 void image_to_root_window(ImageWindow *imd, gint scaled)
1804 {
1805         GdkScreen *screen;
1806         GdkWindow *rootwindow;
1807         GdkPixmap *pixmap;
1808         GdkPixbuf *pixbuf;
1809         GdkPixbuf *pb;
1810         gint width, height;
1811
1812         if (!imd) return;
1813
1814         pixbuf = image_get_pixbuf(imd);
1815         if (!pixbuf) return;
1816
1817         screen = gtk_widget_get_screen(imd->widget);
1818         rootwindow = gdk_screen_get_root_window(screen);
1819         if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1820
1821         if (scaled)
1822                 {
1823                 width = gdk_screen_width();
1824                 height = gdk_screen_height();
1825                 }
1826         else
1827                 {
1828                 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1829                 }
1830
1831         pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1832
1833         gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1834         gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1835         gdk_window_clear(rootwindow);
1836         g_object_unref(pb);
1837         g_object_unref(pixmap);
1838
1839         gdk_flush();
1840 }
1841
1842 void image_select(ImageWindow *imd, gboolean select)
1843 {
1844         if (imd->has_frame)
1845                 {
1846                 if (select)
1847                         {
1848                         gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1849                         gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1850                         }
1851                 else
1852                         gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1853                 }
1854 }
1855
1856
1857
1858 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1859 {
1860         if (imd->has_frame)
1861                 {
1862                 if (selectable)
1863                         {
1864                         gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1865                         gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1866                         }
1867                 else
1868                         {
1869                         gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1870                         gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1871                         }
1872                 }
1873 }
1874
1875 /*
1876  *-------------------------------------------------------------------
1877  * prefs sync
1878  *-------------------------------------------------------------------
1879  */
1880
1881 static void image_options_set(ImageWindow *imd)
1882 {
1883         g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1884                                         "zoom_2pass", options->image.zoom_2pass,
1885                                         "zoom_expand", options->image.zoom_to_fit_allow_expand,
1886                                         "dither_quality", options->image.dither_quality,
1887                                         "scroll_reset", options->image.scroll_reset_method,
1888                                         "cache_display", options->image.tile_cache_max,
1889                                         "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1890                                         "window_limit", options->image.limit_window_size,
1891                                         "window_limit_value", options->image.max_window_size,
1892                                         "autofit_limit", options->image.limit_autofit_size,
1893                                         "autofit_limit_value", options->image.max_autofit_size,
1894
1895                                         NULL);
1896
1897         pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1898 }
1899
1900 void image_options_sync(void)
1901 {
1902         GList *work;
1903
1904         work = image_list;
1905         while (work)
1906                 {
1907                 ImageWindow *imd;
1908
1909                 imd = work->data;
1910                 work = work->next;
1911
1912                 image_options_set(imd);
1913                 }
1914 }
1915
1916 /*
1917  *-------------------------------------------------------------------
1918  * init / destroy
1919  *-------------------------------------------------------------------
1920  */
1921
1922 static void image_free(ImageWindow *imd)
1923 {
1924         image_list = g_list_remove(image_list, imd);
1925
1926         image_reset(imd);
1927
1928         image_read_ahead_cancel(imd);
1929         image_post_buffer_set(imd, NULL, NULL, -1);
1930         image_auto_refresh(imd, -1);
1931
1932         file_data_unref(imd->image_fd);
1933         g_free(imd->title);
1934         g_free(imd->title_right);
1935
1936         g_free(imd);
1937 }
1938
1939 static void image_destroy_cb(GtkObject *widget, gpointer data)
1940 {
1941         ImageWindow *imd = data;
1942         image_free(imd);
1943 }
1944
1945 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1946 {
1947         gtk_paint_flat_box(widget->style,
1948                            widget->window,
1949                            widget->state,
1950                            GTK_FRAME (widget)->shadow_type,
1951                            NULL,
1952                            widget,
1953                            NULL,
1954                            widget->allocation.x + 3, widget->allocation.y + 3,
1955                            widget->allocation.width - 6, widget->allocation.height - 6);
1956
1957
1958         return FALSE;
1959 }
1960
1961
1962 void image_set_frame(ImageWindow *imd, gboolean frame)
1963 {
1964         frame = !!frame;
1965
1966         if (frame == imd->has_frame) return;
1967
1968         gtk_widget_hide(imd->pr);
1969
1970         if (frame)
1971                 {
1972                 imd->frame = gtk_frame_new(NULL);
1973                 gtk_widget_ref(imd->pr);
1974                 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1975                 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1976                 gtk_widget_unref(imd->pr);
1977                 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1978                     G_CALLBACK (selectable_frame_expose_cb), NULL);
1979
1980                 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1981                 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1982                                  G_CALLBACK(image_focus_in_cb), imd);
1983                 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1984                                  G_CALLBACK(image_focus_out_cb), imd);
1985
1986                 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1987                                        G_CALLBACK(image_focus_expose), imd);
1988
1989
1990                 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1991                 gtk_widget_show(imd->frame);
1992                 }
1993         else
1994                 {
1995                 gtk_widget_ref(imd->pr);
1996                 if (imd->frame)
1997                         {
1998                         gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1999                         gtk_widget_destroy(imd->frame);
2000                         imd->frame = NULL;
2001                         }
2002                 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2003                 gtk_widget_unref(imd->pr);
2004                 }
2005
2006         gtk_widget_show(imd->pr);
2007
2008         imd->has_frame = frame;
2009 }
2010
2011 ImageWindow *image_new(gint frame)
2012 {
2013         ImageWindow *imd;
2014
2015         imd = g_new0(ImageWindow, 1);
2016
2017         imd->top_window = NULL;
2018         imd->title = NULL;
2019         imd->title_right = NULL;
2020         imd->title_show_zoom = FALSE;
2021
2022         imd->unknown = TRUE;
2023
2024         imd->has_frame = -1; /* not initialized; for image_set_frame */
2025         imd->top_window_sync = FALSE;
2026
2027         imd->delay_alter_type = ALTER_NONE;
2028
2029         imd->read_ahead_il = NULL;
2030         imd->read_ahead_pixbuf = NULL;
2031         imd->read_ahead_fd = NULL;
2032
2033         imd->completed = FALSE;
2034         imd->state = IMAGE_STATE_NONE;
2035
2036         imd->color_profile_enable = FALSE;
2037         imd->color_profile_input = 0;
2038         imd->color_profile_screen = 0;
2039         imd->color_profile_use_image = FALSE;
2040         imd->color_profile_from_image = COLOR_PROFILE_NONE;
2041
2042         imd->auto_refresh_id = -1;
2043         imd->auto_refresh_interval = -1;
2044
2045         imd->delay_flip = FALSE;
2046
2047         imd->func_update = NULL;
2048         imd->func_complete = NULL;
2049         imd->func_tile_request = NULL;
2050         imd->func_tile_dispose = NULL;
2051
2052         imd->func_button = NULL;
2053         imd->func_scroll = NULL;
2054
2055         imd->orientation = 1;
2056
2057         imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2058
2059         image_options_set(imd);
2060
2061
2062         imd->widget = gtk_vbox_new(0, 0);
2063
2064         image_set_frame(imd, frame);
2065
2066         image_set_selectable(imd, 0);
2067
2068         g_signal_connect(G_OBJECT(imd->pr), "clicked",
2069                          G_CALLBACK(image_click_cb), imd);
2070         g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2071                          G_CALLBACK(image_scroll_notify_cb), imd);
2072
2073         g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2074                          G_CALLBACK(image_scroll_cb), imd);
2075
2076         g_signal_connect(G_OBJECT(imd->pr), "destroy",
2077                          G_CALLBACK(image_destroy_cb), imd);
2078
2079         g_signal_connect(G_OBJECT(imd->pr), "zoom",
2080                          G_CALLBACK(image_zoom_cb), imd);
2081         g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2082                          G_CALLBACK(image_render_complete_cb), imd);
2083         g_signal_connect(G_OBJECT(imd->pr), "drag",
2084                          G_CALLBACK(image_drag_cb), imd);
2085
2086         image_list = g_list_append(image_list, imd);
2087
2088         return imd;
2089 }