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