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