bb5f8c1dd64d9e9496221866142d55e63a0b7930
[geeqie.git] / src / image.c
1 /*
2  * GQview
3  * (C) 2005 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 "gqview.h"
14 #include "image.h"
15
16
17 #include "image-load.h"
18 #include "collect.h"
19 #include "exif.h"
20 #include "pixbuf-renderer.h"
21 #include "pixbuf_util.h"
22 #include "ui_fileops.h"
23
24 #include <math.h>
25
26
27 /* size of the image loader buffer (512 bytes x defined number) */
28 #define IMAGE_LOAD_BUFFER_COUNT 8
29
30 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
31 #define IMAGE_THROTTLE_LARGER_IMAGES 1
32
33 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
34 #define IMAGE_THROTTLE_FACTOR 4
35
36 /* the file size at which throttling take place */
37 #define IMAGE_THROTTLE_THRESHOLD 1048576
38
39 #define IMAGE_AUTO_REFRESH_TIME 3000
40
41
42 static GList *image_list = NULL;
43
44
45 static void image_update_title(ImageWindow *imd);
46
47 /*
48  *-------------------------------------------------------------------
49  * 'signals'
50  *-------------------------------------------------------------------
51  */
52
53 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
54 {
55         ImageWindow *imd = data;
56
57         if (imd->func_button)
58                 {
59                 imd->func_button(imd, event->button, event->time,
60                                  event->x, event->y, event->state, imd->data_button);
61                 }
62 }
63
64 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
65 {
66         ImageWindow *imd = data;
67
68         if (imd->func_scroll_notify && pr->scale)
69                 {
70                 imd->func_scroll_notify(imd,
71                                         (gint)((gdouble)pr->x_scroll / pr->scale),
72                                         (gint)((gdouble)pr->y_scroll / pr->scale),
73                                         (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
74                                         (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
75                                         imd->data_scroll_notify);
76                 }
77 }
78
79 static void image_update_util(ImageWindow *imd)
80 {
81         if (imd->func_update) imd->func_update(imd, imd->data_update);
82 }
83
84 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
85 {
86         ImageWindow *imd = data;
87
88         if (imd->title_show_zoom) image_update_title(imd);
89         image_update_util(imd);
90 }
91
92 static void image_complete_util(ImageWindow *imd, gint preload)
93 {
94         if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
95
96         if (debug) printf("image load completed \"%s\" (%s)\n",
97                           (preload) ? imd->read_ahead_path : imd->image_path,
98                           (preload) ? "preload" : "current");
99
100         if (!preload) imd->completed = TRUE;
101         if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
102 }
103
104 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
105 {
106         ImageWindow *imd = data;
107
108         image_complete_util(imd, FALSE);
109 }
110
111 static void image_new_util(ImageWindow *imd)
112 {
113         if (imd->func_new) imd->func_new(imd, imd->data_new);
114 }
115
116 /*
117  *-------------------------------------------------------------------
118  * misc
119  *-------------------------------------------------------------------
120  */
121
122 static void image_update_title(ImageWindow *imd)
123 {
124         gchar *title = NULL;
125         gchar *zoom = NULL;
126         gchar *collection = NULL;
127
128         if (!imd->top_window) return;
129
130         if (imd->collection && collection_to_number(imd->collection) >= 0)
131                 {
132                 const gchar *name;
133                 name = imd->collection->name;
134                 if (!name) name = _("Untitled");
135                 collection = g_strdup_printf(" (Collection %s)", name);
136                 }
137
138         if (imd->title_show_zoom)
139                 {
140                 gchar *buf = image_zoom_get_as_text(imd);
141                 zoom = g_strconcat(" [", buf, "]", NULL);
142                 g_free(buf);
143                 }
144
145         title = g_strdup_printf("%s%s%s%s%s%s",
146                 imd->title ? imd->title : "",
147                 imd->image_name ? imd->image_name : "",
148                 zoom ? zoom : "",
149                 collection ? collection : "",
150                 imd->image_name ? " - " : "",
151                 imd->title_right ? imd->title_right : "");
152
153         gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
154
155         g_free(title);
156         g_free(zoom);
157         g_free(collection);
158 }
159
160 /*
161  *-------------------------------------------------------------------
162  * rotation, flip, etc.
163  *-------------------------------------------------------------------
164  */
165
166 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp, gint exif_rotated)
167 {
168         PixbufRenderer *pr;
169         GdkPixbuf *new = NULL;
170         gint x, y;
171         gint t;
172
173         pr = (PixbufRenderer *)imd->pr;
174
175         imd->delay_alter_type = ALTER_NONE;
176
177         if (!pr->pixbuf) return;
178
179         x = pr->x_scroll + (pr->vis_width / 2);
180         y = pr->y_scroll + (pr->vis_height / 2);
181
182         switch (type)
183                 {
184                 case ALTER_ROTATE_90:
185                         new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
186                         t = x;
187                         x = pr->height - y;
188                         y = t;
189                         break;
190                 case ALTER_ROTATE_90_CC:
191                         new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
192                         t = x;
193                         x = y;
194                         y = pr->width - t;
195                         break;
196                 case ALTER_ROTATE_180:
197                         new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
198                         x = pr->width - x;
199                         y = pr->height - y;
200                         break;
201                 case ALTER_MIRROR:
202                         new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
203                         x = pr->width - x;
204                         break;
205                 case ALTER_FLIP:
206                         new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
207                         y = pr->height - y;
208                         break;
209                 case ALTER_DESATURATE:
210                         pixbuf_desaturate_rect(pr->pixbuf,
211                                                0, 0,  pr->image_width, pr->image_height);
212                         image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
213                         break;
214                 case ALTER_NONE:
215                 default:
216                         return;
217                         break;
218                 }
219
220         if (!new) return;
221
222         pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
223         g_object_unref(new);
224
225         if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
226                 {
227                 if (exif_rotated)
228                         {
229                         switch (pr->scroll_reset)
230                                 {
231                                 case PR_SCROLL_RESET_NOCHANGE:
232                                         break;
233                                 case PR_SCROLL_RESET_CENTER:
234                                         x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
235                                         y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
236                                         break;
237                                 case PR_SCROLL_RESET_TOPLEFT:
238                                 default:
239                                         x = 0;
240                                         y = 0;
241                                         break;
242                                 }
243                         }
244                 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
245                                                     (gint)((gdouble)y / pr->scale),
246                                                     0.50, 0.50);
247                 }
248 }
249
250 static void image_post_process(ImageWindow *imd, gint clamp)
251 {
252         gint exif_rotated = FALSE;
253
254         if (exif_rotate_enable && image_get_pixbuf(imd))
255                 {
256                 ExifData *ed;
257                 gint orientation;
258
259                 ed = exif_read(imd->image_path);
260                 if (ed && exif_get_integer(ed, "Orientation", &orientation))
261                         {
262                         /* see http://jpegclub.org/exif_orientation.html 
263                           1        2       3      4         5            6           7          8
264
265                         888888  888888      88  88      8888888888  88                  88  8888888888
266                         88          88      88  88      88  88      88  88          88  88      88  88
267                         8888      8888    8888  8888    88          8888888888  8888888888          88
268                         88          88      88  88
269                         88          88  888888  888888
270                         */
271
272                         switch (orientation)
273                                 {
274                                 case EXIF_ORIENTATION_TOP_LEFT:
275                                         /* normal -- nothing to do */
276                                         break;
277                                 case EXIF_ORIENTATION_TOP_RIGHT:
278                                         /* mirrored */
279                                         imd->delay_alter_type = ALTER_MIRROR;
280                                         exif_rotated = TRUE;
281                                         break;
282                                 case EXIF_ORIENTATION_BOTTOM_RIGHT:
283                                         /* upside down */
284                                         imd->delay_alter_type = ALTER_ROTATE_180;
285                                         exif_rotated = TRUE;
286                                         break;
287                                 case EXIF_ORIENTATION_BOTTOM_LEFT:
288                                         /* flipped */
289                                         imd->delay_alter_type = ALTER_FLIP;
290                                         exif_rotated = TRUE;
291                                         break;
292                                 case EXIF_ORIENTATION_LEFT_TOP:
293                                         /* not implemented -- too wacky to fix in one step */
294                                         break;
295                                 case EXIF_ORIENTATION_RIGHT_TOP:
296                                         /* rotated -90 (270) */
297                                         imd->delay_alter_type = ALTER_ROTATE_90;
298                                         exif_rotated = TRUE;
299                                         break;
300                                 case EXIF_ORIENTATION_RIGHT_BOTTOM:
301                                         /* not implemented -- too wacky to fix in one step */
302                                         break;
303                                 case EXIF_ORIENTATION_LEFT_BOTTOM:
304                                         /* rotated 90 */
305                                         imd->delay_alter_type = ALTER_ROTATE_90_CC;
306                                         exif_rotated = TRUE;
307                                         break;
308                                 default:
309                                         /* The other values are out of range */
310                                         break;
311                                 }
312                         }
313                 exif_free(ed);
314                 }
315
316         if (imd->delay_alter_type != ALTER_NONE)
317                 {
318                 image_alter_real(imd, imd->delay_alter_type, clamp, exif_rotated);
319                 }
320 }
321
322 /*
323  *-------------------------------------------------------------------
324  * read ahead (prebuffer)
325  *-------------------------------------------------------------------
326  */
327
328 static void image_read_ahead_cancel(ImageWindow *imd)
329 {
330         if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_path);
331
332         image_loader_free(imd->read_ahead_il);
333         imd->read_ahead_il = NULL;
334
335         if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
336         imd->read_ahead_pixbuf = NULL;
337
338         g_free(imd->read_ahead_path);
339         imd->read_ahead_path = NULL;
340 }
341
342 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
343 {
344         ImageWindow *imd = data;
345
346         if (debug) printf("read ahead done for :%s\n", imd->read_ahead_path);
347
348         imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
349         if (imd->read_ahead_pixbuf)
350                 {
351                 g_object_ref(imd->read_ahead_pixbuf);
352                 }
353         else
354                 {
355                 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
356                 }
357         image_loader_free(imd->read_ahead_il);
358         imd->read_ahead_il = NULL;
359
360         image_complete_util(imd, TRUE);
361 }
362
363 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
364 {
365         /* we even treat errors as success, maybe at least some of the file was ok */
366         image_read_ahead_done_cb(il, data);
367 }
368
369 static void image_read_ahead_start(ImageWindow *imd)
370 {
371         /* already started ? */
372         if (!imd->read_ahead_path || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
373
374         /* still loading ?, do later */
375         if (imd->il) return;
376
377         if (debug) printf("read ahead started for :%s\n", imd->read_ahead_path);
378
379         imd->read_ahead_il = image_loader_new(imd->read_ahead_path);
380
381         image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
382         if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
383                 {
384                 image_read_ahead_cancel(imd);
385                 image_complete_util(imd, TRUE);
386                 }
387 }
388
389 static void image_read_ahead_set(ImageWindow *imd, const gchar *path)
390 {
391         if (imd->read_ahead_path && path && strcmp(imd->read_ahead_path, path) == 0) return;
392
393         image_read_ahead_cancel(imd);
394
395         imd->read_ahead_path = g_strdup(path);
396
397         if (debug) printf("read ahead set to :%s\n", imd->read_ahead_path);
398
399         image_read_ahead_start(imd);
400 }
401
402 /*
403  *-------------------------------------------------------------------
404  * post buffering
405  *-------------------------------------------------------------------
406  */
407
408 static void image_post_buffer_set(ImageWindow *imd, const gchar *path, GdkPixbuf *pixbuf)
409 {
410         g_free(imd->prev_path);
411         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
412
413         if (path && pixbuf)
414                 {
415                 imd->prev_path = g_strdup(path);
416                         
417                 g_object_ref(pixbuf);
418                 imd->prev_pixbuf = pixbuf;
419                 }
420         else
421                 {
422                 imd->prev_path = NULL;
423                 imd->prev_pixbuf = NULL;
424                 }
425
426         if (debug) printf("post buffer set: %s\n", path);
427 }
428
429 static gint image_post_buffer_get(ImageWindow *imd)
430 {
431         gint success;
432
433         if (imd->prev_pixbuf &&
434             imd->image_path && imd->prev_path && strcmp(imd->image_path, imd->prev_path) == 0)
435                 {
436                 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
437                 success = TRUE;
438                 }
439         else
440                 {
441                 success = FALSE;
442                 }
443
444         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
445         imd->prev_pixbuf = NULL;
446
447         g_free(imd->prev_path);
448         imd->prev_path = NULL;
449
450         return success;
451 }
452
453 /*
454  *-------------------------------------------------------------------
455  * loading
456  *-------------------------------------------------------------------
457  */
458
459 static void image_load_pixbuf_ready(ImageWindow *imd)
460 {
461         if (image_get_pixbuf(imd) || !imd->il) return;
462
463         image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
464 }
465
466 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
467 {
468         ImageWindow *imd = data;
469         PixbufRenderer *pr;
470
471         pr = (PixbufRenderer *)imd->pr;
472
473         if (imd->delay_flip &&
474             pr->pixbuf != image_loader_get_pixbuf(il))
475                 {
476                 return;
477                 }
478
479         if (!pr->pixbuf) image_load_pixbuf_ready(imd);
480
481         pixbuf_renderer_area_changed(pr, x, y, w, h);
482 }
483
484 static void image_load_done_cb(ImageLoader *il, gpointer data)
485 {
486         ImageWindow *imd = data;
487
488         if (debug) printf ("image done\n");
489
490         g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
491
492         if (imd->delay_flip &&
493             image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
494                 {
495                 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
496                 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
497                 }
498
499         image_loader_free(imd->il);
500         imd->il = NULL;
501
502         image_post_process(imd, TRUE);
503
504         image_read_ahead_start(imd);
505 }
506
507 static void image_load_error_cb(ImageLoader *il, gpointer data)
508 {
509         if (debug) printf ("image error\n");
510
511         /* even on error handle it like it was done,
512          * since we have a pixbuf with _something_ */
513
514         image_load_done_cb(il, data);
515 }
516
517 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
518 static void image_load_buffer_throttle(ImageLoader *il)
519 {
520         if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
521
522         /* Larger image files usually have larger chunks of data per pixel...
523          * So increase the buffer read size so that the rendering chunks called
524          * are also larger.
525          */
526
527         image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
528 }
529 #endif
530
531 /* this read ahead is located here merely for the callbacks, above */
532
533 static gint image_read_ahead_check(ImageWindow *imd)
534 {
535         if (!imd->read_ahead_path) return FALSE;
536         if (imd->il) return FALSE;
537
538         if (!imd->image_path || strcmp(imd->read_ahead_path, imd->image_path) != 0)
539                 {
540                 image_read_ahead_cancel(imd);
541                 return FALSE;
542                 }
543
544         if (imd->read_ahead_il)
545                 {
546                 imd->il = imd->read_ahead_il;
547                 imd->read_ahead_il = NULL;
548
549                 /* override the old signals */
550                 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
551                 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
552                 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
553
554 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
555                 image_load_buffer_throttle(imd->il);
556 #endif
557
558                 /* do this one directly (probably should add a set func) */
559                 imd->il->func_done = image_load_done_cb;
560
561                 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
562
563                 if (!imd->delay_flip)
564                         {
565                         image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
566                         }
567
568                 image_read_ahead_cancel(imd);
569                 return TRUE;
570                 }
571         else if (imd->read_ahead_pixbuf)
572                 {
573                 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
574                 g_object_unref(imd->read_ahead_pixbuf);
575                 imd->read_ahead_pixbuf = NULL;
576
577                 image_read_ahead_cancel(imd);
578
579                 image_post_process(imd, FALSE);
580                 return TRUE;
581                 }
582
583         image_read_ahead_cancel(imd);
584         return FALSE;
585 }
586
587 static gint image_load_begin(ImageWindow *imd, const gchar *path)
588 {
589         if (debug) printf ("image begin \n");
590
591         if (imd->il) return FALSE;
592
593         imd->completed = FALSE;
594         g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
595
596         if (image_post_buffer_get(imd))
597                 {
598                 if (debug) printf("from post buffer: %s\n", imd->image_path);
599                 return TRUE;
600                 }
601
602         if (image_read_ahead_check(imd))
603                 {
604                 if (debug) printf("from read ahead buffer: %s\n", imd->image_path);
605                 return TRUE;
606                 }
607
608         if (!imd->delay_flip && image_get_pixbuf(imd))
609                 {
610                 PixbufRenderer *pr;
611
612                 pr = PIXBUF_RENDERER(imd->pr);
613                 if (pr->pixbuf) g_object_unref(pr->pixbuf);
614                 pr->pixbuf = NULL;
615                 }
616
617         g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
618
619         imd->il = image_loader_new(path);
620
621         image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
622         image_loader_set_error_func(imd->il, image_load_error_cb, imd);
623         image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
624
625         if (!image_loader_start(imd->il, image_load_done_cb, imd))
626                 {
627                 if (debug) printf("image start error\n");
628
629                 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
630
631                 image_loader_free(imd->il);
632                 imd->il = NULL;
633
634                 image_complete_util(imd, FALSE);
635
636                 return FALSE;
637                 }
638
639 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
640         image_load_buffer_throttle(imd->il);
641 #endif
642
643         if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
644
645         return TRUE;
646 }
647
648 static void image_reset(ImageWindow *imd)
649 {
650         /* stops anything currently being done */
651
652         if (debug) printf("image reset\n");
653
654         g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
655
656         image_loader_free(imd->il);
657         imd->il = NULL;
658
659         imd->delay_alter_type = ALTER_NONE;
660 }
661
662 /*
663  *-------------------------------------------------------------------
664  * image changer
665  *-------------------------------------------------------------------
666  */
667
668 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
669 {
670         image_reset(imd);
671
672         if (imd->image_path && isfile(imd->image_path))
673                 {
674                 PixbufRenderer *pr;
675
676                 pr = PIXBUF_RENDERER(imd->pr);
677                 pr->zoom = zoom;        /* store the zoom, needed by the loader */
678
679                 if (image_load_begin(imd, imd->image_path))
680                         {
681                         imd->unknown = FALSE;
682                         }
683                 else
684                         {
685                         GdkPixbuf *pixbuf;
686
687                         pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
688                         image_change_pixbuf(imd, pixbuf, zoom);
689                         g_object_unref(pixbuf);
690
691                         imd->unknown = TRUE;
692                         }
693                 imd->size = filesize(imd->image_path);
694                 imd->mtime = filetime(imd->image_path);
695                 }
696         else
697                 {
698                 if (imd->image_path)
699                         {
700                         GdkPixbuf *pixbuf;
701
702                         pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
703                         image_change_pixbuf(imd, pixbuf, zoom);
704                         g_object_unref(pixbuf);
705                         imd->mtime = filetime(imd->image_path);
706                         }
707                 else
708                         {
709                         image_change_pixbuf(imd, NULL, zoom);
710                         imd->mtime = 0;
711                         }
712                 imd->unknown = TRUE;
713                 imd->size = 0;
714                 }
715
716         image_update_util(imd);
717 }
718
719 static void image_change_real(ImageWindow *imd, const gchar *path,
720                               CollectionData *cd, CollectInfo *info, gdouble zoom)
721 {
722         GdkPixbuf *pixbuf;
723         GdkPixbuf *prev_pixbuf = NULL;
724         gchar *prev_path = NULL;
725         gint prev_clear = FALSE;
726
727         imd->collection = cd;
728         imd->collection_info = info;
729
730         pixbuf = image_get_pixbuf(imd);
731
732         if (enable_read_ahead && imd->image_path && pixbuf)
733                 {
734                 if (imd->il)
735                         {
736                         /* current image is not finished */
737                         prev_clear = TRUE;
738                         }
739                 else
740                         {
741                         prev_path = g_strdup(imd->image_path);
742                         prev_pixbuf = pixbuf;
743                         g_object_ref(prev_pixbuf);
744                         }
745                 }
746
747         g_free(imd->image_path);
748         imd->image_path = g_strdup(path);
749         imd->image_name = filename_from_path(imd->image_path);
750
751         image_change_complete(imd, zoom, TRUE);
752
753         if (prev_pixbuf)
754                 {
755                 image_post_buffer_set(imd, prev_path, prev_pixbuf);
756                 g_free(prev_path);
757                 g_object_unref(prev_pixbuf);
758                 }
759         else if (prev_clear)
760                 {
761                 image_post_buffer_set(imd, NULL, NULL);
762                 }
763
764         image_update_title(imd);
765         image_new_util(imd);
766 }
767
768 /*
769  *-------------------------------------------------------------------
770  * focus stuff
771  *-------------------------------------------------------------------
772  */
773
774 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
775 {
776         GtkWidget *widget;
777
778         widget = imd->widget;
779         if (!widget->window) return;
780
781         if (has_focus)
782                 {
783                 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
784                                  area, widget, "image_window",
785                                  widget->allocation.x, widget->allocation.y,
786                                  widget->allocation.width - 1, widget->allocation.height - 1);  
787                 }
788         else
789                 {
790                 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
791                                   area, widget, "image_window",
792                                   widget->allocation.x, widget->allocation.y,
793                                   widget->allocation.width - 1, widget->allocation.height - 1);
794                 }
795 }
796
797 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
798 {
799         ImageWindow *imd = data;
800
801         image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
802         return TRUE;
803 }
804
805 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
806 {
807         ImageWindow *imd = data;
808
809         GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
810         image_focus_paint(imd, TRUE, NULL);
811
812         return TRUE;
813 }
814
815 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
816 {
817         ImageWindow *imd = data;
818
819         GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
820         image_focus_paint(imd, FALSE, NULL);
821
822         return TRUE;
823 }
824
825 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
826                        gint relative, gint always)
827 {
828         return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
829 }
830
831 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
832 {
833         pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
834 }
835
836 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
837 {
838         return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
839 }
840
841 void image_overlay_remove(ImageWindow *imd, gint id)
842 {
843         pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
844 }
845
846 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
847 {
848         ImageWindow *imd = data;
849
850         if (imd->func_scroll &&
851             event && event->type == GDK_SCROLL)
852                 {
853                 imd->func_scroll(imd, event->direction, event->time,
854                                  event->x, event->y, event->state, imd->data_scroll);
855                 return TRUE;
856                 }
857
858         return FALSE;
859 }
860
861 /*
862  *-------------------------------------------------------------------
863  * public interface
864  *-------------------------------------------------------------------
865  */
866
867 void image_attach_window(ImageWindow *imd, GtkWidget *window,
868                          const gchar *title, const gchar *title_right, gint show_zoom)
869 {
870         imd->top_window = window;
871         g_free(imd->title);
872         imd->title = g_strdup(title);
873         g_free(imd->title_right);
874         imd->title_right = g_strdup(title_right);
875         imd->title_show_zoom = show_zoom;
876
877         if (!fit_window) window = NULL;
878
879         pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
880
881         image_update_title(imd);
882 }
883
884 void image_set_update_func(ImageWindow *imd,
885                            void (*func)(ImageWindow *imd, gpointer data),
886                            gpointer data)
887 {
888         imd->func_update = func;
889         imd->data_update = data;
890 }
891
892 void image_set_complete_func(ImageWindow *imd,
893                              void (*func)(ImageWindow *, gint preload, gpointer),
894                              gpointer data)
895 {
896         imd->func_complete = func;
897         imd->data_complete = data;
898 }
899
900 void image_set_new_func(ImageWindow *imd,
901                         void (*func)(ImageWindow *, gpointer),
902                         gpointer data)
903 {
904         imd->func_new = func;
905         imd->data_new = data;
906 }
907
908
909 void image_set_button_func(ImageWindow *imd,
910                            void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
911                            gpointer data)
912 {
913         imd->func_button = func;
914         imd->data_button = data;
915 }
916
917 void image_set_scroll_func(ImageWindow *imd,
918                            void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
919                            gpointer data)
920 {
921         imd->func_scroll = func;
922         imd->data_scroll = data;
923 }
924
925 void image_set_scroll_notify_func(ImageWindow *imd,
926                                   void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
927                                   gpointer data)
928 {
929         imd->func_scroll_notify = func;
930         imd->data_scroll_notify = data;
931 }
932
933 /* path, name */
934
935 const gchar *image_get_path(ImageWindow *imd)
936 {
937         return imd->image_path;
938 }
939
940 const gchar *image_get_name(ImageWindow *imd)
941 {
942         return imd->image_name;
943 }
944
945 /* merely changes path string, does not change the image! */
946 void image_set_path(ImageWindow *imd, const gchar *newpath)
947 {
948         g_free(imd->image_path);
949         imd->image_path = g_strdup(newpath);
950         imd->image_name = filename_from_path(imd->image_path);
951
952         image_update_title(imd);
953         image_new_util(imd);
954 }
955
956 /* load a new image */
957
958 void image_change_path(ImageWindow *imd, const gchar *path, gdouble zoom)
959 {
960         if (imd->image_path == path ||
961             (path && imd->image_path && !strcmp(path, imd->image_path)) ) return;
962
963         image_change_real(imd, path, NULL, NULL, zoom);
964 }
965
966 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
967 {
968         return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
969 }
970
971 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
972 {
973         pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
974         image_new_util(imd);
975 }
976
977 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
978 {
979         if (!cd || !info || !g_list_find(cd->list, info)) return;
980
981         image_change_real(imd, info->path, cd, info, zoom);
982 }
983
984 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
985 {
986         if (collection_to_number(imd->collection) >= 0)
987                 {
988                 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
989                         {
990                         if (info) *info = imd->collection_info;
991                         }
992                 else
993                         {
994                         if (info) *info = NULL;
995                         }
996                 return imd->collection;
997                 }
998
999         if (info) *info = NULL;
1000         return NULL;
1001 }
1002
1003 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1004 {
1005         /* change data for the callbacks directly */
1006
1007         il->data_area_ready = data;
1008         il->data_error = data;
1009         il->data_done = data;
1010         il->data_percent = data;
1011 }
1012
1013 /* this is more like a move function
1014  * it moves most data from source to imd
1015  */
1016 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1017 {
1018         if (imd == source) return;
1019
1020         imd->unknown = source->unknown;
1021
1022         imd->collection = source->collection;
1023         imd->collection_info = source->collection_info;
1024         imd->size = source->size;
1025         imd->mtime = source->mtime;
1026
1027         image_set_path(imd, image_get_path(source));
1028
1029         image_loader_free(imd->il);
1030         imd->il = NULL;
1031
1032         if (source->il)
1033                 {
1034                 imd->il = source->il;
1035                 source->il = NULL;
1036
1037                 image_loader_sync_data(imd->il, imd);
1038
1039                 imd->delay_alter_type = source->delay_alter_type;
1040                 source->delay_alter_type = ALTER_NONE;
1041                 }
1042
1043         image_loader_free(imd->read_ahead_il);
1044         imd->read_ahead_il = source->read_ahead_il;
1045         source->read_ahead_il = NULL;
1046         if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1047
1048         if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1049         imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1050         source->read_ahead_pixbuf = NULL;
1051
1052         g_free(imd->read_ahead_path);
1053         imd->read_ahead_path = source->read_ahead_path;
1054         source->read_ahead_path = NULL;
1055
1056         if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1057         imd->prev_pixbuf = source->prev_pixbuf;
1058         source->prev_pixbuf = NULL;
1059
1060         g_free(imd->prev_path);
1061         imd->prev_path = source->prev_path;
1062         source->prev_path = NULL;
1063
1064         imd->completed = source->completed;
1065
1066         pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1067 }
1068
1069 /* manipulation */
1070
1071 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1072 {
1073         pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1074 }
1075
1076 void image_reload(ImageWindow *imd)
1077 {
1078         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1079
1080         image_change_complete(imd, image_zoom_get(imd), FALSE);
1081 }
1082
1083 void image_scroll(ImageWindow *imd, gint x, gint y)
1084 {
1085         pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1086 }
1087
1088 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1089                            gdouble x_align, gdouble y_align)
1090 {
1091         pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1092 }
1093
1094 void image_alter(ImageWindow *imd, AlterType type)
1095 {
1096         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1097
1098         if (imd->il)
1099                 {
1100                 /* still loading, wait till done */
1101                 imd->delay_alter_type = type;
1102                 return;
1103                 }
1104
1105         image_alter_real(imd, type, TRUE, FALSE);
1106 }
1107
1108 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1109 {
1110         pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1111 }
1112
1113 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1114 {
1115         pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1116 }
1117
1118 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1119 {
1120         pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1121 }
1122
1123 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1124 {
1125         pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1126 }
1127
1128 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1129 {
1130         PixbufRenderer *pr;
1131         gdouble zoom;
1132         gint width, height;
1133
1134         pr = (PixbufRenderer *)imd->pr;
1135
1136         if (!pixbuf_renderer_get_pixbuf(pr) ||
1137             !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1138
1139         if (vertical)
1140                 {
1141                 zoom = (gdouble)pr->window_height / height;
1142                 }
1143         else
1144                 {
1145                 zoom = (gdouble)pr->window_width / width;
1146                 }
1147
1148         if (zoom < 1.0)
1149                 {
1150                 zoom = 0.0 - 1.0 / zoom;
1151                 }
1152
1153         pixbuf_renderer_zoom_set(pr, zoom);
1154 }
1155
1156 gdouble image_zoom_get(ImageWindow *imd)
1157 {
1158         return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1159 }
1160
1161 gdouble image_zoom_get_real(ImageWindow *imd)
1162 {
1163         return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1164 }
1165
1166 gchar *image_zoom_get_as_text(ImageWindow *imd)
1167 {
1168         gdouble zoom;
1169         gdouble scale;
1170         gdouble l = 1.0;
1171         gdouble r = 1.0;
1172         gint pl = 0;
1173         gint pr = 0;
1174         gchar *approx = " ";
1175
1176         zoom = image_zoom_get(imd);
1177         scale = image_zoom_get_real(imd);
1178
1179         if (zoom > 0.0)
1180                 {
1181                 l = zoom;
1182                 }
1183         else if (zoom < 0.0)
1184                 {
1185                 r = 0.0 - zoom;
1186                 }
1187         else if (zoom == 0.0 && scale != 0.0)
1188                 {
1189                 if (scale >= 1.0)
1190                         {
1191                         l = scale;
1192                         }
1193                 else
1194                         {
1195                         r = 1.0 / scale;
1196                         }
1197                 approx = " ~";
1198                 }
1199
1200         if (rint(l) != l) pl = 1;
1201         if (rint(r) != r) pr = 1;
1202
1203         return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1204 }
1205
1206 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1207 {
1208         gdouble zoom;
1209
1210         if (mode == ZOOM_RESET_ORIGINAL)
1211                 {
1212                 zoom = 1.0;
1213                 }
1214         else if (mode == ZOOM_RESET_FIT_WINDOW)
1215                 {
1216                 zoom = 0.0;
1217                 }
1218         else
1219                 {
1220                 if (imd)
1221                         {
1222                         zoom = image_zoom_get(imd);
1223                         }
1224                 else
1225                         {
1226                         zoom = 1.0;
1227                         }
1228                 }
1229
1230         return zoom;
1231 }
1232
1233 /* read ahead */
1234
1235 void image_prebuffer_set(ImageWindow *imd, const gchar *path)
1236 {
1237         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1238
1239         if (path)
1240                 {
1241                 image_read_ahead_set(imd, path);
1242                 }
1243         else
1244                 {
1245                 image_read_ahead_cancel(imd);
1246                 }
1247 }
1248
1249 static gint image_auto_refresh_cb(gpointer data)
1250 {
1251         ImageWindow *imd = data;
1252         time_t newtime;
1253         
1254         if (!imd || !image_get_pixbuf(imd) ||
1255             imd->il || !imd->image_path ||
1256             !update_on_time_change) return TRUE;
1257
1258         newtime = filetime(imd->image_path);
1259         if (newtime > 0 && newtime != imd->mtime)
1260                 {
1261                 imd->mtime = newtime;
1262                 image_reload(imd);
1263                 }
1264
1265         return TRUE;
1266 }
1267
1268 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1269
1270 void image_auto_refresh(ImageWindow *imd, gint interval)
1271 {
1272         if (!imd) return;
1273         if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1274
1275         if (imd->auto_refresh_id > -1)
1276                 {
1277                 g_source_remove(imd->auto_refresh_id);
1278                 imd->auto_refresh_id = -1;
1279                 imd->auto_refresh_interval = -1;
1280                 }
1281
1282         if (interval < 0) return;
1283
1284         if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1285
1286         imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1287         imd->auto_refresh_interval = interval;
1288 }
1289
1290 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1291 {
1292         imd->top_window_sync = allow_sync;
1293
1294         g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1295 }
1296
1297 void image_background_set_black(ImageWindow *imd, gint black)
1298 {
1299         pixbuf_renderer_set_black((PixbufRenderer *)imd->pr, black);
1300 }
1301
1302 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1303 {
1304         pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1305 }
1306
1307 void image_set_delay_flip(ImageWindow *imd, gint delay)
1308 {
1309         if (!imd ||
1310             imd->delay_flip == delay) return;
1311
1312         imd->delay_flip = delay;
1313
1314         g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1315
1316         if (!imd->delay_flip && imd->il)
1317                 {
1318                 PixbufRenderer *pr;
1319
1320                 pr = PIXBUF_RENDERER(imd->pr);
1321                 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1322                 pr->pixbuf = NULL;
1323
1324                 image_load_pixbuf_ready(imd);
1325                 }
1326 }
1327
1328 void image_to_root_window(ImageWindow *imd, gint scaled)
1329 {
1330         GdkScreen *screen;
1331         GdkWindow *rootwindow;
1332         GdkPixmap *pixmap;
1333         GdkPixbuf *pixbuf;
1334         GdkPixbuf *pb;
1335         gint width, height;
1336
1337         if (!imd) return;
1338
1339         pixbuf = image_get_pixbuf(imd);
1340         if (!pixbuf) return;
1341
1342         screen = gtk_widget_get_screen(imd->widget);
1343         rootwindow = gdk_screen_get_root_window(screen);
1344         if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1345
1346         if (scaled)
1347                 {
1348                 width = gdk_screen_width();
1349                 height = gdk_screen_height();
1350                 }
1351         else
1352                 {
1353                 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1354                 }
1355
1356         pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1357
1358         gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1359         gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1360         gdk_window_clear(rootwindow);
1361         g_object_unref(pb);
1362         g_object_unref(pixmap);
1363
1364         gdk_flush();
1365 }
1366
1367 /*
1368  *-------------------------------------------------------------------
1369  * prefs sync
1370  *-------------------------------------------------------------------
1371  */
1372
1373 static void image_options_set(ImageWindow *imd)
1374 {
1375         g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1376                                         "zoom_2pass", two_pass_zoom,
1377                                         "zoom_expand", zoom_to_fit_expands,
1378                                         "dither_quality", dither_quality,
1379                                         "scroll_reset", scroll_reset_method,
1380                                         "cache_display", tile_cache_max,
1381                                         "window_fit", (imd->top_window_sync && fit_window),
1382                                         "window_limit", limit_window_size,
1383                                         "window_limit_value", max_window_size,
1384                                         NULL);
1385
1386         pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1387 }
1388
1389 void image_options_sync(void)
1390 {
1391         GList *work;
1392
1393         work = image_list;
1394         while (work)
1395                 {
1396                 ImageWindow *imd;
1397
1398                 imd = work->data;
1399                 work = work->next;
1400
1401                 image_options_set(imd);
1402                 }
1403 }
1404
1405 /*
1406  *-------------------------------------------------------------------
1407  * init / destroy
1408  *-------------------------------------------------------------------
1409  */
1410
1411 static void image_free(ImageWindow *imd)
1412 {
1413         image_list = g_list_remove(image_list, imd);
1414
1415         image_reset(imd);
1416
1417         image_read_ahead_cancel(imd);
1418         image_post_buffer_set(imd, NULL, NULL);
1419         image_auto_refresh(imd, -1);
1420
1421         g_free(imd->image_path);
1422         g_free(imd->title);
1423         g_free(imd->title_right);
1424
1425         g_free(imd);
1426 }
1427
1428 static void image_destroy_cb(GtkObject *widget, gpointer data)
1429 {
1430         ImageWindow *imd = data;
1431         image_free(imd);
1432 }
1433
1434 ImageWindow *image_new(gint frame)
1435 {
1436         ImageWindow *imd;
1437
1438         imd = g_new0(ImageWindow, 1);
1439
1440         imd->top_window = NULL;
1441         imd->title = NULL;
1442         imd->title_right = NULL;
1443         imd->title_show_zoom = FALSE;
1444
1445         imd->unknown = TRUE;
1446
1447         imd->has_frame = frame;
1448         imd->top_window_sync = FALSE;
1449
1450         imd->delay_alter_type = ALTER_NONE;
1451
1452         imd->read_ahead_il = NULL;
1453         imd->read_ahead_pixbuf = NULL;
1454         imd->read_ahead_path = NULL;
1455
1456         imd->completed = FALSE;
1457
1458         imd->auto_refresh_id = -1;
1459         imd->auto_refresh_interval = -1;
1460
1461         imd->delay_flip = FALSE;
1462
1463         imd->func_update = NULL;
1464         imd->func_complete = NULL;
1465         imd->func_tile_request = NULL;
1466         imd->func_tile_dispose = NULL;
1467
1468         imd->func_button = NULL;
1469         imd->func_scroll = NULL;
1470
1471         imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1472
1473         image_options_set(imd);
1474
1475         if (imd->has_frame)
1476                 {
1477                 imd->widget = gtk_frame_new(NULL);
1478                 gtk_frame_set_shadow_type(GTK_FRAME(imd->widget), GTK_SHADOW_IN);
1479                 gtk_container_add(GTK_CONTAINER(imd->widget), imd->pr);
1480                 gtk_widget_show(imd->pr);
1481
1482                 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_CAN_FOCUS);
1483                 g_signal_connect(G_OBJECT(imd->widget), "focus_in_event",
1484                                  G_CALLBACK(image_focus_in_cb), imd);
1485                 g_signal_connect(G_OBJECT(imd->widget), "focus_out_event",
1486                                  G_CALLBACK(image_focus_out_cb), imd);
1487
1488                 g_signal_connect_after(G_OBJECT(imd->widget), "expose_event",
1489                                        G_CALLBACK(image_focus_expose), imd);
1490                 }
1491         else
1492                 {
1493                 imd->widget = imd->pr;
1494                 }
1495
1496         g_signal_connect(G_OBJECT(imd->pr), "clicked",
1497                          G_CALLBACK(image_click_cb), imd);
1498         g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1499                          G_CALLBACK(image_scroll_notify_cb), imd);
1500
1501         g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1502                          G_CALLBACK(image_scroll_cb), imd);
1503
1504         g_signal_connect(G_OBJECT(imd->pr), "destroy",
1505                          G_CALLBACK(image_destroy_cb), imd);
1506
1507         g_signal_connect(G_OBJECT(imd->pr), "zoom",
1508                          G_CALLBACK(image_zoom_cb), imd);
1509         g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1510                          G_CALLBACK(image_render_complete_cb), imd);
1511
1512         image_list = g_list_append(image_list, imd);
1513
1514         return imd;
1515 }
1516