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