Fix the case "orientation from FileData, color profile from exif".
[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
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, TRUE);
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, read_exif_for_color_profile);
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                         }
1324                 }
1325
1326         pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1327         if (imd->cm) 
1328                 {
1329                 color_man_free(imd->cm);
1330                 imd->cm = NULL;
1331                 }
1332
1333         pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1334         pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1335
1336         if (imd->color_profile_enable)
1337                 {
1338                 if (!image_post_process_color(imd, 0, exif, FALSE))
1339                         {
1340                         /* fixme: note error to user */
1341 //                      image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1342                         }
1343                 }
1344                 
1345         exif_free(exif);
1346
1347         if (imd->cm || imd->desaturate) 
1348                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1349                 
1350         image_state_set(imd, IMAGE_STATE_IMAGE);
1351 }
1352
1353 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1354 {
1355         if (!cd || !info || !g_list_find(cd->list, info)) return;
1356
1357         image_change_real(imd, info->fd, cd, info, zoom);
1358 }
1359
1360 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1361 {
1362         if (collection_to_number(imd->collection) >= 0)
1363                 {
1364                 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1365                         {
1366                         if (info) *info = imd->collection_info;
1367                         }
1368                 else
1369                         {
1370                         if (info) *info = NULL;
1371                         }
1372                 return imd->collection;
1373                 }
1374
1375         if (info) *info = NULL;
1376         return NULL;
1377 }
1378
1379 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1380 {
1381         /* change data for the callbacks directly */
1382
1383         il->data_area_ready = data;
1384         il->data_error = data;
1385         il->data_done = data;
1386         il->data_percent = data;
1387 }
1388
1389 /* this is more like a move function
1390  * it moves most data from source to imd
1391  */
1392 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1393 {
1394         if (imd == source) return;
1395
1396         imd->unknown = source->unknown;
1397
1398         imd->collection = source->collection;
1399         imd->collection_info = source->collection_info;
1400         imd->size = source->size;
1401         imd->mtime = source->mtime;
1402
1403         image_set_fd(imd, image_get_fd(source));
1404
1405         image_loader_free(imd->il);
1406         imd->il = NULL;
1407
1408         if (source->il)
1409                 {
1410                 imd->il = source->il;
1411                 source->il = NULL;
1412
1413                 image_loader_sync_data(imd->il, imd);
1414
1415                 imd->delay_alter_type = source->delay_alter_type;
1416                 source->delay_alter_type = ALTER_NONE;
1417                 }
1418
1419         imd->color_profile_enable = source->color_profile_enable;
1420         imd->color_profile_input = source->color_profile_input;
1421         imd->color_profile_screen = source->color_profile_screen;
1422         imd->color_profile_use_image = source->color_profile_use_image;
1423         color_man_free((ColorMan *)imd->cm);
1424         imd->cm = NULL;
1425         if (source->cm)
1426                 {
1427                 ColorMan *cm;
1428
1429                 imd->cm = source->cm;
1430                 source->cm = NULL;
1431
1432                 cm = (ColorMan *)imd->cm;
1433                 cm->imd = imd;
1434                 cm->func_done_data = imd;
1435                 }
1436
1437         image_loader_free(imd->read_ahead_il);
1438         imd->read_ahead_il = source->read_ahead_il;
1439         source->read_ahead_il = NULL;
1440         if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1441
1442         if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1443         imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1444         source->read_ahead_pixbuf = NULL;
1445
1446         file_data_unref(imd->read_ahead_fd);
1447         imd->read_ahead_fd = source->read_ahead_fd;
1448         source->read_ahead_fd = NULL;
1449
1450         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1451         imd->prev_pixbuf = source->prev_pixbuf;
1452         source->prev_pixbuf = NULL;
1453         imd->prev_color_row = source->prev_color_row;
1454         source->prev_color_row = -1;
1455
1456         file_data_unref(imd->prev_fd);
1457         imd->prev_fd = source->prev_fd;
1458         source->prev_fd = NULL;
1459
1460         imd->completed = source->completed;
1461         imd->state = source->state;
1462         source->state = IMAGE_STATE_NONE;
1463         
1464         imd->orientation = source->orientation;
1465         imd->desaturate = source->desaturate;
1466
1467         pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1468
1469         if (imd->cm || imd->desaturate) 
1470                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1471         else
1472                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1473
1474 }
1475
1476 /* manipulation */
1477
1478 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1479 {
1480         pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1481 }
1482
1483 void image_reload(ImageWindow *imd)
1484 {
1485         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1486
1487         image_change_complete(imd, image_zoom_get(imd), FALSE);
1488 }
1489
1490 void image_scroll(ImageWindow *imd, gint x, gint y)
1491 {
1492         pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1493 }
1494
1495 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1496                            gdouble x_align, gdouble y_align)
1497 {
1498         pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1499 }
1500
1501 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1502 {
1503         pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1504 }
1505
1506 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1507 {
1508         pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1509 }
1510
1511
1512 #if 0
1513 void image_alter(ImageWindow *imd, AlterType type)
1514 {
1515         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1516
1517         if (imd->il || imd->cm)
1518                 {
1519                 /* still loading, wait till done */
1520                 imd->delay_alter_type = type;
1521                 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1522
1523                 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1524                         {
1525                         image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1526                         }
1527                 return;
1528                 }
1529
1530         image_alter_real(imd, type, TRUE);
1531 }
1532 #endif
1533
1534 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1535 {
1536         pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1537 }
1538
1539 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1540 {
1541         pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1542 }
1543
1544 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1545 {
1546         pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1547 }
1548
1549 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1550 {
1551         pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1552 }
1553
1554 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1555 {
1556         PixbufRenderer *pr;
1557         gdouble zoom;
1558         gint width, height;
1559
1560         pr = (PixbufRenderer *)imd->pr;
1561
1562         if (!pixbuf_renderer_get_pixbuf(pr) ||
1563             !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1564
1565         if (vertical)
1566                 {
1567                 zoom = (gdouble)pr->window_height / height;
1568                 }
1569         else
1570                 {
1571                 zoom = (gdouble)pr->window_width / width;
1572                 }
1573
1574         if (zoom < 1.0)
1575                 {
1576                 zoom = 0.0 - 1.0 / zoom;
1577                 }
1578
1579         pixbuf_renderer_zoom_set(pr, zoom);
1580 }
1581
1582 gdouble image_zoom_get(ImageWindow *imd)
1583 {
1584         return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1585 }
1586
1587 gdouble image_zoom_get_real(ImageWindow *imd)
1588 {
1589         return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1590 }
1591
1592 gchar *image_zoom_get_as_text(ImageWindow *imd)
1593 {
1594         gdouble zoom;
1595         gdouble scale;
1596         gdouble l = 1.0;
1597         gdouble r = 1.0;
1598         gint pl = 0;
1599         gint pr = 0;
1600         gchar *approx = " ";
1601
1602         zoom = image_zoom_get(imd);
1603         scale = image_zoom_get_real(imd);
1604
1605         if (zoom > 0.0)
1606                 {
1607                 l = zoom;
1608                 }
1609         else if (zoom < 0.0)
1610                 {
1611                 r = 0.0 - zoom;
1612                 }
1613         else if (zoom == 0.0 && scale != 0.0)
1614                 {
1615                 if (scale >= 1.0)
1616                         {
1617                         l = scale;
1618                         }
1619                 else
1620                         {
1621                         r = 1.0 / scale;
1622                         }
1623                 approx = "~";
1624                 }
1625
1626         if (rint(l) != l) pl = 1;
1627         if (rint(r) != r) pr = 1;
1628
1629         return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1630 }
1631
1632 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1633 {
1634         gdouble zoom;
1635
1636         if (mode == ZOOM_RESET_ORIGINAL)
1637                 {
1638                 zoom = 1.0;
1639                 }
1640         else if (mode == ZOOM_RESET_FIT_WINDOW)
1641                 {
1642                 zoom = 0.0;
1643                 }
1644         else
1645                 {
1646                 if (imd)
1647                         {
1648                         zoom = image_zoom_get(imd);
1649                         }
1650                 else
1651                         {
1652                         zoom = 1.0;
1653                         }
1654                 }
1655
1656         return zoom;
1657 }
1658
1659 /* read ahead */
1660
1661 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1662 {
1663         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1664
1665         if (fd)
1666                 {
1667                 image_read_ahead_set(imd, fd);
1668                 }
1669         else
1670                 {
1671                 image_read_ahead_cancel(imd);
1672                 }
1673 }
1674
1675 static gint image_auto_refresh_cb(gpointer data)
1676 {
1677         ImageWindow *imd = data;
1678         time_t newtime;
1679         
1680         if (!imd || !image_get_pixbuf(imd) ||
1681             imd->il || !imd->image_fd ||
1682             !options->update_on_time_change) return TRUE;
1683
1684         newtime = filetime(imd->image_fd->path);
1685         if (newtime > 0 && newtime != imd->mtime)
1686                 {
1687                 imd->mtime = newtime;
1688                 image_reload(imd);
1689                 }
1690
1691         return TRUE;
1692 }
1693
1694 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1695
1696 void image_auto_refresh(ImageWindow *imd, gint interval)
1697 {
1698         if (!imd) return;
1699         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1700
1701         if (imd->auto_refresh_id > -1)
1702                 {
1703                 g_source_remove(imd->auto_refresh_id);
1704                 imd->auto_refresh_id = -1;
1705                 imd->auto_refresh_interval = -1;
1706                 }
1707
1708         if (interval < 0) return;
1709
1710         if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1711
1712         imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1713         imd->auto_refresh_interval = interval;
1714 }
1715
1716 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1717 {
1718         imd->top_window_sync = allow_sync;
1719
1720         g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1721 }
1722
1723 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1724 {
1725         pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1726 }
1727
1728 void image_color_profile_set(ImageWindow *imd,
1729                              gint input_type, gint screen_type,
1730                              gint use_image)
1731 {
1732         if (!imd) return;
1733
1734         if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1735             screen_type < 0 || screen_type > 1)
1736                 {
1737                 return;
1738                 }
1739
1740         imd->color_profile_input = input_type;
1741         imd->color_profile_screen = screen_type;
1742         imd->color_profile_use_image = use_image;
1743 }
1744
1745 gint image_color_profile_get(ImageWindow *imd,
1746                              gint *input_type, gint *screen_type,
1747                              gint *use_image)
1748 {
1749         if (!imd) return FALSE;
1750
1751         if (input_type) *input_type = imd->color_profile_input;
1752         if (screen_type) *screen_type = imd->color_profile_screen;
1753         if (use_image) *use_image = imd->color_profile_use_image;
1754
1755         return TRUE;
1756 }
1757
1758 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1759 {
1760         if (!imd) return;
1761
1762         if (imd->color_profile_enable == enable) return;
1763
1764         imd->color_profile_enable = enable;
1765 }
1766
1767 gint image_color_profile_get_use(ImageWindow *imd)
1768 {
1769         if (!imd) return FALSE;
1770
1771         return imd->color_profile_enable;
1772 }
1773
1774 gint image_color_profile_get_from_image(ImageWindow *imd)
1775 {
1776         if (!imd) return FALSE;
1777
1778         return imd->color_profile_from_image;
1779 }
1780
1781 void image_set_delay_flip(ImageWindow *imd, gint delay)
1782 {
1783         if (!imd ||
1784             imd->delay_flip == delay) return;
1785
1786         imd->delay_flip = delay;
1787
1788         g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1789
1790         if (!imd->delay_flip && imd->il)
1791                 {
1792                 PixbufRenderer *pr;
1793
1794                 pr = PIXBUF_RENDERER(imd->pr);
1795                 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1796                 pr->pixbuf = NULL;
1797
1798                 image_load_pixbuf_ready(imd);
1799                 }
1800 }
1801
1802 void image_to_root_window(ImageWindow *imd, gint scaled)
1803 {
1804         GdkScreen *screen;
1805         GdkWindow *rootwindow;
1806         GdkPixmap *pixmap;
1807         GdkPixbuf *pixbuf;
1808         GdkPixbuf *pb;
1809         gint width, height;
1810
1811         if (!imd) return;
1812
1813         pixbuf = image_get_pixbuf(imd);
1814         if (!pixbuf) return;
1815
1816         screen = gtk_widget_get_screen(imd->widget);
1817         rootwindow = gdk_screen_get_root_window(screen);
1818         if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1819
1820         if (scaled)
1821                 {
1822                 width = gdk_screen_width();
1823                 height = gdk_screen_height();
1824                 }
1825         else
1826                 {
1827                 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1828                 }
1829
1830         pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1831
1832         gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1833         gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1834         gdk_window_clear(rootwindow);
1835         g_object_unref(pb);
1836         g_object_unref(pixmap);
1837
1838         gdk_flush();
1839 }
1840
1841 void image_select(ImageWindow *imd, gboolean select)
1842 {
1843         if (imd->has_frame)
1844                 {
1845                 if (select) 
1846                         {
1847                         gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1848                         gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1849                         }
1850                 else
1851                         gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1852                 }
1853 }
1854
1855
1856
1857 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1858 {
1859         if (imd->has_frame)
1860                 {
1861                 if (selectable) 
1862                         {
1863                         gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1864                         gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1865                         }
1866                 else
1867                         {
1868                         gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1869                         gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1870                         }
1871                 }
1872 }
1873
1874 /*
1875  *-------------------------------------------------------------------
1876  * prefs sync
1877  *-------------------------------------------------------------------
1878  */
1879
1880 static void image_options_set(ImageWindow *imd)
1881 {
1882         g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1883                                         "zoom_2pass", options->image.zoom_2pass,
1884                                         "zoom_expand", options->image.zoom_to_fit_allow_expand,
1885                                         "dither_quality", options->image.dither_quality,
1886                                         "scroll_reset", options->image.scroll_reset_method,
1887                                         "cache_display", options->image.tile_cache_max,
1888                                         "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1889                                         "window_limit", options->image.limit_window_size,
1890                                         "window_limit_value", options->image.max_window_size,
1891                                         "autofit_limit", options->image.limit_autofit_size,
1892                                         "autofit_limit_value", options->image.max_autofit_size,
1893
1894                                         NULL);
1895
1896         pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1897 }
1898
1899 void image_options_sync(void)
1900 {
1901         GList *work;
1902
1903         work = image_list;
1904         while (work)
1905                 {
1906                 ImageWindow *imd;
1907
1908                 imd = work->data;
1909                 work = work->next;
1910
1911                 image_options_set(imd);
1912                 }
1913 }
1914
1915 /*
1916  *-------------------------------------------------------------------
1917  * init / destroy
1918  *-------------------------------------------------------------------
1919  */
1920
1921 static void image_free(ImageWindow *imd)
1922 {
1923         image_list = g_list_remove(image_list, imd);
1924
1925         image_reset(imd);
1926
1927         image_read_ahead_cancel(imd);
1928         image_post_buffer_set(imd, NULL, NULL, -1);
1929         image_auto_refresh(imd, -1);
1930
1931         file_data_unref(imd->image_fd);
1932         g_free(imd->title);
1933         g_free(imd->title_right);
1934
1935         g_free(imd);
1936 }
1937
1938 static void image_destroy_cb(GtkObject *widget, gpointer data)
1939 {
1940         ImageWindow *imd = data;
1941         image_free(imd);
1942 }
1943
1944 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1945 {
1946         gtk_paint_flat_box(widget->style,
1947                            widget->window,
1948                            widget->state,
1949                            GTK_FRAME (widget)->shadow_type,
1950                            NULL,
1951                            widget,
1952                            NULL,
1953                            widget->allocation.x + 3, widget->allocation.y + 3, 
1954                            widget->allocation.width - 6, widget->allocation.height - 6); 
1955  
1956  
1957         return FALSE;
1958 }
1959
1960
1961 void image_set_frame(ImageWindow *imd, gboolean frame)
1962 {
1963         frame = !!frame;
1964         
1965         if (frame == imd->has_frame) return;
1966         
1967         gtk_widget_hide(imd->pr);
1968         
1969         if (frame)
1970                 {
1971                 imd->frame = gtk_frame_new(NULL);
1972                 gtk_widget_ref(imd->pr);
1973                 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1974                 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1975                 gtk_widget_unref(imd->pr);
1976                 g_signal_connect (G_OBJECT (imd->frame), "expose_event",  
1977                     G_CALLBACK (selectable_frame_expose_cb), NULL);
1978
1979                 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1980                 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1981                                  G_CALLBACK(image_focus_in_cb), imd);
1982                 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1983                                  G_CALLBACK(image_focus_out_cb), imd);
1984
1985                 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1986                                        G_CALLBACK(image_focus_expose), imd);
1987
1988
1989                 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1990                 gtk_widget_show(imd->frame);
1991                 }
1992         else
1993                 {
1994                 gtk_widget_ref(imd->pr);
1995                 if (imd->frame) 
1996                         {
1997                         gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1998                         gtk_widget_destroy(imd->frame);
1999                         imd->frame = NULL;
2000                         }
2001                 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2002                 gtk_widget_unref(imd->pr);
2003                 }
2004
2005         gtk_widget_show(imd->pr);
2006         
2007         imd->has_frame = frame;
2008 }
2009
2010 ImageWindow *image_new(gint frame)
2011 {
2012         ImageWindow *imd;
2013
2014         imd = g_new0(ImageWindow, 1);
2015
2016         imd->top_window = NULL;
2017         imd->title = NULL;
2018         imd->title_right = NULL;
2019         imd->title_show_zoom = FALSE;
2020
2021         imd->unknown = TRUE;
2022
2023         imd->has_frame = -1; /* not initialized; for image_set_frame */
2024         imd->top_window_sync = FALSE;
2025
2026         imd->delay_alter_type = ALTER_NONE;
2027
2028         imd->read_ahead_il = NULL;
2029         imd->read_ahead_pixbuf = NULL;
2030         imd->read_ahead_fd = NULL;
2031
2032         imd->completed = FALSE;
2033         imd->state = IMAGE_STATE_NONE;
2034
2035         imd->color_profile_enable = FALSE;
2036         imd->color_profile_input = 0;
2037         imd->color_profile_screen = 0;
2038         imd->color_profile_use_image = FALSE;
2039         imd->color_profile_from_image = COLOR_PROFILE_NONE;
2040
2041         imd->auto_refresh_id = -1;
2042         imd->auto_refresh_interval = -1;
2043
2044         imd->delay_flip = FALSE;
2045
2046         imd->func_update = NULL;
2047         imd->func_complete = NULL;
2048         imd->func_tile_request = NULL;
2049         imd->func_tile_dispose = NULL;
2050
2051         imd->func_button = NULL;
2052         imd->func_scroll = NULL;
2053         
2054         imd->orientation = 1;
2055
2056         imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2057
2058         image_options_set(imd);
2059
2060         
2061         imd->widget = gtk_vbox_new(0, 0);
2062
2063         image_set_frame(imd, frame);
2064
2065         image_set_selectable(imd, 0);
2066
2067         g_signal_connect(G_OBJECT(imd->pr), "clicked",
2068                          G_CALLBACK(image_click_cb), imd);
2069         g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2070                          G_CALLBACK(image_scroll_notify_cb), imd);
2071
2072         g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2073                          G_CALLBACK(image_scroll_cb), imd);
2074
2075         g_signal_connect(G_OBJECT(imd->pr), "destroy",
2076                          G_CALLBACK(image_destroy_cb), imd);
2077
2078         g_signal_connect(G_OBJECT(imd->pr), "zoom",
2079                          G_CALLBACK(image_zoom_cb), imd);
2080         g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2081                          G_CALLBACK(image_render_complete_cb), imd);
2082         g_signal_connect(G_OBJECT(imd->pr), "drag",
2083                          G_CALLBACK(image_drag_cb), imd);
2084
2085         image_list = g_list_append(image_list, imd);
2086
2087         return imd;
2088 }
2089