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