Add a way to restore original state in Adjust menu.
[geeqie.git] / src / image.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12
13 #include "main.h"
14 #include "image.h"
15
16
17 #include "image-load.h"
18 #include "collect.h"
19 #include "color-man.h"
20 #include "exif.h"
21 #include "image-overlay.h"
22 #include "layout.h"
23 #include "layout_image.h"
24 #include "pixbuf-renderer.h"
25 #include "pixbuf_util.h"
26 #include "ui_fileops.h"
27
28 #include "filelist.h"
29
30 #include <math.h>
31
32
33 /* size of the image loader buffer (512 bytes x defined number) */
34 #define IMAGE_LOAD_BUFFER_COUNT 8
35
36 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
37 #define IMAGE_THROTTLE_LARGER_IMAGES 1
38
39 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
40 #define IMAGE_THROTTLE_FACTOR 32
41
42 /* the file size at which throttling take place */
43 #define IMAGE_THROTTLE_THRESHOLD 1048576
44
45 #define IMAGE_AUTO_REFRESH_TIME 3000
46
47
48 static GList *image_list = NULL;
49
50
51 static void image_update_title(ImageWindow *imd);
52 static void image_post_process(ImageWindow *imd, gint clamp);
53 static void image_read_ahead_start(ImageWindow *imd);
54
55 /*
56  *-------------------------------------------------------------------
57  * 'signals'
58  *-------------------------------------------------------------------
59  */
60
61 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
62 {
63         ImageWindow *imd = data;
64
65         if (imd->func_button)
66                 {
67                 imd->func_button(imd, event->button, event->time,
68                                  event->x, event->y, event->state, imd->data_button);
69                 }
70 }
71
72 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
73 {
74         ImageWindow *imd = data;
75         gint width, height;
76
77         pixbuf_renderer_get_scaled_size(pr, &width, &height);
78         
79         if (imd->func_drag)
80                 {
81                 imd->func_drag(imd, event->button, event->time,
82                                  event->x, event->y, event->state,
83                                  (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
84                                  imd->data_button);
85                 }
86 }
87
88 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
89 {
90         ImageWindow *imd = data;
91
92         if (imd->func_scroll_notify && pr->scale)
93                 {
94                 imd->func_scroll_notify(imd,
95                                         (gint)((gdouble)pr->x_scroll / pr->scale),
96                                         (gint)((gdouble)pr->y_scroll / pr->scale),
97                                         (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
98                                         (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
99                                         imd->data_scroll_notify);
100                 }
101 }
102
103 static void image_update_util(ImageWindow *imd)
104 {
105         if (imd->func_update) imd->func_update(imd, imd->data_update);
106 }
107
108 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
109 {
110         ImageWindow *imd = data;
111
112         if (imd->title_show_zoom) image_update_title(imd);
113         if (imd->overlay_show_zoom) image_osd_update(imd);
114
115         image_update_util(imd);
116 }
117
118 static void image_complete_util(ImageWindow *imd, gint preload)
119 {
120         if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
121
122         if (debug) printf("%s image load completed \"%s\" (%s)\n", get_exec_time(),
123                           (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") : 
124                                       (imd->image_fd ? imd->image_fd->path : "null"),
125                           (preload) ? "preload" : "current");
126
127         if (!preload) imd->completed = TRUE;
128         if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
129 }
130
131 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
132 {
133         ImageWindow *imd = data;
134
135         image_complete_util(imd, FALSE);
136 }
137
138 static void image_state_set(ImageWindow *imd, ImageState state)
139 {
140         if (state == IMAGE_STATE_NONE)
141                 {
142                 imd->state = state;
143                 }
144         else
145                 {
146                 imd->state |= state;
147                 }
148         if (imd->func_state) imd->func_state(imd, state, imd->data_state);
149 }
150
151 static void image_state_unset(ImageWindow *imd, ImageState state)
152 {
153         imd->state &= ~state;
154         if (imd->func_state) imd->func_state(imd, state, imd->data_state);
155 }
156
157 /*
158  *-------------------------------------------------------------------
159  * misc
160  *-------------------------------------------------------------------
161  */
162
163 static void image_update_title(ImageWindow *imd)
164 {
165         gchar *title = NULL;
166         gchar *zoom = NULL;
167         gchar *collection = NULL;
168
169         if (!imd->top_window) return;
170
171         if (imd->collection && collection_to_number(imd->collection) >= 0)
172                 {
173                 const gchar *name;
174                 name = imd->collection->name;
175                 if (!name) name = _("Untitled");
176                 collection = g_strdup_printf(" (Collection %s)", name);
177                 }
178
179         if (imd->title_show_zoom)
180                 {
181                 gchar *buf = image_zoom_get_as_text(imd);
182                 zoom = g_strconcat(" [", buf, "]", NULL);
183                 g_free(buf);
184                 }
185
186         title = g_strdup_printf("%s%s%s%s%s%s",
187                 imd->title ? imd->title : "",
188                 imd->image_fd ? imd->image_fd->name : "",
189                 zoom ? zoom : "",
190                 collection ? collection : "",
191                 imd->image_fd ? " - " : "",
192                 imd->title_right ? imd->title_right : "");
193
194         gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
195
196         g_free(title);
197         g_free(zoom);
198         g_free(collection);
199 }
200
201 /*
202  *-------------------------------------------------------------------
203  * rotation, flip, etc.
204  *-------------------------------------------------------------------
205  */
206
207
208 #if 0
209
210 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
211 {
212         PixbufRenderer *pr;
213         GdkPixbuf *new = NULL;
214         gint exif_rotate;
215         gint x, y;
216         gint t;
217
218         pr = (PixbufRenderer *)imd->pr;
219
220         exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
221         imd->delay_alter_type = ALTER_NONE;
222
223         if (!pr->pixbuf) return;
224
225         x = pr->x_scroll + (pr->vis_width / 2);
226         y = pr->y_scroll + (pr->vis_height / 2);
227
228         switch (type)
229                 {
230                 case ALTER_ROTATE_90:
231                         new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
232                         t = x;
233                         x = pr->height - y;
234                         y = t;
235                         break;
236                 case ALTER_ROTATE_90_CC:
237                         new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
238                         t = x;
239                         x = y;
240                         y = pr->width - t;
241                         break;
242                 case ALTER_ROTATE_180:
243                         new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
244                         x = pr->width - x;
245                         y = pr->height - y;
246                         break;
247                 case ALTER_MIRROR:
248                         new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
249                         x = pr->width - x;
250                         break;
251                 case ALTER_FLIP:
252                         new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
253                         y = pr->height - y;
254                         break;
255                 case ALTER_DESATURATE:
256                         pixbuf_desaturate_rect(pr->pixbuf,
257                                                0, 0,  pr->image_width, pr->image_height);
258                         image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
259                         layout_image_overlay_update(layout_find_by_image(imd));
260                         break;
261                 case ALTER_NONE:
262                 default:
263                         return;
264                         break;
265                 }
266
267         if (!new) return;
268
269         pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
270         g_object_unref(new);
271
272         if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
273                 {
274                 if (exif_rotate)
275                         {
276                         switch (pr->scroll_reset)
277                                 {
278                                 case PR_SCROLL_RESET_NOCHANGE:
279                                         break;
280                                 case PR_SCROLL_RESET_CENTER:
281                                         x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
282                                         y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
283                                         break;
284                                 case PR_SCROLL_RESET_TOPLEFT:
285                                 default:
286                                         x = 0;
287                                         y = 0;
288                                         break;
289                                 }
290                         }
291                 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
292                                                     (gint)((gdouble)y / pr->scale),
293                                                     0.50, 0.50);
294                 }
295
296         if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
297         layout_image_overlay_update(layout_find_by_image(imd));
298         if (debug) printf("%s image postprocess done: %s\n", get_exec_time(), imd->image_fd->name);
299 }
300
301 static void image_post_process_alter(ImageWindow *imd, gint clamp)
302 {
303         if (imd->delay_alter_type != ALTER_NONE)
304                 {
305                 image_alter_real(imd, imd->delay_alter_type, clamp);
306                 }
307 }
308
309
310 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
311 {
312         ImageWindow *imd = data;
313
314         color_man_free(cm);
315         if (type == COLOR_RETURN_IMAGE_CHANGED)
316                 {
317                 if (cm == imd->cm) imd->cm = NULL;
318                 return;
319                 }
320
321         imd->cm = NULL;
322         image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
323         if (debug) printf("%s image postprocess cm done: %s\n", get_exec_time(), imd->image_fd->name);
324
325         image_post_process_alter(imd, FALSE);
326
327         image_read_ahead_start(imd);
328 }
329 #endif
330
331 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg)
332 {
333         ColorMan *cm;
334         ColorManProfileType input_type;
335         ColorManProfileType screen_type;
336         const gchar *input_file;
337         const gchar *screen_file;
338         ExifItem *item = NULL;
339
340         if (imd->cm) return FALSE;
341
342         if (imd->color_profile_input >= COLOR_PROFILE_FILE &&
343             imd->color_profile_input <  COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS)
344                 {
345                 gint n;
346
347                 n = imd->color_profile_input - COLOR_PROFILE_FILE;
348                 if (!options->color_profile.input_file[n]) return FALSE;
349
350                 input_type = COLOR_PROFILE_FILE;
351                 input_file = options->color_profile.input_file[n];
352                 }
353         else if (imd->color_profile_input >= COLOR_PROFILE_SRGB && 
354                  imd->color_profile_input <  COLOR_PROFILE_FILE)
355                 {
356                 input_type = imd->color_profile_input;
357                 input_file = NULL;
358                 }
359         else
360                 {
361                 return FALSE;
362                 }
363
364         if (imd->color_profile_screen == 1 &&
365             options->color_profile.screen_file)
366                 {
367                 screen_type = COLOR_PROFILE_FILE;
368                 screen_file = options->color_profile.screen_file;
369                 }
370         else if (imd->color_profile_screen == 0)
371                 {
372                 screen_type = COLOR_PROFILE_SRGB;
373                 screen_file = NULL;
374                 }
375         else
376                 {
377                 return FALSE;
378                 }
379         imd->color_profile_from_image = COLOR_PROFILE_NONE;
380
381         if (imd->color_profile_use_image && exif)
382                 {
383                 item = exif_get_item(exif, "Exif.Image.InterColorProfile");
384                 if (!item)
385                         {
386                         gint cs;
387                         gchar *interop_index;
388
389                         /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
390                         if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
391                         interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");                  
392                         
393                         if (cs == 1)
394                                 {
395                                 input_type = COLOR_PROFILE_SRGB;
396                                 input_file = NULL;
397                                 imd->color_profile_from_image = COLOR_PROFILE_SRGB;
398
399                                 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
400                                 }
401                         if (cs == 2 || (interop_index && !strcmp(interop_index, "R03")))
402                                 {
403                                 input_type = COLOR_PROFILE_ADOBERGB;
404                                 input_file = NULL;
405                                 imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB;
406
407                                 if (debug) printf("Found EXIF ColorSpace of AdobeRGB\n");
408                                 }
409                                 
410                         g_free(interop_index);
411                         }
412                 }
413
414         if (item && exif_item_get_format_id(item) == EXIF_FORMAT_UNDEFINED)
415                 {
416                 unsigned char *data;
417                 guint data_len;
418                 if (debug) printf("Found embedded color profile\n");
419                 imd->color_profile_from_image = COLOR_PROFILE_MEM;
420                 
421                 data = (unsigned char *) exif_item_get_data(item, &data_len);
422
423                 cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL,
424                                             data, data_len,
425                                             screen_type, screen_file);
426                 g_free(data);
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         if (debug) printf("%s image postprocess: %s\n", 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, (imd->color_profile_enable && imd->color_profile_use_image));
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         if (debug) printf("%s read ahead cancelled for :%s\n", 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         if (debug) printf("%s read ahead done for :%s\n", 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         if (debug) printf("%s read ahead started for :%s\n", 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         if (debug) printf("read ahead set to :%s\n", 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         if (debug) printf("%s post buffer set: %s\n", 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, TRUE);
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         if (debug) printf ("%s image done\n", 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         if (debug) printf ("%s image error\n", 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         if (debug) printf ("%s image begin \n", 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                 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
902                 return TRUE;
903                 }
904
905         if (image_read_ahead_check(imd))
906                 {
907                 if (debug) printf("from read ahead buffer: %s\n", 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                 if (debug) printf("image start error\n");
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         if (debug) printf("%s image reset\n", 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 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1298 {
1299         return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1300 }
1301
1302 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1303 {
1304
1305         ExifData *exif = NULL;
1306         gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
1307         gint read_exif_for_orientation = FALSE;
1308
1309         if (imd->image_fd && imd->image_fd->user_orientation)
1310                 imd->orientation = imd->image_fd->user_orientation;
1311         else if (options->image.exif_rotate_enable)
1312                 read_exif_for_orientation = TRUE;
1313         
1314         if (read_exif_for_color_profile || read_exif_for_orientation)
1315                 {
1316                 gint orientation;
1317
1318                 exif = exif_read_fd(imd->image_fd, read_exif_for_color_profile);
1319                 
1320                 if (exif && read_exif_for_orientation)
1321                         {
1322                         if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
1323                                 imd->orientation = orientation;
1324                         else
1325                                 imd->orientation = 1;
1326                         imd->image_fd->exif_orientation = imd->orientation;
1327                         }
1328                 }
1329
1330         pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE);
1331         if (imd->cm) 
1332                 {
1333                 color_man_free(imd->cm);
1334                 imd->cm = NULL;
1335                 }
1336
1337         pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1338         pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
1339
1340         if (imd->color_profile_enable)
1341                 {
1342                 if (!image_post_process_color(imd, 0, exif, FALSE))
1343                         {
1344                         /* fixme: note error to user */
1345 //                      image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
1346                         }
1347                 }
1348                 
1349         exif_free(exif);
1350
1351         if (imd->cm || imd->desaturate) 
1352                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1353                 
1354         image_state_set(imd, IMAGE_STATE_IMAGE);
1355 }
1356
1357 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1358 {
1359         if (!cd || !info || !g_list_find(cd->list, info)) return;
1360
1361         image_change_real(imd, info->fd, cd, info, zoom);
1362 }
1363
1364 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1365 {
1366         if (collection_to_number(imd->collection) >= 0)
1367                 {
1368                 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1369                         {
1370                         if (info) *info = imd->collection_info;
1371                         }
1372                 else
1373                         {
1374                         if (info) *info = NULL;
1375                         }
1376                 return imd->collection;
1377                 }
1378
1379         if (info) *info = NULL;
1380         return NULL;
1381 }
1382
1383 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1384 {
1385         /* change data for the callbacks directly */
1386
1387         il->data_area_ready = data;
1388         il->data_error = data;
1389         il->data_done = data;
1390         il->data_percent = data;
1391 }
1392
1393 /* this is more like a move function
1394  * it moves most data from source to imd
1395  */
1396 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1397 {
1398         if (imd == source) return;
1399
1400         imd->unknown = source->unknown;
1401
1402         imd->collection = source->collection;
1403         imd->collection_info = source->collection_info;
1404         imd->size = source->size;
1405         imd->mtime = source->mtime;
1406
1407         image_set_fd(imd, image_get_fd(source));
1408
1409         image_loader_free(imd->il);
1410         imd->il = NULL;
1411
1412         if (source->il)
1413                 {
1414                 imd->il = source->il;
1415                 source->il = NULL;
1416
1417                 image_loader_sync_data(imd->il, imd);
1418
1419                 imd->delay_alter_type = source->delay_alter_type;
1420                 source->delay_alter_type = ALTER_NONE;
1421                 }
1422
1423         imd->color_profile_enable = source->color_profile_enable;
1424         imd->color_profile_input = source->color_profile_input;
1425         imd->color_profile_screen = source->color_profile_screen;
1426         imd->color_profile_use_image = source->color_profile_use_image;
1427         color_man_free((ColorMan *)imd->cm);
1428         imd->cm = NULL;
1429         if (source->cm)
1430                 {
1431                 ColorMan *cm;
1432
1433                 imd->cm = source->cm;
1434                 source->cm = NULL;
1435
1436                 cm = (ColorMan *)imd->cm;
1437                 cm->imd = imd;
1438                 cm->func_done_data = imd;
1439                 }
1440
1441         image_loader_free(imd->read_ahead_il);
1442         imd->read_ahead_il = source->read_ahead_il;
1443         source->read_ahead_il = NULL;
1444         if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1445
1446         if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1447         imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1448         source->read_ahead_pixbuf = NULL;
1449
1450         file_data_unref(imd->read_ahead_fd);
1451         imd->read_ahead_fd = source->read_ahead_fd;
1452         source->read_ahead_fd = NULL;
1453
1454         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1455         imd->prev_pixbuf = source->prev_pixbuf;
1456         source->prev_pixbuf = NULL;
1457         imd->prev_color_row = source->prev_color_row;
1458         source->prev_color_row = -1;
1459
1460         file_data_unref(imd->prev_fd);
1461         imd->prev_fd = source->prev_fd;
1462         source->prev_fd = NULL;
1463
1464         imd->completed = source->completed;
1465         imd->state = source->state;
1466         source->state = IMAGE_STATE_NONE;
1467         
1468         imd->orientation = source->orientation;
1469         imd->desaturate = source->desaturate;
1470
1471         pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1472
1473         if (imd->cm || imd->desaturate) 
1474                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
1475         else
1476                 pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE);
1477
1478 }
1479
1480 /* manipulation */
1481
1482 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1483 {
1484         pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1485 }
1486
1487 void image_reload(ImageWindow *imd)
1488 {
1489         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1490
1491         image_change_complete(imd, image_zoom_get(imd), FALSE);
1492 }
1493
1494 void image_scroll(ImageWindow *imd, gint x, gint y)
1495 {
1496         pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1497 }
1498
1499 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1500                            gdouble x_align, gdouble y_align)
1501 {
1502         pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1503 }
1504
1505 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1506 {
1507         pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1508 }
1509
1510 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1511 {
1512         pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1513 }
1514
1515
1516 #if 0
1517 void image_alter(ImageWindow *imd, AlterType type)
1518 {
1519         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1520
1521         if (imd->il || imd->cm)
1522                 {
1523                 /* still loading, wait till done */
1524                 imd->delay_alter_type = type;
1525                 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1526
1527                 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1528                         {
1529                         image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1530                         }
1531                 return;
1532                 }
1533
1534         image_alter_real(imd, type, TRUE);
1535 }
1536 #endif
1537
1538 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1539 {
1540         pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1541 }
1542
1543 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1544 {
1545         pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1546 }
1547
1548 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1549 {
1550         pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1551 }
1552
1553 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1554 {
1555         pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1556 }
1557
1558 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1559 {
1560         PixbufRenderer *pr;
1561         gdouble zoom;
1562         gint width, height;
1563
1564         pr = (PixbufRenderer *)imd->pr;
1565
1566         if (!pixbuf_renderer_get_pixbuf(pr) ||
1567             !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1568
1569         if (vertical)
1570                 {
1571                 zoom = (gdouble)pr->window_height / height;
1572                 }
1573         else
1574                 {
1575                 zoom = (gdouble)pr->window_width / width;
1576                 }
1577
1578         if (zoom < 1.0)
1579                 {
1580                 zoom = 0.0 - 1.0 / zoom;
1581                 }
1582
1583         pixbuf_renderer_zoom_set(pr, zoom);
1584 }
1585
1586 gdouble image_zoom_get(ImageWindow *imd)
1587 {
1588         return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1589 }
1590
1591 gdouble image_zoom_get_real(ImageWindow *imd)
1592 {
1593         return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1594 }
1595
1596 gchar *image_zoom_get_as_text(ImageWindow *imd)
1597 {
1598         gdouble zoom;
1599         gdouble scale;
1600         gdouble l = 1.0;
1601         gdouble r = 1.0;
1602         gint pl = 0;
1603         gint pr = 0;
1604         gchar *approx = " ";
1605
1606         zoom = image_zoom_get(imd);
1607         scale = image_zoom_get_real(imd);
1608
1609         if (zoom > 0.0)
1610                 {
1611                 l = zoom;
1612                 }
1613         else if (zoom < 0.0)
1614                 {
1615                 r = 0.0 - zoom;
1616                 }
1617         else if (zoom == 0.0 && scale != 0.0)
1618                 {
1619                 if (scale >= 1.0)
1620                         {
1621                         l = scale;
1622                         }
1623                 else
1624                         {
1625                         r = 1.0 / scale;
1626                         }
1627                 approx = "~";
1628                 }
1629
1630         if (rint(l) != l) pl = 1;
1631         if (rint(r) != r) pr = 1;
1632
1633         return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1634 }
1635
1636 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1637 {
1638         gdouble zoom;
1639
1640         if (mode == ZOOM_RESET_ORIGINAL)
1641                 {
1642                 zoom = 1.0;
1643                 }
1644         else if (mode == ZOOM_RESET_FIT_WINDOW)
1645                 {
1646                 zoom = 0.0;
1647                 }
1648         else
1649                 {
1650                 if (imd)
1651                         {
1652                         zoom = image_zoom_get(imd);
1653                         }
1654                 else
1655                         {
1656                         zoom = 1.0;
1657                         }
1658                 }
1659
1660         return zoom;
1661 }
1662
1663 /* read ahead */
1664
1665 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1666 {
1667         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1668
1669         if (fd)
1670                 {
1671                 image_read_ahead_set(imd, fd);
1672                 }
1673         else
1674                 {
1675                 image_read_ahead_cancel(imd);
1676                 }
1677 }
1678
1679 static gint image_auto_refresh_cb(gpointer data)
1680 {
1681         ImageWindow *imd = data;
1682         time_t newtime;
1683         
1684         if (!imd || !image_get_pixbuf(imd) ||
1685             imd->il || !imd->image_fd ||
1686             !options->update_on_time_change) return TRUE;
1687
1688         newtime = filetime(imd->image_fd->path);
1689         if (newtime > 0 && newtime != imd->mtime)
1690                 {
1691                 imd->mtime = newtime;
1692                 image_reload(imd);
1693                 }
1694
1695         return TRUE;
1696 }
1697
1698 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1699
1700 void image_auto_refresh(ImageWindow *imd, gint interval)
1701 {
1702         if (!imd) return;
1703         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1704
1705         if (imd->auto_refresh_id > -1)
1706                 {
1707                 g_source_remove(imd->auto_refresh_id);
1708                 imd->auto_refresh_id = -1;
1709                 imd->auto_refresh_interval = -1;
1710                 }
1711
1712         if (interval < 0) return;
1713
1714         if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1715
1716         imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1717         imd->auto_refresh_interval = interval;
1718 }
1719
1720 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1721 {
1722         imd->top_window_sync = allow_sync;
1723
1724         g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1725 }
1726
1727 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1728 {
1729         pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1730 }
1731
1732 void image_color_profile_set(ImageWindow *imd,
1733                              gint input_type, gint screen_type,
1734                              gint use_image)
1735 {
1736         if (!imd) return;
1737
1738         if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS ||
1739             screen_type < 0 || screen_type > 1)
1740                 {
1741                 return;
1742                 }
1743
1744         imd->color_profile_input = input_type;
1745         imd->color_profile_screen = screen_type;
1746         imd->color_profile_use_image = use_image;
1747 }
1748
1749 gint image_color_profile_get(ImageWindow *imd,
1750                              gint *input_type, gint *screen_type,
1751                              gint *use_image)
1752 {
1753         if (!imd) return FALSE;
1754
1755         if (input_type) *input_type = imd->color_profile_input;
1756         if (screen_type) *screen_type = imd->color_profile_screen;
1757         if (use_image) *use_image = imd->color_profile_use_image;
1758
1759         return TRUE;
1760 }
1761
1762 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1763 {
1764         if (!imd) return;
1765
1766         if (imd->color_profile_enable == enable) return;
1767
1768         imd->color_profile_enable = enable;
1769 }
1770
1771 gint image_color_profile_get_use(ImageWindow *imd)
1772 {
1773         if (!imd) return FALSE;
1774
1775         return imd->color_profile_enable;
1776 }
1777
1778 gint image_color_profile_get_from_image(ImageWindow *imd)
1779 {
1780         if (!imd) return FALSE;
1781
1782         return imd->color_profile_from_image;
1783 }
1784
1785 void image_set_delay_flip(ImageWindow *imd, gint delay)
1786 {
1787         if (!imd ||
1788             imd->delay_flip == delay) return;
1789
1790         imd->delay_flip = delay;
1791
1792         g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1793
1794         if (!imd->delay_flip && imd->il)
1795                 {
1796                 PixbufRenderer *pr;
1797
1798                 pr = PIXBUF_RENDERER(imd->pr);
1799                 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1800                 pr->pixbuf = NULL;
1801
1802                 image_load_pixbuf_ready(imd);
1803                 }
1804 }
1805
1806 void image_to_root_window(ImageWindow *imd, gint scaled)
1807 {
1808         GdkScreen *screen;
1809         GdkWindow *rootwindow;
1810         GdkPixmap *pixmap;
1811         GdkPixbuf *pixbuf;
1812         GdkPixbuf *pb;
1813         gint width, height;
1814
1815         if (!imd) return;
1816
1817         pixbuf = image_get_pixbuf(imd);
1818         if (!pixbuf) return;
1819
1820         screen = gtk_widget_get_screen(imd->widget);
1821         rootwindow = gdk_screen_get_root_window(screen);
1822         if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1823
1824         if (scaled)
1825                 {
1826                 width = gdk_screen_width();
1827                 height = gdk_screen_height();
1828                 }
1829         else
1830                 {
1831                 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1832                 }
1833
1834         pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)options->image.zoom_quality);
1835
1836         gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1837         gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1838         gdk_window_clear(rootwindow);
1839         g_object_unref(pb);
1840         g_object_unref(pixmap);
1841
1842         gdk_flush();
1843 }
1844
1845 void image_select(ImageWindow *imd, gboolean select)
1846 {
1847         if (imd->has_frame)
1848                 {
1849                 if (select) 
1850                         {
1851                         gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1852                         gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1853                         }
1854                 else
1855                         gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1856                 }
1857 }
1858
1859
1860
1861 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1862 {
1863         if (imd->has_frame)
1864                 {
1865                 if (selectable) 
1866                         {
1867                         gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1868                         gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1869                         }
1870                 else
1871                         {
1872                         gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1873                         gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1874                         }
1875                 }
1876 }
1877
1878 /*
1879  *-------------------------------------------------------------------
1880  * prefs sync
1881  *-------------------------------------------------------------------
1882  */
1883
1884 static void image_options_set(ImageWindow *imd)
1885 {
1886         g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality,
1887                                         "zoom_2pass", options->image.zoom_2pass,
1888                                         "zoom_expand", options->image.zoom_to_fit_allow_expand,
1889                                         "dither_quality", options->image.dither_quality,
1890                                         "scroll_reset", options->image.scroll_reset_method,
1891                                         "cache_display", options->image.tile_cache_max,
1892                                         "window_fit", (imd->top_window_sync && options->image.fit_window_to_image),
1893                                         "window_limit", options->image.limit_window_size,
1894                                         "window_limit_value", options->image.max_window_size,
1895                                         "autofit_limit", options->image.limit_autofit_size,
1896                                         "autofit_limit_value", options->image.max_autofit_size,
1897
1898                                         NULL);
1899
1900         pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1901 }
1902
1903 void image_options_sync(void)
1904 {
1905         GList *work;
1906
1907         work = image_list;
1908         while (work)
1909                 {
1910                 ImageWindow *imd;
1911
1912                 imd = work->data;
1913                 work = work->next;
1914
1915                 image_options_set(imd);
1916                 }
1917 }
1918
1919 /*
1920  *-------------------------------------------------------------------
1921  * init / destroy
1922  *-------------------------------------------------------------------
1923  */
1924
1925 static void image_free(ImageWindow *imd)
1926 {
1927         image_list = g_list_remove(image_list, imd);
1928
1929         image_reset(imd);
1930
1931         image_read_ahead_cancel(imd);
1932         image_post_buffer_set(imd, NULL, NULL, -1);
1933         image_auto_refresh(imd, -1);
1934
1935         file_data_unref(imd->image_fd);
1936         g_free(imd->title);
1937         g_free(imd->title_right);
1938
1939         g_free(imd);
1940 }
1941
1942 static void image_destroy_cb(GtkObject *widget, gpointer data)
1943 {
1944         ImageWindow *imd = data;
1945         image_free(imd);
1946 }
1947
1948 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1949 {
1950         gtk_paint_flat_box(widget->style,
1951                            widget->window,
1952                            widget->state,
1953                            GTK_FRAME (widget)->shadow_type,
1954                            NULL,
1955                            widget,
1956                            NULL,
1957                            widget->allocation.x + 3, widget->allocation.y + 3, 
1958                            widget->allocation.width - 6, widget->allocation.height - 6); 
1959  
1960  
1961         return FALSE;
1962 }
1963
1964
1965 void image_set_frame(ImageWindow *imd, gboolean frame)
1966 {
1967         frame = !!frame;
1968         
1969         if (frame == imd->has_frame) return;
1970         
1971         gtk_widget_hide(imd->pr);
1972         
1973         if (frame)
1974                 {
1975                 imd->frame = gtk_frame_new(NULL);
1976                 gtk_widget_ref(imd->pr);
1977                 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1978                 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1979                 gtk_widget_unref(imd->pr);
1980                 g_signal_connect (G_OBJECT (imd->frame), "expose_event",  
1981                     G_CALLBACK (selectable_frame_expose_cb), NULL);
1982
1983                 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1984                 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1985                                  G_CALLBACK(image_focus_in_cb), imd);
1986                 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1987                                  G_CALLBACK(image_focus_out_cb), imd);
1988
1989                 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1990                                        G_CALLBACK(image_focus_expose), imd);
1991
1992
1993                 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1994                 gtk_widget_show(imd->frame);
1995                 }
1996         else
1997                 {
1998                 gtk_widget_ref(imd->pr);
1999                 if (imd->frame) 
2000                         {
2001                         gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
2002                         gtk_widget_destroy(imd->frame);
2003                         imd->frame = NULL;
2004                         }
2005                 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
2006                 gtk_widget_unref(imd->pr);
2007                 }
2008
2009         gtk_widget_show(imd->pr);
2010         
2011         imd->has_frame = frame;
2012 }
2013
2014 ImageWindow *image_new(gint frame)
2015 {
2016         ImageWindow *imd;
2017
2018         imd = g_new0(ImageWindow, 1);
2019
2020         imd->top_window = NULL;
2021         imd->title = NULL;
2022         imd->title_right = NULL;
2023         imd->title_show_zoom = FALSE;
2024
2025         imd->unknown = TRUE;
2026
2027         imd->has_frame = -1; /* not initialized; for image_set_frame */
2028         imd->top_window_sync = FALSE;
2029
2030         imd->delay_alter_type = ALTER_NONE;
2031
2032         imd->read_ahead_il = NULL;
2033         imd->read_ahead_pixbuf = NULL;
2034         imd->read_ahead_fd = NULL;
2035
2036         imd->completed = FALSE;
2037         imd->state = IMAGE_STATE_NONE;
2038
2039         imd->color_profile_enable = FALSE;
2040         imd->color_profile_input = 0;
2041         imd->color_profile_screen = 0;
2042         imd->color_profile_use_image = FALSE;
2043         imd->color_profile_from_image = COLOR_PROFILE_NONE;
2044
2045         imd->auto_refresh_id = -1;
2046         imd->auto_refresh_interval = -1;
2047
2048         imd->delay_flip = FALSE;
2049
2050         imd->func_update = NULL;
2051         imd->func_complete = NULL;
2052         imd->func_tile_request = NULL;
2053         imd->func_tile_dispose = NULL;
2054
2055         imd->func_button = NULL;
2056         imd->func_scroll = NULL;
2057         
2058         imd->orientation = 1;
2059
2060         imd->pr = GTK_WIDGET(pixbuf_renderer_new());
2061
2062         image_options_set(imd);
2063
2064         
2065         imd->widget = gtk_vbox_new(0, 0);
2066
2067         image_set_frame(imd, frame);
2068
2069         image_set_selectable(imd, 0);
2070
2071         g_signal_connect(G_OBJECT(imd->pr), "clicked",
2072                          G_CALLBACK(image_click_cb), imd);
2073         g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
2074                          G_CALLBACK(image_scroll_notify_cb), imd);
2075
2076         g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
2077                          G_CALLBACK(image_scroll_cb), imd);
2078
2079         g_signal_connect(G_OBJECT(imd->pr), "destroy",
2080                          G_CALLBACK(image_destroy_cb), imd);
2081
2082         g_signal_connect(G_OBJECT(imd->pr), "zoom",
2083                          G_CALLBACK(image_zoom_cb), imd);
2084         g_signal_connect(G_OBJECT(imd->pr), "render_complete",
2085                          G_CALLBACK(image_render_complete_cb), imd);
2086         g_signal_connect(G_OBJECT(imd->pr), "drag",
2087                          G_CALLBACK(image_drag_cb), imd);
2088
2089         image_list = g_list_append(image_list, imd);
2090
2091         return imd;
2092 }
2093