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