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