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