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!
17 #include "image-load.h"
19 #include "color-man.h"
21 #include "pixbuf-renderer.h"
22 #include "pixbuf_util.h"
23 #include "ui_fileops.h"
30 /* size of the image loader buffer (512 bytes x defined number) */
31 #define IMAGE_LOAD_BUFFER_COUNT 8
33 /* define this so that more bytes are read per idle loop on larger images (> 1MB) */
34 #define IMAGE_THROTTLE_LARGER_IMAGES 1
36 /* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
37 #define IMAGE_THROTTLE_FACTOR 4
39 /* the file size at which throttling take place */
40 #define IMAGE_THROTTLE_THRESHOLD 1048576
42 #define IMAGE_AUTO_REFRESH_TIME 3000
45 static GList *image_list = NULL;
48 static void image_update_title(ImageWindow *imd);
49 static void image_post_process(ImageWindow *imd, gint clamp);
50 static void image_read_ahead_start(ImageWindow *imd);
53 *-------------------------------------------------------------------
55 *-------------------------------------------------------------------
58 static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
60 ImageWindow *imd = data;
64 imd->func_button(imd, event->button, event->time,
65 event->x, event->y, event->state, imd->data_button);
69 static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data)
71 ImageWindow *imd = data;
74 pixbuf_renderer_get_scaled_size(pr, &width, &height);
78 imd->func_drag(imd, event->button, event->time,
79 event->x, event->y, event->state,
80 (gfloat)(pr->drag_last_x - event->x) / width, (gfloat)(pr->drag_last_y - event->y) / height,
85 static void image_scroll_notify_cb(PixbufRenderer *pr, gpointer data)
87 ImageWindow *imd = data;
89 if (imd->func_scroll_notify && pr->scale)
91 imd->func_scroll_notify(imd,
92 (gint)((gdouble)pr->x_scroll / pr->scale),
93 (gint)((gdouble)pr->y_scroll / pr->scale),
94 (gint)((gdouble)pr->image_width - pr->vis_width / pr->scale),
95 (gint)((gdouble)pr->image_height - pr->vis_height / pr->scale),
96 imd->data_scroll_notify);
100 static void image_update_util(ImageWindow *imd)
102 if (imd->func_update) imd->func_update(imd, imd->data_update);
105 static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data)
107 ImageWindow *imd = data;
109 if (imd->title_show_zoom) image_update_title(imd);
110 image_update_util(imd);
113 static void image_complete_util(ImageWindow *imd, gint preload)
115 if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return;
117 if (debug) printf("image load completed \"%s\" (%s)\n",
118 (preload) ? (imd->read_ahead_fd ? imd->read_ahead_fd->path : "null") :
119 (imd->image_fd ? imd->image_fd->path : "null"),
120 (preload) ? "preload" : "current");
122 if (!preload) imd->completed = TRUE;
123 if (imd->func_complete) imd->func_complete(imd, preload, imd->data_complete);
126 static void image_render_complete_cb(PixbufRenderer *pr, gpointer data)
128 ImageWindow *imd = data;
130 image_complete_util(imd, FALSE);
133 static void image_state_set(ImageWindow *imd, ImageState state)
135 if (state == IMAGE_STATE_NONE)
143 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
146 static void image_state_unset(ImageWindow *imd, ImageState state)
148 imd->state &= ~state;
149 if (imd->func_state) imd->func_state(imd, state, imd->data_state);
153 *-------------------------------------------------------------------
155 *-------------------------------------------------------------------
158 static void image_update_title(ImageWindow *imd)
162 gchar *collection = NULL;
164 if (!imd->top_window) return;
166 if (imd->collection && collection_to_number(imd->collection) >= 0)
169 name = imd->collection->name;
170 if (!name) name = _("Untitled");
171 collection = g_strdup_printf(" (Collection %s)", name);
174 if (imd->title_show_zoom)
176 gchar *buf = image_zoom_get_as_text(imd);
177 zoom = g_strconcat(" [", buf, "]", NULL);
181 title = g_strdup_printf("%s%s%s%s%s%s",
182 imd->title ? imd->title : "",
183 imd->image_fd ? imd->image_fd->name : "",
185 collection ? collection : "",
186 imd->image_fd ? " - " : "",
187 imd->title_right ? imd->title_right : "");
189 gtk_window_set_title(GTK_WINDOW(imd->top_window), title);
197 *-------------------------------------------------------------------
198 * rotation, flip, etc.
199 *-------------------------------------------------------------------
202 static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
205 GdkPixbuf *new = NULL;
210 pr = (PixbufRenderer *)imd->pr;
212 exif_rotate = (imd->delay_alter_type != ALTER_NONE && (imd->state & IMAGE_STATE_ROTATE_AUTO));
213 imd->delay_alter_type = ALTER_NONE;
215 if (!pr->pixbuf) return;
217 x = pr->x_scroll + (pr->vis_width / 2);
218 y = pr->y_scroll + (pr->vis_height / 2);
222 case ALTER_ROTATE_90:
223 new = pixbuf_copy_rotate_90(pr->pixbuf, FALSE);
228 case ALTER_ROTATE_90_CC:
229 new = pixbuf_copy_rotate_90(pr->pixbuf, TRUE);
234 case ALTER_ROTATE_180:
235 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, TRUE);
240 new = pixbuf_copy_mirror(pr->pixbuf, TRUE, FALSE);
244 new = pixbuf_copy_mirror(pr->pixbuf, FALSE, TRUE);
247 case ALTER_DESATURATE:
248 pixbuf_desaturate_rect(pr->pixbuf,
249 0, 0, pr->image_width, pr->image_height);
250 image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
251 layout_image_overlay_update(layout_find_by_image(imd));
261 pixbuf_renderer_set_pixbuf(pr, new, pr->zoom);
264 if (clamp && pr->zoom != 0.0 && pr->scale != 0.0)
268 switch (pr->scroll_reset)
270 case PR_SCROLL_RESET_NOCHANGE:
272 case PR_SCROLL_RESET_CENTER:
273 x = (gint)((gdouble)pr->image_width / 2.0 * pr->scale);
274 y = (gint)((gdouble)pr->image_height / 2.0 * pr->scale);
276 case PR_SCROLL_RESET_TOPLEFT:
283 pixbuf_renderer_scroll_to_point(pr, (gint)((gdouble)x / pr->scale),
284 (gint)((gdouble)y / pr->scale),
288 if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
289 layout_image_overlay_update(layout_find_by_image(imd));
292 static void image_post_process_alter(ImageWindow *imd, gint clamp)
294 if (imd->delay_alter_type != ALTER_NONE)
296 image_alter_real(imd, imd->delay_alter_type, clamp);
300 static void image_post_process_color_cb(ColorMan *cm, ColorManReturnType type, gpointer data)
302 ImageWindow *imd = data;
305 if (type == COLOR_RETURN_IMAGE_CHANGED)
307 if (cm == imd->cm) imd->cm = NULL;
312 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
314 image_post_process_alter(imd, FALSE);
316 image_read_ahead_start(imd);
319 static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif)
322 ColorManProfileType input_type;
323 ColorManProfileType screen_type;
324 const gchar *input_file;
325 const gchar *screen_file;
326 ExifItem *item = NULL;
328 if (imd->cm) return FALSE;
330 if (imd->color_profile_input >= 1 &&
331 imd->color_profile_input <= COLOR_PROFILE_INPUTS)
335 n = imd->color_profile_input - 1;
336 if (!color_profile_input_file[n]) return FALSE;
338 input_type = COLOR_PROFILE_FILE;
339 input_file = color_profile_input_file[n];
341 else if (imd->color_profile_input == 0)
343 input_type = COLOR_PROFILE_SRGB;
351 if (imd->color_profile_screen == 1 &&
352 color_profile_screen_file)
354 screen_type = COLOR_PROFILE_FILE;
355 screen_file = color_profile_screen_file;
357 else if (imd->color_profile_screen == 0)
359 screen_type = COLOR_PROFILE_SRGB;
367 if (imd->color_profile_use_image && exif)
369 item = exif_get_item(exif, "Exif.Image.InterColorProfile");
374 /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
375 if (exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs) &&
378 input_type = COLOR_PROFILE_SRGB;
381 if (debug) printf("Found EXIF ColorSpace of sRGB\n");
386 if (item && exif_item_get_format_id(item) == EXIF_FORMAT_UNDEFINED)
390 if (debug) printf("Found embedded color profile\n");
392 data = (unsigned char *) exif_item_get_data(item, &data_len);
394 cm = color_man_new_embedded(imd, NULL,
396 screen_type, screen_file,
397 image_post_process_color_cb, imd);
401 cm = color_man_new(imd, NULL,
402 input_type, input_file,
403 screen_type, screen_file,
404 image_post_process_color_cb, imd);
412 cm->incremental_sync = TRUE;
415 imd->cm = (gpointer)cm;
422 static void image_post_process(ImageWindow *imd, gint clamp)
424 ExifData *exif = NULL;
426 if (!image_get_pixbuf(imd)) return;
428 if (exif_rotate_enable ||
429 (imd->color_profile_enable && imd->color_profile_use_image) )
431 exif = exif_read_fd(imd->image_fd, (imd->color_profile_enable && imd->color_profile_use_image));
434 if (exif_rotate_enable && exif)
438 if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
442 /* see http://jpegclub.org/exif_orientation.html
445 888888 888888 88 88 8888888888 88 88 8888888888
446 88 88 88 88 88 88 88 88 88 88 88 88
447 8888 8888 8888 8888 88 8888888888 8888888888 88
453 case EXIF_ORIENTATION_TOP_LEFT:
454 /* normal -- nothing to do */
457 case EXIF_ORIENTATION_TOP_RIGHT:
459 imd->delay_alter_type = ALTER_MIRROR;
461 case EXIF_ORIENTATION_BOTTOM_RIGHT:
463 imd->delay_alter_type = ALTER_ROTATE_180;
465 case EXIF_ORIENTATION_BOTTOM_LEFT:
467 imd->delay_alter_type = ALTER_FLIP;
469 case EXIF_ORIENTATION_LEFT_TOP:
470 /* not implemented -- too wacky to fix in one step */
473 case EXIF_ORIENTATION_RIGHT_TOP:
474 /* rotated -90 (270) */
475 imd->delay_alter_type = ALTER_ROTATE_90;
477 case EXIF_ORIENTATION_RIGHT_BOTTOM:
478 /* not implemented -- too wacky to fix in one step */
481 case EXIF_ORIENTATION_LEFT_BOTTOM:
483 imd->delay_alter_type = ALTER_ROTATE_90_CC;
486 /* The other values are out of range */
491 if (rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
495 if (imd->color_profile_enable)
497 if (!image_post_process_color(imd, 0, exif))
499 /* fixme: note error to user */
500 image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
504 if (!imd->cm) image_post_process_alter(imd, clamp);
510 *-------------------------------------------------------------------
511 * read ahead (prebuffer)
512 *-------------------------------------------------------------------
515 static void image_read_ahead_cancel(ImageWindow *imd)
517 if (debug) printf("read ahead cancelled for :%s\n", imd->read_ahead_fd ? imd->read_ahead_fd->path : "null");
519 image_loader_free(imd->read_ahead_il);
520 imd->read_ahead_il = NULL;
522 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
523 imd->read_ahead_pixbuf = NULL;
525 file_data_unref(imd->read_ahead_fd);
526 imd->read_ahead_fd = NULL;
529 static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
531 ImageWindow *imd = data;
533 if (debug) printf("read ahead done for :%s\n", imd->read_ahead_fd->path);
535 imd->read_ahead_pixbuf = image_loader_get_pixbuf(imd->read_ahead_il);
536 if (imd->read_ahead_pixbuf)
538 g_object_ref(imd->read_ahead_pixbuf);
542 imd->read_ahead_pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
544 image_loader_free(imd->read_ahead_il);
545 imd->read_ahead_il = NULL;
547 image_complete_util(imd, TRUE);
550 static void image_read_ahead_error_cb(ImageLoader *il, gpointer data)
552 /* we even treat errors as success, maybe at least some of the file was ok */
553 image_read_ahead_done_cb(il, data);
556 static void image_read_ahead_start(ImageWindow *imd)
558 /* already started ? */
559 if (!imd->read_ahead_fd || imd->read_ahead_il || imd->read_ahead_pixbuf) return;
561 /* still loading ?, do later */
562 if (imd->il || imd->cm) return;
564 if (debug) printf("read ahead started for :%s\n", imd->read_ahead_fd->path);
566 imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
568 image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
569 if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
571 image_read_ahead_cancel(imd);
572 image_complete_util(imd, TRUE);
576 static void image_read_ahead_set(ImageWindow *imd, FileData *fd)
578 if (imd->read_ahead_fd && fd && imd->read_ahead_fd == fd) return;
580 image_read_ahead_cancel(imd);
582 imd->read_ahead_fd = file_data_ref(fd);
584 if (debug) printf("read ahead set to :%s\n", imd->read_ahead_fd->path);
586 image_read_ahead_start(imd);
590 *-------------------------------------------------------------------
592 *-------------------------------------------------------------------
595 static void image_post_buffer_set(ImageWindow *imd, FileData *fd, GdkPixbuf *pixbuf, gint color_row)
597 file_data_unref(imd->prev_fd);
598 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
602 imd->prev_fd = file_data_ref(fd);
604 g_object_ref(pixbuf);
605 imd->prev_pixbuf = pixbuf;
606 imd->prev_color_row = color_row;
611 imd->prev_pixbuf = NULL;
612 imd->prev_color_row = -1;
615 if (debug) printf("post buffer set: %s\n", fd ? fd->path : "null");
618 static gint image_post_buffer_get(ImageWindow *imd)
622 if (imd->prev_pixbuf &&
623 imd->image_fd && imd->prev_fd && imd->image_fd == imd->prev_fd)
625 image_change_pixbuf(imd, imd->prev_pixbuf, image_zoom_get(imd));
626 if (imd->prev_color_row >= 0)
628 ExifData *exif = NULL;
630 if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd, TRUE);
631 image_post_process_color(imd, imd->prev_color_row, exif);
641 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
642 imd->prev_pixbuf = NULL;
644 file_data_unref(imd->prev_fd);
651 *-------------------------------------------------------------------
653 *-------------------------------------------------------------------
656 static void image_load_pixbuf_ready(ImageWindow *imd)
658 if (image_get_pixbuf(imd) || !imd->il) return;
660 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
663 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
665 ImageWindow *imd = data;
668 pr = (PixbufRenderer *)imd->pr;
670 if (imd->delay_flip &&
671 pr->pixbuf != image_loader_get_pixbuf(il))
676 if (!pr->pixbuf) image_load_pixbuf_ready(imd);
678 pixbuf_renderer_area_changed(pr, x, y, w, h);
681 static void image_load_done_cb(ImageLoader *il, gpointer data)
683 ImageWindow *imd = data;
685 if (debug) printf ("image done\n");
687 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
688 image_state_unset(imd, IMAGE_STATE_LOADING);
690 if (imd->delay_flip &&
691 image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
693 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
694 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
697 image_loader_free(imd->il);
700 image_post_process(imd, TRUE);
702 image_read_ahead_start(imd);
705 static void image_load_error_cb(ImageLoader *il, gpointer data)
707 if (debug) printf ("image error\n");
709 /* even on error handle it like it was done,
710 * since we have a pixbuf with _something_ */
712 image_load_done_cb(il, data);
715 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
716 static void image_load_buffer_throttle(ImageLoader *il)
718 if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
720 /* Larger image files usually have larger chunks of data per pixel...
721 * So increase the buffer read size so that the rendering chunks called
725 image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
729 /* this read ahead is located here merely for the callbacks, above */
731 static gint image_read_ahead_check(ImageWindow *imd)
733 if (!imd->read_ahead_fd) return FALSE;
734 if (imd->il) return FALSE;
736 if (!imd->image_fd || imd->read_ahead_fd != imd->image_fd)
738 image_read_ahead_cancel(imd);
742 if (imd->read_ahead_il)
744 imd->il = imd->read_ahead_il;
745 imd->read_ahead_il = NULL;
747 /* override the old signals */
748 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
749 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
750 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
752 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
753 image_load_buffer_throttle(imd->il);
756 /* do this one directly (probably should add a set func) */
757 imd->il->func_done = image_load_done_cb;
759 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
760 image_state_set(imd, IMAGE_STATE_LOADING);
762 if (!imd->delay_flip)
764 image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
767 image_read_ahead_cancel(imd);
770 else if (imd->read_ahead_pixbuf)
772 image_change_pixbuf(imd, imd->read_ahead_pixbuf, image_zoom_get(imd));
773 g_object_unref(imd->read_ahead_pixbuf);
774 imd->read_ahead_pixbuf = NULL;
776 image_read_ahead_cancel(imd);
778 image_post_process(imd, FALSE);
782 image_read_ahead_cancel(imd);
786 static gint image_load_begin(ImageWindow *imd, FileData *fd)
788 if (debug) printf ("image begin \n");
790 if (imd->il) return FALSE;
792 imd->completed = FALSE;
793 g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
795 if (image_post_buffer_get(imd))
797 if (debug) printf("from post buffer: %s\n", imd->image_fd->path);
801 if (image_read_ahead_check(imd))
803 if (debug) printf("from read ahead buffer: %s\n", imd->image_fd->path);
807 if (!imd->delay_flip && image_get_pixbuf(imd))
811 pr = PIXBUF_RENDERER(imd->pr);
812 if (pr->pixbuf) g_object_unref(pr->pixbuf);
816 g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
818 imd->il = image_loader_new(fd);
820 image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
821 image_loader_set_error_func(imd->il, image_load_error_cb, imd);
822 image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
824 if (!image_loader_start(imd->il, image_load_done_cb, imd))
826 if (debug) printf("image start error\n");
828 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
830 image_loader_free(imd->il);
833 image_complete_util(imd, FALSE);
838 image_state_set(imd, IMAGE_STATE_LOADING);
840 #ifdef IMAGE_THROTTLE_LARGER_IMAGES
841 image_load_buffer_throttle(imd->il);
844 if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
849 static void image_reset(ImageWindow *imd)
851 /* stops anything currently being done */
853 if (debug) printf("image reset\n");
855 g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
857 image_loader_free(imd->il);
860 color_man_free((ColorMan *)imd->cm);
863 imd->delay_alter_type = ALTER_NONE;
865 image_state_set(imd, IMAGE_STATE_NONE);
869 *-------------------------------------------------------------------
871 *-------------------------------------------------------------------
874 static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
878 if (imd->image_fd && isfile(imd->image_fd->path))
882 pr = PIXBUF_RENDERER(imd->pr);
883 pr->zoom = zoom; /* store the zoom, needed by the loader */
885 if (image_load_begin(imd, imd->image_fd))
887 imd->unknown = FALSE;
893 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
894 image_change_pixbuf(imd, pixbuf, zoom);
895 g_object_unref(pixbuf);
899 imd->size = filesize(imd->image_fd->path);
900 imd->mtime = filetime(imd->image_fd->path);
908 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
909 image_change_pixbuf(imd, pixbuf, zoom);
910 g_object_unref(pixbuf);
911 imd->mtime = filetime(imd->image_fd->path);
915 image_change_pixbuf(imd, NULL, zoom);
922 image_update_util(imd);
925 static void image_change_real(ImageWindow *imd, FileData *fd,
926 CollectionData *cd, CollectInfo *info, gdouble zoom)
929 GdkPixbuf *prev_pixbuf = NULL;
930 FileData *prev_fd = NULL;
931 gint prev_clear = FALSE;
932 gint prev_color_row = -1;
934 imd->collection = cd;
935 imd->collection_info = info;
937 pixbuf = image_get_pixbuf(imd);
939 if (enable_read_ahead && imd->image_fd && pixbuf)
943 /* current image is not finished */
948 prev_fd = file_data_ref(imd->image_fd);
949 prev_pixbuf = pixbuf;
950 g_object_ref(prev_pixbuf);
956 cm = (ColorMan *)imd->cm;
957 prev_color_row = cm->row;
962 file_data_unref(imd->image_fd);
963 imd->image_fd = file_data_ref(fd);
965 image_change_complete(imd, zoom, TRUE);
969 image_post_buffer_set(imd, prev_fd, prev_pixbuf, prev_color_row);
970 file_data_unref(prev_fd);
971 g_object_unref(prev_pixbuf);
975 image_post_buffer_set(imd, NULL, NULL, -1);
978 image_update_title(imd);
979 image_state_set(imd, IMAGE_STATE_IMAGE);
983 *-------------------------------------------------------------------
985 *-------------------------------------------------------------------
988 static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area)
992 widget = imd->widget;
993 if (!widget->window) return;
997 gtk_paint_focus (widget->style, widget->window, GTK_STATE_ACTIVE,
998 area, widget, "image_window",
999 widget->allocation.x, widget->allocation.y,
1000 widget->allocation.width - 1, widget->allocation.height - 1);
1004 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1005 area, widget, "image_window",
1006 widget->allocation.x, widget->allocation.y,
1007 widget->allocation.width - 1, widget->allocation.height - 1);
1011 static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
1013 ImageWindow *imd = data;
1015 image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area);
1019 static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1021 ImageWindow *imd = data;
1023 GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1024 image_focus_paint(imd, TRUE, NULL);
1029 static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
1031 ImageWindow *imd = data;
1033 GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS);
1034 image_focus_paint(imd, FALSE, NULL);
1039 gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
1040 gint relative, gint always)
1042 return pixbuf_renderer_overlay_add((PixbufRenderer *)imd->pr, pixbuf, x, y, relative, always);
1045 void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
1047 pixbuf_renderer_overlay_set((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1050 gint image_overlay_get(ImageWindow *imd, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
1052 return pixbuf_renderer_overlay_get((PixbufRenderer *)imd->pr, id, pixbuf, x, y);
1055 void image_overlay_remove(ImageWindow *imd, gint id)
1057 pixbuf_renderer_overlay_remove((PixbufRenderer *)imd->pr, id);
1060 static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data)
1062 ImageWindow *imd = data;
1064 if (imd->func_scroll &&
1065 event && event->type == GDK_SCROLL)
1067 imd->func_scroll(imd, event->direction, event->time,
1068 event->x, event->y, event->state, imd->data_scroll);
1076 *-------------------------------------------------------------------
1078 *-------------------------------------------------------------------
1081 void image_attach_window(ImageWindow *imd, GtkWidget *window,
1082 const gchar *title, const gchar *title_right, gint show_zoom)
1084 imd->top_window = window;
1086 imd->title = g_strdup(title);
1087 g_free(imd->title_right);
1088 imd->title_right = g_strdup(title_right);
1089 imd->title_show_zoom = show_zoom;
1091 if (!fit_window) window = NULL;
1093 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)window);
1095 image_update_title(imd);
1098 void image_set_update_func(ImageWindow *imd,
1099 void (*func)(ImageWindow *imd, gpointer data),
1102 imd->func_update = func;
1103 imd->data_update = data;
1106 void image_set_complete_func(ImageWindow *imd,
1107 void (*func)(ImageWindow *imd, gint preload, gpointer data),
1110 imd->func_complete = func;
1111 imd->data_complete = data;
1114 void image_set_state_func(ImageWindow *imd,
1115 void (*func)(ImageWindow *imd, ImageState state, gpointer data),
1118 imd->func_state = func;
1119 imd->data_state = data;
1123 void image_set_button_func(ImageWindow *imd,
1124 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1127 imd->func_button = func;
1128 imd->data_button = data;
1131 void image_set_drag_func(ImageWindow *imd,
1132 void (*func)(ImageWindow *, gint button, guint32 time, gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer),
1135 imd->func_drag = func;
1136 imd->data_drag = data;
1139 void image_set_scroll_func(ImageWindow *imd,
1140 void (*func)(ImageWindow *, GdkScrollDirection direction, guint32 time, gdouble x, gdouble y, guint state, gpointer),
1143 imd->func_scroll = func;
1144 imd->data_scroll = data;
1147 void image_set_scroll_notify_func(ImageWindow *imd,
1148 void (*func)(ImageWindow *imd, gint x, gint y, gint width, gint height, gpointer data),
1151 imd->func_scroll_notify = func;
1152 imd->data_scroll_notify = data;
1157 const gchar *image_get_path(ImageWindow *imd)
1159 if (imd->image_fd == NULL) return NULL;
1160 return imd->image_fd->path;
1163 const gchar *image_get_name(ImageWindow *imd)
1165 if (imd->image_fd == NULL) return NULL;
1166 return imd->image_fd->name;
1169 FileData *image_get_fd(ImageWindow *imd)
1171 return imd->image_fd;
1174 /* merely changes path string, does not change the image! */
1175 void image_set_fd(ImageWindow *imd, FileData *fd)
1177 file_data_unref(imd->image_fd);
1178 imd->image_fd = file_data_ref(fd);
1180 image_update_title(imd);
1181 image_state_set(imd, IMAGE_STATE_IMAGE);
1184 /* load a new image */
1186 void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom)
1188 if (imd->image_fd == fd) return;
1190 image_change_real(imd, fd, NULL, NULL, zoom);
1193 GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
1195 return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
1198 void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
1200 pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
1201 image_state_set(imd, IMAGE_STATE_IMAGE);
1204 void image_change_from_collection(ImageWindow *imd, CollectionData *cd, CollectInfo *info, gdouble zoom)
1206 if (!cd || !info || !g_list_find(cd->list, info)) return;
1208 image_change_real(imd, info->fd, cd, info, zoom);
1211 CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
1213 if (collection_to_number(imd->collection) >= 0)
1215 if (g_list_find(imd->collection->list, imd->collection_info) != NULL)
1217 if (info) *info = imd->collection_info;
1221 if (info) *info = NULL;
1223 return imd->collection;
1226 if (info) *info = NULL;
1230 static void image_loader_sync_data(ImageLoader *il, gpointer data)
1232 /* change data for the callbacks directly */
1234 il->data_area_ready = data;
1235 il->data_error = data;
1236 il->data_done = data;
1237 il->data_percent = data;
1240 /* this is more like a move function
1241 * it moves most data from source to imd
1243 void image_change_from_image(ImageWindow *imd, ImageWindow *source)
1245 if (imd == source) return;
1247 imd->unknown = source->unknown;
1249 imd->collection = source->collection;
1250 imd->collection_info = source->collection_info;
1251 imd->size = source->size;
1252 imd->mtime = source->mtime;
1254 image_set_fd(imd, image_get_fd(source));
1256 image_loader_free(imd->il);
1261 imd->il = source->il;
1264 image_loader_sync_data(imd->il, imd);
1266 imd->delay_alter_type = source->delay_alter_type;
1267 source->delay_alter_type = ALTER_NONE;
1270 imd->color_profile_enable = source->color_profile_enable;
1271 imd->color_profile_input = source->color_profile_input;
1272 imd->color_profile_screen = source->color_profile_screen;
1273 imd->color_profile_use_image = source->color_profile_use_image;
1274 color_man_free((ColorMan *)imd->cm);
1280 imd->cm = source->cm;
1283 cm = (ColorMan *)imd->cm;
1285 cm->func_done_data = imd;
1288 image_loader_free(imd->read_ahead_il);
1289 imd->read_ahead_il = source->read_ahead_il;
1290 source->read_ahead_il = NULL;
1291 if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
1293 if (imd->read_ahead_pixbuf) g_object_unref(imd->read_ahead_pixbuf);
1294 imd->read_ahead_pixbuf = source->read_ahead_pixbuf;
1295 source->read_ahead_pixbuf = NULL;
1297 file_data_unref(imd->read_ahead_fd);
1298 imd->read_ahead_fd = source->read_ahead_fd;
1299 source->read_ahead_fd = NULL;
1301 if (imd->prev_pixbuf) g_object_unref(imd->prev_pixbuf);
1302 imd->prev_pixbuf = source->prev_pixbuf;
1303 source->prev_pixbuf = NULL;
1304 imd->prev_color_row = source->prev_color_row;
1305 source->prev_color_row = -1;
1307 file_data_unref(imd->prev_fd);
1308 imd->prev_fd = source->prev_fd;
1309 source->prev_fd = NULL;
1311 imd->completed = source->completed;
1312 imd->state = source->state;
1313 source->state = IMAGE_STATE_NONE;
1315 pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr));
1320 void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height)
1322 pixbuf_renderer_area_changed((PixbufRenderer *)imd->pr, x, y, width, height);
1325 void image_reload(ImageWindow *imd)
1327 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1329 image_change_complete(imd, image_zoom_get(imd), FALSE);
1332 void image_scroll(ImageWindow *imd, gint x, gint y)
1334 pixbuf_renderer_scroll((PixbufRenderer *)imd->pr, x, y);
1337 void image_scroll_to_point(ImageWindow *imd, gint x, gint y,
1338 gdouble x_align, gdouble y_align)
1340 pixbuf_renderer_scroll_to_point((PixbufRenderer *)imd->pr, x, y, x_align, y_align);
1343 void image_get_scroll_center(ImageWindow *imd, gdouble *x, gdouble *y)
1345 pixbuf_renderer_get_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1348 void image_set_scroll_center(ImageWindow *imd, gdouble x, gdouble y)
1350 pixbuf_renderer_set_scroll_center(PIXBUF_RENDERER(imd->pr), x, y);
1355 void image_alter(ImageWindow *imd, AlterType type)
1357 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1359 if (imd->il || imd->cm)
1361 /* still loading, wait till done */
1362 imd->delay_alter_type = type;
1363 image_state_set(imd, IMAGE_STATE_ROTATE_USER);
1365 if (imd->cm && (imd->state & IMAGE_STATE_ROTATE_AUTO))
1367 image_state_unset(imd, IMAGE_STATE_ROTATE_AUTO);
1372 image_alter_real(imd, type, TRUE);
1375 void image_zoom_adjust(ImageWindow *imd, gdouble increment)
1377 pixbuf_renderer_zoom_adjust((PixbufRenderer *)imd->pr, increment);
1380 void image_zoom_adjust_at_point(ImageWindow *imd, gdouble increment, gint x, gint y)
1382 pixbuf_renderer_zoom_adjust_at_point((PixbufRenderer *)imd->pr, increment, x, y);
1385 void image_zoom_set_limits(ImageWindow *imd, gdouble min, gdouble max)
1387 pixbuf_renderer_zoom_set_limits((PixbufRenderer *)imd->pr, min, max);
1390 void image_zoom_set(ImageWindow *imd, gdouble zoom)
1392 pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
1395 void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
1401 pr = (PixbufRenderer *)imd->pr;
1403 if (!pixbuf_renderer_get_pixbuf(pr) ||
1404 !pixbuf_renderer_get_image_size(pr, &width, &height)) return;
1408 zoom = (gdouble)pr->window_height / height;
1412 zoom = (gdouble)pr->window_width / width;
1417 zoom = 0.0 - 1.0 / zoom;
1420 pixbuf_renderer_zoom_set(pr, zoom);
1423 gdouble image_zoom_get(ImageWindow *imd)
1425 return pixbuf_renderer_zoom_get((PixbufRenderer *)imd->pr);
1428 gdouble image_zoom_get_real(ImageWindow *imd)
1430 return pixbuf_renderer_zoom_get_scale((PixbufRenderer *)imd->pr);
1433 gchar *image_zoom_get_as_text(ImageWindow *imd)
1441 gchar *approx = " ";
1443 zoom = image_zoom_get(imd);
1444 scale = image_zoom_get_real(imd);
1450 else if (zoom < 0.0)
1454 else if (zoom == 0.0 && scale != 0.0)
1467 if (rint(l) != l) pl = 1;
1468 if (rint(r) != r) pr = 1;
1470 return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r);
1473 gdouble image_zoom_get_default(ImageWindow *imd, gint mode)
1477 if (mode == ZOOM_RESET_ORIGINAL)
1481 else if (mode == ZOOM_RESET_FIT_WINDOW)
1489 zoom = image_zoom_get(imd);
1502 void image_prebuffer_set(ImageWindow *imd, FileData *fd)
1504 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1508 image_read_ahead_set(imd, fd);
1512 image_read_ahead_cancel(imd);
1516 static gint image_auto_refresh_cb(gpointer data)
1518 ImageWindow *imd = data;
1521 if (!imd || !image_get_pixbuf(imd) ||
1522 imd->il || !imd->image_fd ||
1523 !update_on_time_change) return TRUE;
1525 newtime = filetime(imd->image_fd->path);
1526 if (newtime > 0 && newtime != imd->mtime)
1528 imd->mtime = newtime;
1535 /* image auto refresh on time stamp change, in 1/1000's second, -1 disables */
1537 void image_auto_refresh(ImageWindow *imd, gint interval)
1540 if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return;
1542 if (imd->auto_refresh_id > -1)
1544 g_source_remove(imd->auto_refresh_id);
1545 imd->auto_refresh_id = -1;
1546 imd->auto_refresh_interval = -1;
1549 if (interval < 0) return;
1551 if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME;
1553 imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd);
1554 imd->auto_refresh_interval = interval;
1557 void image_top_window_set_sync(ImageWindow *imd, gint allow_sync)
1559 imd->top_window_sync = allow_sync;
1561 g_object_set(G_OBJECT(imd->pr), "window_fit", allow_sync, NULL);
1564 void image_background_set_color(ImageWindow *imd, GdkColor *color)
1566 pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color);
1569 void image_color_profile_set(ImageWindow *imd,
1570 gint input_type, gint screen_type,
1575 if (input_type < 0 || input_type > COLOR_PROFILE_INPUTS ||
1576 screen_type < 0 || screen_type > 1)
1581 imd->color_profile_input = input_type;
1582 imd->color_profile_screen = screen_type;
1583 imd->color_profile_use_image = use_image;
1586 gint image_color_profile_get(ImageWindow *imd,
1587 gint *input_type, gint *screen_type,
1590 if (!imd) return FALSE;
1592 if (input_type) *input_type = imd->color_profile_input;
1593 if (screen_type) *screen_type = imd->color_profile_screen;
1594 if (use_image) *use_image = imd->color_profile_use_image;
1599 void image_color_profile_set_use(ImageWindow *imd, gint enable)
1603 if (imd->color_profile_enable == enable) return;
1605 imd->color_profile_enable = enable;
1608 gint image_color_profile_get_use(ImageWindow *imd)
1610 if (!imd) return FALSE;
1612 return imd->color_profile_enable;
1615 void image_set_delay_flip(ImageWindow *imd, gint delay)
1618 imd->delay_flip == delay) return;
1620 imd->delay_flip = delay;
1622 g_object_set(G_OBJECT(imd->pr), "delay_flip", delay, NULL);
1624 if (!imd->delay_flip && imd->il)
1628 pr = PIXBUF_RENDERER(imd->pr);
1629 if (pr->pixbuf) g_object_unref(pr->pixbuf);
1632 image_load_pixbuf_ready(imd);
1636 void image_to_root_window(ImageWindow *imd, gint scaled)
1639 GdkWindow *rootwindow;
1647 pixbuf = image_get_pixbuf(imd);
1648 if (!pixbuf) return;
1650 screen = gtk_widget_get_screen(imd->widget);
1651 rootwindow = gdk_screen_get_root_window(screen);
1652 if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return;
1656 width = gdk_screen_width();
1657 height = gdk_screen_height();
1661 pixbuf_renderer_get_scaled_size((PixbufRenderer *)imd->pr, &width, &height);
1664 pb = gdk_pixbuf_scale_simple(pixbuf, width, height, (GdkInterpType)zoom_quality);
1666 gdk_pixbuf_render_pixmap_and_mask (pb, &pixmap, NULL, 128);
1667 gdk_window_set_back_pixmap(rootwindow, pixmap, FALSE);
1668 gdk_window_clear(rootwindow);
1670 g_object_unref(pixmap);
1675 void image_select(ImageWindow *imd, gboolean select)
1681 gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED);
1682 gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */
1685 gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL);
1691 void image_set_selectable(ImageWindow *imd, gboolean selectable)
1697 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1698 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 4);
1702 gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE);
1703 gtk_container_set_border_width (GTK_CONTAINER (imd->frame), 0);
1709 *-------------------------------------------------------------------
1711 *-------------------------------------------------------------------
1714 static void image_options_set(ImageWindow *imd)
1716 g_object_set(G_OBJECT(imd->pr), "zoom_quality", zoom_quality,
1717 "zoom_2pass", two_pass_zoom,
1718 "zoom_expand", zoom_to_fit_expands,
1719 "dither_quality", dither_quality,
1720 "scroll_reset", scroll_reset_method,
1721 "cache_display", tile_cache_max,
1722 "window_fit", (imd->top_window_sync && fit_window),
1723 "window_limit", limit_window_size,
1724 "window_limit_value", max_window_size,
1725 "autofit_limit", limit_autofit_size,
1726 "autofit_limit_value", max_autofit_size,
1730 pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window);
1733 void image_options_sync(void)
1745 image_options_set(imd);
1750 *-------------------------------------------------------------------
1752 *-------------------------------------------------------------------
1755 static void image_free(ImageWindow *imd)
1757 image_list = g_list_remove(image_list, imd);
1761 image_read_ahead_cancel(imd);
1762 image_post_buffer_set(imd, NULL, NULL, -1);
1763 image_auto_refresh(imd, -1);
1765 file_data_unref(imd->image_fd);
1767 g_free(imd->title_right);
1772 static void image_destroy_cb(GtkObject *widget, gpointer data)
1774 ImageWindow *imd = data;
1778 gboolean selectable_frame_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1780 gtk_paint_flat_box(widget->style,
1783 GTK_FRAME (widget)->shadow_type,
1787 widget->allocation.x + 3, widget->allocation.y + 3,
1788 widget->allocation.width - 6, widget->allocation.height - 6);
1795 void image_set_frame(ImageWindow *imd, gboolean frame)
1799 if (frame == imd->has_frame) return;
1801 gtk_widget_hide(imd->pr);
1805 imd->frame = gtk_frame_new(NULL);
1806 gtk_widget_ref(imd->pr);
1807 if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
1808 gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
1809 gtk_widget_unref(imd->pr);
1810 g_signal_connect (G_OBJECT (imd->frame), "expose_event",
1811 G_CALLBACK (selectable_frame_expose_cb), NULL);
1813 GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS);
1814 g_signal_connect(G_OBJECT(imd->frame), "focus_in_event",
1815 G_CALLBACK(image_focus_in_cb), imd);
1816 g_signal_connect(G_OBJECT(imd->frame), "focus_out_event",
1817 G_CALLBACK(image_focus_out_cb), imd);
1819 g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
1820 G_CALLBACK(image_focus_expose), imd);
1823 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
1824 gtk_widget_show(imd->frame);
1828 gtk_widget_ref(imd->pr);
1831 gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
1832 gtk_widget_destroy(imd->frame);
1835 gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
1836 gtk_widget_unref(imd->pr);
1839 gtk_widget_show(imd->pr);
1841 imd->has_frame = frame;
1844 ImageWindow *image_new(gint frame)
1848 imd = g_new0(ImageWindow, 1);
1850 imd->top_window = NULL;
1852 imd->title_right = NULL;
1853 imd->title_show_zoom = FALSE;
1855 imd->unknown = TRUE;
1857 imd->has_frame = -1; /* not initialized; for image_set_frame */
1858 imd->top_window_sync = FALSE;
1860 imd->delay_alter_type = ALTER_NONE;
1862 imd->read_ahead_il = NULL;
1863 imd->read_ahead_pixbuf = NULL;
1864 imd->read_ahead_fd = NULL;
1866 imd->completed = FALSE;
1867 imd->state = IMAGE_STATE_NONE;
1869 imd->color_profile_enable = FALSE;
1870 imd->color_profile_input = 0;
1871 imd->color_profile_screen = 0;
1872 imd->color_profile_use_image = FALSE;
1874 imd->auto_refresh_id = -1;
1875 imd->auto_refresh_interval = -1;
1877 imd->delay_flip = FALSE;
1879 imd->func_update = NULL;
1880 imd->func_complete = NULL;
1881 imd->func_tile_request = NULL;
1882 imd->func_tile_dispose = NULL;
1884 imd->func_button = NULL;
1885 imd->func_scroll = NULL;
1887 imd->pr = GTK_WIDGET(pixbuf_renderer_new());
1889 image_options_set(imd);
1892 imd->widget = gtk_vbox_new(0, 0);
1894 image_set_frame(imd, frame);
1896 image_set_selectable(imd, 0);
1898 g_signal_connect(G_OBJECT(imd->pr), "clicked",
1899 G_CALLBACK(image_click_cb), imd);
1900 g_signal_connect(G_OBJECT(imd->pr), "scroll_notify",
1901 G_CALLBACK(image_scroll_notify_cb), imd);
1903 g_signal_connect(G_OBJECT(imd->pr), "scroll_event",
1904 G_CALLBACK(image_scroll_cb), imd);
1906 g_signal_connect(G_OBJECT(imd->pr), "destroy",
1907 G_CALLBACK(image_destroy_cb), imd);
1909 g_signal_connect(G_OBJECT(imd->pr), "zoom",
1910 G_CALLBACK(image_zoom_cb), imd);
1911 g_signal_connect(G_OBJECT(imd->pr), "render_complete",
1912 G_CALLBACK(image_render_complete_cb), imd);
1913 g_signal_connect(G_OBJECT(imd->pr), "drag",
1914 G_CALLBACK(image_drag_cb), imd);
1916 image_list = g_list_append(image_list, imd);