X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fimage.c;h=e04037fce520573258937482f69dc2f9b476e681;hb=9c47109d3aa65663b0c95d454dadca43ce0ba7f4;hp=aaae255fd7860de2c6135bfe1e8d20e9f8e4243c;hpb=ed00275170d23e38bff5a01130e5056a799788c1;p=geeqie.git diff --git a/src/image.c b/src/image.c index aaae255f..e04037fc 100644 --- a/src/image.c +++ b/src/image.c @@ -1,16 +1,24 @@ /* - * Geeqie - * (C) 2006 John Ellis - * Copyright (C) 2008 The Geeqie Team + * Copyright (C) 2006 John Ellis + * Copyright (C) 2008 - 2016 The Geeqie Team * * Author: John Ellis * - * This software is released under the GNU General Public License (GNU GPL). - * Please read the included file COPYING for more information. - * This software comes with no warranty of any kind, use at your own risk! + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #include "main.h" #include "image.h" @@ -18,6 +26,7 @@ #include "collect.h" #include "color-man.h" #include "exif.h" +#include "metadata.h" #include "histogram.h" #include "image-load.h" #include "image-overlay.h" @@ -32,25 +41,8 @@ #include - -/* size of the image loader buffer (512 bytes x defined number) */ -#define IMAGE_LOAD_BUFFER_COUNT 8 - -/* define this so that more bytes are read per idle loop on larger images (> 1MB) */ -#define IMAGE_THROTTLE_LARGER_IMAGES 1 - -/* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */ -#define IMAGE_THROTTLE_FACTOR 32 - -/* the file size at which throttling take place */ -#define IMAGE_THROTTLE_THRESHOLD 1048576 - -#define IMAGE_AUTO_REFRESH_TIME 3000 - - static GList *image_list = NULL; - static void image_update_title(ImageWindow *imd); static void image_read_ahead_start(ImageWindow *imd); static void image_cache_set(ImageWindow *imd, FileData *fd); @@ -64,6 +56,10 @@ static void image_cache_set(ImageWindow *imd, FileData *fd); static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data) { ImageWindow *imd = data; + if (!options->image_lm_click_nav && event->button == MOUSE_BUTTON_MIDDLE) + { + imd->mouse_wheel_mode = !imd->mouse_wheel_mode; + } if (imd->func_button) { @@ -71,7 +67,7 @@ static void image_click_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer d } } -static void image_drag_cb(PixbufRenderer *pr, GdkEventButton *event, gpointer data) +static void image_drag_cb(PixbufRenderer *pr, GdkEventMotion *event, gpointer data) { ImageWindow *imd = data; gint width, height; @@ -107,17 +103,8 @@ static void image_update_util(ImageWindow *imd) if (imd->func_update) imd->func_update(imd, imd->data_update); } -static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data) -{ - ImageWindow *imd = data; - - if (imd->title_show_zoom) image_update_title(imd); - if (imd->overlay_show_zoom) image_osd_update(imd); - - image_update_util(imd); -} -static void image_complete_util(ImageWindow *imd, gint preload) +static void image_complete_util(ImageWindow *imd, gboolean preload) { if (imd->il && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) return; @@ -156,6 +143,15 @@ static void image_state_unset(ImageWindow *imd, ImageState state) if (imd->func_state) imd->func_state(imd, state, imd->data_state); } +static void image_zoom_cb(PixbufRenderer *pr, gdouble zoom, gpointer data) +{ + ImageWindow *imd = data; + + if (imd->title_show_zoom) image_update_title(imd); + image_state_set(imd, IMAGE_STATE_IMAGE); + image_update_util(imd); +} + /* *------------------------------------------------------------------- * misc @@ -172,10 +168,9 @@ static void image_update_title(ImageWindow *imd) if (imd->collection && collection_to_number(imd->collection) >= 0) { - const gchar *name; - name = imd->collection->name; + const gchar *name = imd->collection->name; if (!name) name = _("Untitled"); - collection = g_strdup_printf(" (Collection %s)", name); + collection = g_strdup_printf(_(" (Collection %s)"), name); } if (imd->title_show_zoom) @@ -205,29 +200,43 @@ static void image_update_title(ImageWindow *imd) * rotation, flip, etc. *------------------------------------------------------------------- */ +static gboolean image_get_x11_screen_profile(ImageWindow *imd, guchar **screen_profile, gint *screen_profile_len) +{ + GdkScreen *screen = gtk_widget_get_screen(imd->widget);; + GdkAtom type = GDK_NONE; + gint format = 0; + + return (gdk_property_get(gdk_screen_get_root_window(screen), + gdk_atom_intern ("_ICC_PROFILE", FALSE), + GDK_NONE, + 0, 64 * 1024 * 1024, FALSE, + &type, &format, screen_profile_len, screen_profile) && *screen_profile_len > 0); +} -static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData *exif, gint run_in_bg) +static gboolean image_post_process_color(ImageWindow *imd, gint start_row, gboolean run_in_bg) { ColorMan *cm; ColorManProfileType input_type; ColorManProfileType screen_type; - const gchar *input_file; - const gchar *screen_file; - unsigned char *profile = NULL; + const gchar *input_file = NULL; + const gchar *screen_file = NULL; + guchar *profile = NULL; guint profile_len; + guchar *screen_profile = NULL; + gint screen_profile_len; + ExifData *exif; if (imd->cm) return FALSE; if (imd->color_profile_input >= COLOR_PROFILE_FILE && imd->color_profile_input < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS) { - gint n; + const gchar *file = options->color_profile.input_file[imd->color_profile_input - COLOR_PROFILE_FILE]; - n = imd->color_profile_input - COLOR_PROFILE_FILE; - if (!options->color_profile.input_file[n]) return FALSE; + if (!is_readable_file(file)) return FALSE; input_type = COLOR_PROFILE_FILE; - input_file = options->color_profile.input_file[n]; + input_file = file; } else if (imd->color_profile_input >= COLOR_PROFILE_SRGB && imd->color_profile_input < COLOR_PROFILE_FILE) @@ -240,71 +249,103 @@ static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData return FALSE; } - if (imd->color_profile_screen == 1 && - options->color_profile.screen_file) + if (options->color_profile.use_x11_screen_profile && + image_get_x11_screen_profile(imd, &screen_profile, &screen_profile_len)) + { + screen_type = COLOR_PROFILE_MEM; + DEBUG_1("Using X11 screen profile, length: %d", screen_profile_len); + } + else if (options->color_profile.screen_file && + is_readable_file(options->color_profile.screen_file)) { screen_type = COLOR_PROFILE_FILE; screen_file = options->color_profile.screen_file; } - else if (imd->color_profile_screen == 0) + else { screen_type = COLOR_PROFILE_SRGB; screen_file = NULL; } - else - { - return FALSE; - } + + imd->color_profile_from_image = COLOR_PROFILE_NONE; - if (imd->color_profile_use_image && exif) + exif = exif_read_fd(imd->image_fd); + + if (exif) { profile = exif_get_color_profile(exif, &profile_len); - if (!profile) + if (profile) { - gint cs; - gchar *interop_index; - - /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */ - if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0; - interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex"); - - if (cs == 1) + if (!imd->color_profile_use_image) { - input_type = COLOR_PROFILE_SRGB; - input_file = NULL; - imd->color_profile_from_image = COLOR_PROFILE_SRGB; + g_free(profile); + profile = NULL; + } + DEBUG_1("Found embedded color profile"); + imd->color_profile_from_image = COLOR_PROFILE_MEM; + } + else + { + gchar *interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex"); - DEBUG_1("Found EXIF ColorSpace of sRGB"); + if (interop_index) + { + /* Exif 2.21 specification */ + if (!strcmp(interop_index, "R98")) + { + imd->color_profile_from_image = COLOR_PROFILE_SRGB; + DEBUG_1("Found EXIF 2.21 ColorSpace of sRGB"); + } + else if (!strcmp(interop_index, "R03")) + { + imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB; + DEBUG_1("Found EXIF 2.21 ColorSpace of AdobeRGB"); + } + g_free(interop_index); } - if (cs == 2 || (interop_index && !strcmp(interop_index, "R03"))) + else { - input_type = COLOR_PROFILE_ADOBERGB; - input_file = NULL; - imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB; - - DEBUG_1("Found EXIF ColorSpace of AdobeRGB"); + gint cs; + + /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */ + if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0; + if (cs == 1) + { + imd->color_profile_from_image = COLOR_PROFILE_SRGB; + DEBUG_1("Found EXIF 2.2 ColorSpace of sRGB"); + } + else if (cs == 2) + { + /* non-standard way of specifying AdobeRGB (used by some software) */ + imd->color_profile_from_image = COLOR_PROFILE_ADOBERGB; + DEBUG_1("Found EXIF 2.2 ColorSpace of AdobeRGB"); + } } - g_free(interop_index); + if (imd->color_profile_use_image && imd->color_profile_from_image != COLOR_PROFILE_NONE) + { + input_type = imd->color_profile_from_image; + input_file = NULL; + } } + + exif_free_fd(imd->image_fd, exif); } + if (profile) { - DEBUG_1("Found embedded color profile"); - imd->color_profile_from_image = COLOR_PROFILE_MEM; - cm = color_man_new_embedded(run_in_bg ? imd : NULL, NULL, profile, profile_len, - screen_type, screen_file); + screen_type, screen_file, screen_profile, screen_profile_len); g_free(profile); } else { cm = color_man_new(run_in_bg ? imd : NULL, NULL, input_type, input_file, - screen_type, screen_file); + screen_type, screen_file, screen_profile, screen_profile_len); } if (cm) @@ -316,13 +357,17 @@ static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData } imd->cm = (gpointer)cm; -#if 0 - if (run_in_bg) color_man_start_bg(imd->cm, image_post_process_color_cb, imd); -#endif - return TRUE; } - return FALSE; + image_update_util(imd); + + if (screen_profile) + { + g_free(screen_profile); + screen_profile = NULL; + } + + return !!cm; } @@ -334,7 +379,7 @@ static void image_post_process_tile_color_cb(PixbufRenderer *pr, GdkPixbuf **pix } -void image_alter(ImageWindow *imd, AlterType type) +void image_alter_orientation(ImageWindow *imd, FileData *fd_n, AlterType type) { static const gint rotate_90[] = {1, 6, 7, 8, 5, 2, 3, 4, 1}; static const gint rotate_90_cc[] = {1, 8, 5, 6, 7, 4, 1, 2, 3}; @@ -342,58 +387,100 @@ void image_alter(ImageWindow *imd, AlterType type) static const gint mirror[] = {1, 2, 1, 4, 3, 6, 5, 8, 7}; static const gint flip[] = {1, 4, 3, 2, 1, 8, 7, 6, 5}; + gint orientation; - if (!imd || !imd->pr) return; + if (!imd || !imd->pr || !imd->image_fd || !fd_n) return; - if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1; + orientation = EXIF_ORIENTATION_TOP_LEFT; + { + if (fd_n->user_orientation) + { + orientation = fd_n->user_orientation; + } + else + if (options->metadata.write_orientation) + { + orientation = metadata_read_int(fd_n, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT); + } + } switch (type) { case ALTER_ROTATE_90: - imd->orientation = rotate_90[imd->orientation]; + orientation = rotate_90[orientation]; break; case ALTER_ROTATE_90_CC: - imd->orientation = rotate_90_cc[imd->orientation]; + orientation = rotate_90_cc[orientation]; break; case ALTER_ROTATE_180: - imd->orientation = rotate_180[imd->orientation]; + orientation = rotate_180[orientation]; break; case ALTER_MIRROR: - imd->orientation = mirror[imd->orientation]; + orientation = mirror[orientation]; break; case ALTER_FLIP: - imd->orientation = flip[imd->orientation]; - break; - case ALTER_DESATURATE: - imd->desaturate = !imd->desaturate; + orientation = flip[orientation]; break; case ALTER_NONE: - imd->orientation = imd->image_fd->exif_orientation ? imd->image_fd->exif_orientation : 1; - imd->desaturate = FALSE; + orientation = fd_n->exif_orientation ? fd_n->exif_orientation : 1; break; default: return; break; } - if (type != ALTER_NONE && type != ALTER_DESATURATE) + if (orientation != (fd_n->exif_orientation ? fd_n->exif_orientation : 1)) { - if (imd->image_fd->user_orientation == 0) file_data_ref(imd->image_fd); - imd->image_fd->user_orientation = imd->orientation; + if (!options->metadata.write_orientation) + { + /* user_orientation does not work together with options->metadata.write_orientation, + use either one or the other. + we must however handle switching metadata.write_orientation on and off, therefore + we just disable referencing new fd's, not unreferencing the old ones + */ + if (fd_n->user_orientation == 0) file_data_ref(fd_n); + fd_n->user_orientation = orientation; + } } else { - if (imd->image_fd->user_orientation != 0) file_data_unref(imd->image_fd); - imd->image_fd->user_orientation = 0; + if (fd_n->user_orientation != 0) file_data_unref(fd_n); + fd_n->user_orientation = 0; } - pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation); + if (options->metadata.write_orientation) + { + if (type == ALTER_NONE) + { + metadata_write_revert(fd_n, ORIENTATION_KEY); + } + else + { + metadata_write_int(fd_n, ORIENTATION_KEY, orientation); + } + } + + if (imd->image_fd == fd_n && !(options->metadata.write_orientation && !options->image.exif_rotate_enable)) + { + imd->orientation = orientation; + pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, orientation); + } +} + +void image_set_desaturate(ImageWindow *imd, gboolean desaturate) +{ + imd->desaturate = desaturate; if (imd->cm || imd->desaturate) pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); else pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE); + pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation); } +gboolean image_get_desaturate(ImageWindow *imd) +{ + return imd->desaturate; +} /* *------------------------------------------------------------------- @@ -416,6 +503,8 @@ static void image_read_ahead_done_cb(ImageLoader *il, gpointer data) { ImageWindow *imd = data; + if (!imd->read_ahead_fd || !imd->read_ahead_il) return; + DEBUG_1("%s read ahead done for :%s", get_exec_time(), imd->read_ahead_fd->path); if (!imd->read_ahead_fd->pixbuf) @@ -426,10 +515,6 @@ static void image_read_ahead_done_cb(ImageLoader *il, gpointer data) g_object_ref(imd->read_ahead_fd->pixbuf); image_cache_set(imd, imd->read_ahead_fd); } - else - { - imd->read_ahead_fd->pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); - } } image_loader_free(imd->read_ahead_il); imd->read_ahead_il = NULL; @@ -455,8 +540,12 @@ static void image_read_ahead_start(ImageWindow *imd) imd->read_ahead_il = image_loader_new(imd->read_ahead_fd); - image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd); - if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd)) + image_loader_delay_area_ready(imd->read_ahead_il, TRUE); /* we will need the area_ready signals later */ + + g_signal_connect(G_OBJECT(imd->read_ahead_il), "error", (GCallback)image_read_ahead_error_cb, imd); + g_signal_connect(G_OBJECT(imd->read_ahead_il), "done", (GCallback)image_read_ahead_done_cb, imd); + + if (!image_loader_start(imd->read_ahead_il)) { image_read_ahead_cancel(imd); image_complete_util(imd, TRUE); @@ -488,7 +577,7 @@ static void image_cache_release_cb(FileData *fd) fd->pixbuf = NULL; } -static FileCacheData *image_get_cache() +static FileCacheData *image_get_cache(void) { static FileCacheData *cache = NULL; if (!cache) cache = file_cache_new(image_cache_release_cb, 1); @@ -501,6 +590,7 @@ static void image_cache_set(ImageWindow *imd, FileData *fd) g_assert(fd->pixbuf); file_cache_put(image_get_cache(), fd, (gulong)gdk_pixbuf_get_rowstride(fd->pixbuf) * (gulong)gdk_pixbuf_get_height(fd->pixbuf)); + file_data_send_notification(fd, NOTIFY_PIXBUF); /* to update histogram */ } static gint image_cache_get(ImageWindow *imd) @@ -511,10 +601,10 @@ static gint image_cache_get(ImageWindow *imd) if (success) { g_assert(imd->image_fd->pixbuf); - image_change_pixbuf(imd, imd->image_fd->pixbuf, image_zoom_get(imd)); + image_change_pixbuf(imd, imd->image_fd->pixbuf, image_zoom_get(imd), FALSE); } - - file_cache_dump(image_get_cache()); + +// file_cache_dump(image_get_cache()); return success; } @@ -528,7 +618,7 @@ static void image_load_pixbuf_ready(ImageWindow *imd) { if (image_get_pixbuf(imd) || !imd->il) return; - image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd)); + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), FALSE); } static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data) @@ -544,7 +634,7 @@ static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint return; } - if (!pr->pixbuf) image_load_pixbuf_ready(imd); + if (!pr->pixbuf) image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), TRUE); pixbuf_renderer_area_changed(pr, x, y, w, h); } @@ -555,20 +645,30 @@ static void image_load_done_cb(ImageLoader *il, gpointer data) DEBUG_1("%s image done", get_exec_time()); - g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL); - image_state_unset(imd, IMAGE_STATE_LOADING); - if (options->image.enable_read_ahead && imd->image_fd && !imd->image_fd->pixbuf && image_loader_get_pixbuf(imd->il)) { - imd->image_fd->pixbuf = gdk_pixbuf_ref(image_loader_get_pixbuf(imd->il)); + imd->image_fd->pixbuf = g_object_ref(image_loader_get_pixbuf(imd->il)); image_cache_set(imd, imd->image_fd); } + /* call the callback triggered by image_state after fd->pixbuf is set */ + g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL); + image_state_unset(imd, IMAGE_STATE_LOADING); - if (imd->delay_flip && + if (!image_loader_get_pixbuf(imd->il)) + { + GdkPixbuf *pixbuf; + + pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); + image_change_pixbuf(imd, pixbuf, image_zoom_get(imd), FALSE); + g_object_unref(pixbuf); + + imd->unknown = TRUE; + } + else if (imd->delay_flip && image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il)) { g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL); - image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd)); + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), FALSE); } image_loader_free(imd->il); @@ -579,6 +679,14 @@ static void image_load_done_cb(ImageLoader *il, gpointer data) image_read_ahead_start(imd); } +static void image_load_size_cb(ImageLoader *il, guint width, guint height, gpointer data) +{ + ImageWindow *imd = data; + + DEBUG_1("image_load_size_cb: %dx%d", width, height); + pixbuf_renderer_set_size_early((PixbufRenderer *)imd->pr, width, height); +} + static void image_load_error_cb(ImageLoader *il, gpointer data) { DEBUG_1("%s image error", get_exec_time()); @@ -589,23 +697,24 @@ static void image_load_error_cb(ImageLoader *il, gpointer data) image_load_done_cb(il, data); } -#ifdef IMAGE_THROTTLE_LARGER_IMAGES -static void image_load_buffer_throttle(ImageLoader *il) +static void image_load_set_signals(ImageWindow *imd, gboolean override_old_signals) { - if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return; - - /* Larger image files usually have larger chunks of data per pixel... - * So increase the buffer read size so that the rendering chunks called - * are also larger. - */ + g_assert(imd->il); + if (override_old_signals) + { + /* override the old signals */ + g_signal_handlers_disconnect_matched(G_OBJECT(imd->il), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, imd); + } - image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR); + g_signal_connect(G_OBJECT(imd->il), "area_ready", (GCallback)image_load_area_cb, imd); + g_signal_connect(G_OBJECT(imd->il), "error", (GCallback)image_load_error_cb, imd); + g_signal_connect(G_OBJECT(imd->il), "done", (GCallback)image_load_done_cb, imd); + g_signal_connect(G_OBJECT(imd->il), "size_prepared", (GCallback)image_load_size_cb, imd); } -#endif /* this read ahead is located here merely for the callbacks, above */ -static gint image_read_ahead_check(ImageWindow *imd) +static gboolean image_read_ahead_check(ImageWindow *imd) { if (!imd->read_ahead_fd) return FALSE; if (imd->il) return FALSE; @@ -621,33 +730,25 @@ static gint image_read_ahead_check(ImageWindow *imd) imd->il = imd->read_ahead_il; imd->read_ahead_il = NULL; - /* override the old signals */ - image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd); - image_loader_set_error_func(imd->il, image_load_error_cb, imd); - image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT); - -#ifdef IMAGE_THROTTLE_LARGER_IMAGES - image_load_buffer_throttle(imd->il); -#endif - - /* do this one directly (probably should add a set func) */ - imd->il->func_done = image_load_done_cb; + image_load_set_signals(imd, TRUE); g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL); image_state_set(imd, IMAGE_STATE_LOADING); if (!imd->delay_flip) { - image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd)); + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), TRUE); } + image_loader_delay_area_ready(imd->il, FALSE); /* send the delayed area_ready signals */ + file_data_unref(imd->read_ahead_fd); imd->read_ahead_fd = NULL; return TRUE; } else if (imd->read_ahead_fd->pixbuf) { - image_change_pixbuf(imd, imd->read_ahead_fd->pixbuf, image_zoom_get(imd)); + image_change_pixbuf(imd, imd->read_ahead_fd->pixbuf, image_zoom_get(imd), FALSE); file_data_unref(imd->read_ahead_fd); imd->read_ahead_fd = NULL; @@ -660,7 +761,7 @@ static gint image_read_ahead_check(ImageWindow *imd) return FALSE; } -static gint image_load_begin(ImageWindow *imd, FileData *fd) +static gboolean image_load_begin(ImageWindow *imd, FileData *fd) { DEBUG_1("%s image begin", get_exec_time()); @@ -694,11 +795,9 @@ static gint image_load_begin(ImageWindow *imd, FileData *fd) imd->il = image_loader_new(fd); - image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd); - image_loader_set_error_func(imd->il, image_load_error_cb, imd); - image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT); + image_load_set_signals(imd, FALSE); - if (!image_loader_start(imd->il, image_load_done_cb, imd)) + if (!image_loader_start(imd->il)) { DEBUG_1("image start error"); @@ -714,12 +813,12 @@ static gint image_load_begin(ImageWindow *imd, FileData *fd) image_state_set(imd, IMAGE_STATE_LOADING); -#ifdef IMAGE_THROTTLE_LARGER_IMAGES - image_load_buffer_throttle(imd->il); -#endif - - if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd); - +/* + if (!imd->delay_flip && !image_get_pixbuf(imd) && image_loader_get_pixbuf(imd->il)) + { + image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), TRUE); + } +*/ return TRUE; } @@ -748,52 +847,39 @@ static void image_reset(ImageWindow *imd) *------------------------------------------------------------------- */ -static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new) +static void image_change_complete(ImageWindow *imd, gdouble zoom) { image_reset(imd); + imd->unknown = TRUE; - if (imd->image_fd && isfile(imd->image_fd->path)) + if (!imd->image_fd) + { + image_change_pixbuf(imd, NULL, zoom, FALSE); + } + else { - PixbufRenderer *pr; - - pr = PIXBUF_RENDERER(imd->pr); - pr->zoom = zoom; /* store the zoom, needed by the loader */ - if (image_load_begin(imd, imd->image_fd)) + if (is_readable_file(imd->image_fd->path)) { - imd->unknown = FALSE; - } - else - { - GdkPixbuf *pixbuf; + PixbufRenderer *pr; - pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); - image_change_pixbuf(imd, pixbuf, zoom); - g_object_unref(pixbuf); + pr = PIXBUF_RENDERER(imd->pr); + pr->zoom = zoom; /* store the zoom, needed by the loader */ - imd->unknown = TRUE; + if (image_load_begin(imd, imd->image_fd)) + { + imd->unknown = FALSE; + } } - imd->size = filesize(imd->image_fd->path); - imd->mtime = filetime(imd->image_fd->path); - } - else - { - if (imd->image_fd) + + if (imd->unknown == TRUE) { GdkPixbuf *pixbuf; pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); - image_change_pixbuf(imd, pixbuf, zoom); + image_change_pixbuf(imd, pixbuf, zoom, FALSE); g_object_unref(pixbuf); - imd->mtime = filetime(imd->image_fd->path); } - else - { - image_change_pixbuf(imd, NULL, zoom); - imd->mtime = 0; - } - imd->unknown = TRUE; - imd->size = 0; } image_update_util(imd); @@ -806,13 +892,20 @@ static void image_change_real(ImageWindow *imd, FileData *fd, imd->collection = cd; imd->collection_info = info; + if (imd->auto_refresh && imd->image_fd) + file_data_unregister_real_time_monitor(imd->image_fd); + file_data_unref(imd->image_fd); imd->image_fd = file_data_ref(fd); - image_change_complete(imd, zoom, TRUE); + + image_change_complete(imd, zoom); image_update_title(imd); image_state_set(imd, IMAGE_STATE_IMAGE); + + if (imd->auto_refresh && imd->image_fd) + file_data_register_real_time_monitor(imd->image_fd); } /* @@ -821,58 +914,19 @@ static void image_change_real(ImageWindow *imd, FileData *fd, *------------------------------------------------------------------- */ -static void image_focus_paint(ImageWindow *imd, gint has_focus, GdkRectangle *area) +static gboolean image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data) { - GtkWidget *widget; - - widget = imd->widget; - if (!widget->window) return; + ImageWindow *imd = data; - if (has_focus) - { - gtk_paint_focus(widget->style, widget->window, GTK_STATE_ACTIVE, - area, widget, "image_window", - widget->allocation.x, widget->allocation.y, - widget->allocation.width - 1, widget->allocation.height - 1); - } - else + if (imd->func_focus_in) { - gtk_paint_shadow(widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN, - area, widget, "image_window", - widget->allocation.x, widget->allocation.y, - widget->allocation.width - 1, widget->allocation.height - 1); + imd->func_focus_in(imd, imd->data_focus_in); } -} - -static gint image_focus_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - ImageWindow *imd = data; - - image_focus_paint(imd, GTK_WIDGET_HAS_FOCUS(widget), &event->area); - return TRUE; -} - -static gint image_focus_in_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data) -{ - ImageWindow *imd = data; - - GTK_WIDGET_SET_FLAGS(imd->widget, GTK_HAS_FOCUS); - image_focus_paint(imd, TRUE, NULL); return TRUE; } -static gint image_focus_out_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data) -{ - ImageWindow *imd = data; - - GTK_WIDGET_UNSET_FLAGS(imd->widget, GTK_HAS_FOCUS); - image_focus_paint(imd, FALSE, NULL); - - return TRUE; -} - -static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data) +static gboolean image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer data) { ImageWindow *imd = data; @@ -893,7 +947,7 @@ static gint image_scroll_cb(GtkWidget *widget, GdkEventScroll *event, gpointer d */ void image_attach_window(ImageWindow *imd, GtkWidget *window, - const gchar *title, const gchar *title_right, gint show_zoom) + const gchar *title, const gchar *title_right, gboolean show_zoom) { imd->top_window = window; g_free(imd->title); @@ -918,7 +972,7 @@ void image_set_update_func(ImageWindow *imd, } void image_set_complete_func(ImageWindow *imd, - void (*func)(ImageWindow *imd, gint preload, gpointer data), + void (*func)(ImageWindow *imd, gboolean preload, gpointer data), gpointer data) { imd->func_complete = func; @@ -943,7 +997,7 @@ void image_set_button_func(ImageWindow *imd, } void image_set_drag_func(ImageWindow *imd, - void (*func)(ImageWindow *, GdkEventButton *event, gdouble dx, gdouble dy, gpointer), + void (*func)(ImageWindow *, GdkEventMotion *event, gdouble dx, gdouble dy, gpointer), gpointer data) { imd->func_drag = func; @@ -966,6 +1020,14 @@ void image_set_scroll_notify_func(ImageWindow *imd, imd->data_scroll_notify = data; } +void image_set_focus_in_func(ImageWindow *imd, + void (*func)(ImageWindow *, gpointer), + gpointer data) +{ + imd->func_focus_in = func; + imd->data_focus_in = data; +} + /* path, name */ const gchar *image_get_path(ImageWindow *imd) @@ -988,11 +1050,17 @@ FileData *image_get_fd(ImageWindow *imd) /* merely changes path string, does not change the image! */ void image_set_fd(ImageWindow *imd, FileData *fd) { + if (imd->auto_refresh && imd->image_fd) + file_data_unregister_real_time_monitor(imd->image_fd); + file_data_unref(imd->image_fd); imd->image_fd = file_data_ref(fd); image_update_title(imd); image_state_set(imd, IMAGE_STATE_IMAGE); + + if (imd->auto_refresh && imd->image_fd) + file_data_register_real_time_monitor(imd->image_fd); } /* load a new image */ @@ -1004,7 +1072,7 @@ void image_change_fd(ImageWindow *imd, FileData *fd, gdouble zoom) image_change_real(imd, fd, NULL, NULL, zoom); } -gint image_get_image_size(ImageWindow *imd, gint *width, gint *height) +gboolean image_get_image_size(ImageWindow *imd, gint *width, gint *height) { return pixbuf_renderer_get_image_size(PIXBUF_RENDERER(imd->pr), width, height); } @@ -1014,34 +1082,37 @@ GdkPixbuf *image_get_pixbuf(ImageWindow *imd) return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr); } -void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom) +void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom, gboolean lazy) { + StereoPixbufData stereo_data = STEREO_PIXBUF_DEFAULT; + /* read_exif and similar functions can actually notice that the file has changed and trigger + a notification that removes the pixbuf from cache and unrefs it. Therefore we must ref it + here before it is taken over by the renderer. */ + if (pixbuf) g_object_ref(pixbuf); - ExifData *exif = NULL; - gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image); - gint read_exif_for_orientation = FALSE; - - if (imd->image_fd && imd->image_fd->user_orientation) - imd->orientation = imd->image_fd->user_orientation; - else if (options->image.exif_rotate_enable) - read_exif_for_orientation = TRUE; - - if (read_exif_for_color_profile || read_exif_for_orientation) + imd->orientation = EXIF_ORIENTATION_TOP_LEFT; + if (imd->image_fd) { - gint orientation; - - exif = exif_read_fd(imd->image_fd); - - if (exif && read_exif_for_orientation) + if (imd->image_fd->user_orientation) { - if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation)) - imd->orientation = orientation; - else - imd->orientation = 1; + imd->orientation = imd->image_fd->user_orientation; + } + else if (options->image.exif_rotate_enable) + { + imd->orientation = metadata_read_int(imd->image_fd, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT); imd->image_fd->exif_orientation = imd->orientation; } } + if (pixbuf) + { + stereo_data = imd->user_stereo; + if (stereo_data == STEREO_PIXBUF_DEFAULT) + { + stereo_data = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(pixbuf), "stereo_data")); + } + } + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, FALSE); if (imd->cm) { @@ -1049,20 +1120,24 @@ void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom) imd->cm = NULL; } - pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom); - pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation); + if (lazy) + { + pixbuf_renderer_set_pixbuf_lazy((PixbufRenderer *)imd->pr, pixbuf, zoom, imd->orientation, stereo_data); + } + else + { + pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom); + pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation); + pixbuf_renderer_set_stereo_data((PixbufRenderer *)imd->pr, stereo_data); + } + + if (pixbuf) g_object_unref(pixbuf); if (imd->color_profile_enable) { - if (!image_post_process_color(imd, 0, exif, FALSE)) - { - /* fixme: note error to user */ -// image_state_set(imd, IMAGE_STATE_COLOR_ADJ); - } + image_post_process_color(imd, 0, FALSE); /* TODO: error handling */ } - exif_free_fd(imd->image_fd, exif); - if (imd->cm || imd->desaturate) pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); @@ -1095,20 +1170,31 @@ CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info) return NULL; } -static void image_loader_sync_data(ImageLoader *il, gpointer data) +static void image_loader_sync_read_ahead_data(ImageLoader *il, gpointer old_data, gpointer data) { - /* change data for the callbacks directly */ + if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_read_ahead_error_cb, old_data)) + g_signal_connect(G_OBJECT(il), "error", (GCallback)image_read_ahead_error_cb, data); - il->data_area_ready = data; - il->data_error = data; - il->data_done = data; - il->data_percent = data; + if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_read_ahead_done_cb, old_data)) + g_signal_connect(G_OBJECT(il), "done", (GCallback)image_read_ahead_done_cb, data); +} + +static void image_loader_sync_data(ImageLoader *il, gpointer old_data, gpointer data) +{ + if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_load_area_cb, old_data)) + g_signal_connect(G_OBJECT(il), "area_ready", (GCallback)image_load_area_cb, data); + + if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_load_error_cb, old_data)) + g_signal_connect(G_OBJECT(il), "error", (GCallback)image_load_error_cb, data); + + if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_load_done_cb, old_data)) + g_signal_connect(G_OBJECT(il), "done", (GCallback)image_load_done_cb, data); } /* this is more like a move function * it moves most data from source to imd */ -void image_change_from_image(ImageWindow *imd, ImageWindow *source) +void image_move_from_image(ImageWindow *imd, ImageWindow *source) { if (imd == source) return; @@ -1116,8 +1202,6 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source) imd->collection = source->collection; imd->collection_info = source->collection_info; - imd->size = source->size; - imd->mtime = source->mtime; image_loader_free(imd->il); imd->il = NULL; @@ -1130,7 +1214,7 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source) imd->il = source->il; source->il = NULL; - image_loader_sync_data(imd->il, imd); + image_loader_sync_data(imd->il, source, imd); imd->delay_alter_type = source->delay_alter_type; source->delay_alter_type = ALTER_NONE; @@ -1138,7 +1222,58 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source) imd->color_profile_enable = source->color_profile_enable; imd->color_profile_input = source->color_profile_input; - imd->color_profile_screen = source->color_profile_screen; + imd->color_profile_use_image = source->color_profile_use_image; + color_man_free((ColorMan *)imd->cm); + imd->cm = NULL; + if (source->cm) + { + ColorMan *cm; + + imd->cm = source->cm; + source->cm = NULL; + + cm = (ColorMan *)imd->cm; + cm->imd = imd; + cm->func_done_data = imd; + } + + file_data_unref(imd->read_ahead_fd); + source->read_ahead_fd = NULL; + + imd->orientation = source->orientation; + imd->desaturate = source->desaturate; + + imd->user_stereo = source->user_stereo; + + pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr)); + + if (imd->cm || imd->desaturate) + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); + else + pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, NULL, NULL, TRUE); + +} + +/* this is a copy function + * source stays unchanged + */ +void image_copy_from_image(ImageWindow *imd, ImageWindow *source) +{ + if (imd == source) return; + + imd->unknown = source->unknown; + + imd->collection = source->collection; + imd->collection_info = source->collection_info; + + image_loader_free(imd->il); + imd->il = NULL; + + image_set_fd(imd, image_get_fd(source)); + + + imd->color_profile_enable = source->color_profile_enable; + imd->color_profile_input = source->color_profile_input; imd->color_profile_use_image = source->color_profile_use_image; color_man_free((ColorMan *)imd->cm); imd->cm = NULL; @@ -1157,7 +1292,7 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source) image_loader_free(imd->read_ahead_il); imd->read_ahead_il = source->read_ahead_il; source->read_ahead_il = NULL; - if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd); + if (imd->read_ahead_il) image_loader_sync_read_ahead_data(imd->read_ahead_il, source, imd); file_data_unref(imd->read_ahead_fd); imd->read_ahead_fd = source->read_ahead_fd; @@ -1170,7 +1305,9 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source) imd->orientation = source->orientation; imd->desaturate = source->desaturate; - pixbuf_renderer_move(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr)); + imd->user_stereo = source->user_stereo; + + pixbuf_renderer_copy(PIXBUF_RENDERER(imd->pr), PIXBUF_RENDERER(source->pr)); if (imd->cm || imd->desaturate) pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) ); @@ -1179,6 +1316,7 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source) } + /* manipulation */ void image_area_changed(ImageWindow *imd, gint x, gint y, gint width, gint height) @@ -1190,7 +1328,7 @@ void image_reload(ImageWindow *imd) { if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; - image_change_complete(imd, image_zoom_get(imd), FALSE); + image_change_complete(imd, image_zoom_get(imd)); } void image_scroll(ImageWindow *imd, gint x, gint y) @@ -1234,7 +1372,7 @@ void image_zoom_set(ImageWindow *imd, gdouble zoom) pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom); } -void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical) +void image_zoom_set_fill_geometry(ImageWindow *imd, gboolean vertical) { PixbufRenderer *pr; gdouble zoom; @@ -1247,11 +1385,11 @@ void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical) if (vertical) { - zoom = (gdouble)pr->window_height / height; + zoom = (gdouble)pr->viewport_height / height; } else { - zoom = (gdouble)pr->window_width / width; + zoom = (gdouble)pr->viewport_width / width; } if (zoom < 1.0) @@ -1306,39 +1444,61 @@ gchar *image_zoom_get_as_text(ImageWindow *imd) approx = "~"; } - if (rint(l) != l) pl = 1; - if (rint(r) != r) pr = 1; + if (rint(l) != l) pl = 2; + if (rint(r) != r) pr = 2; return g_strdup_printf("%.*f :%s%.*f", pl, l, approx, pr, r); } -gdouble image_zoom_get_default(ImageWindow *imd, gint mode) +gdouble image_zoom_get_default(ImageWindow *imd) { - gdouble zoom; + gdouble zoom = 1.0; - if (mode == ZOOM_RESET_ORIGINAL) - { - zoom = 1.0; - } - else if (mode == ZOOM_RESET_FIT_WINDOW) - { + switch (options->image.zoom_mode) + { + case ZOOM_RESET_ORIGINAL: + break; + case ZOOM_RESET_FIT_WINDOW: zoom = 0.0; - } - else - { - if (imd) - { - zoom = image_zoom_get(imd); - } - else - { - zoom = 1.0; - } - } + break; + case ZOOM_RESET_NONE: + if (imd) zoom = image_zoom_get(imd); + break; + } return zoom; } +/* stereo */ +gint image_stereo_get(ImageWindow *imd) +{ + return pixbuf_renderer_stereo_get((PixbufRenderer *)imd->pr); +} + +void image_stereo_set(ImageWindow *imd, gint stereo_mode) +{ + DEBUG_1("Setting stereo mode %04x for imd %p", stereo_mode, imd); + pixbuf_renderer_stereo_set((PixbufRenderer *)imd->pr, stereo_mode); +} + +void image_stereo_swap(ImageWindow *imd) +{ + gint stereo_mode = pixbuf_renderer_stereo_get((PixbufRenderer *)imd->pr); + stereo_mode ^= PR_STEREO_SWAP; + pixbuf_renderer_stereo_set((PixbufRenderer *)imd->pr, stereo_mode); +} + +StereoPixbufData image_stereo_pixbuf_get(ImageWindow *imd) +{ + return imd->user_stereo; +} + +void image_stereo_pixbuf_set(ImageWindow *imd, StereoPixbufData stereo_mode) +{ + imd->user_stereo = stereo_mode; + image_reload(imd); +} + /* read ahead */ void image_prebuffer_set(ImageWindow *imd, FileData *fd) @@ -1358,48 +1518,39 @@ void image_prebuffer_set(ImageWindow *imd, FileData *fd) } } -static gint image_auto_refresh_cb(gpointer data) +static void image_notify_cb(FileData *fd, NotifyType type, gpointer data) { ImageWindow *imd = data; - time_t newtime; if (!imd || !image_get_pixbuf(imd) || - imd->il || !imd->image_fd || - !options->update_on_time_change) return TRUE; - - newtime = filetime(imd->image_fd->path); - if (newtime > 0 && newtime != imd->mtime) - { - imd->mtime = newtime; + /* imd->il || */ /* loading in progress - do not check - it should start from the beginning anyway */ + !imd->image_fd || /* nothing to reload */ + imd->state == IMAGE_STATE_NONE /* loading not started, no need to reload */ + ) return; + + if ((type & NOTIFY_REREAD) && fd == imd->image_fd) + { + /* there is no need to reload on NOTIFY_CHANGE, + modified files should be detacted anyway and NOTIFY_REREAD should be recieved + or they are removed from the filelist completely on "move" and "delete" + */ + DEBUG_1("Notify image: %s %04x", fd->path, type); image_reload(imd); } - - return TRUE; } -/* image auto refresh on time stamp change, in 1/1000's second, -1 disables */ - -void image_auto_refresh(ImageWindow *imd, gint interval) +void image_auto_refresh_enable(ImageWindow *imd, gboolean enable) { - if (!imd) return; - if (pixbuf_renderer_get_tiles((PixbufRenderer *)imd->pr)) return; - - if (imd->auto_refresh_id > -1) - { - g_source_remove(imd->auto_refresh_id); - imd->auto_refresh_id = -1; - imd->auto_refresh_interval = -1; - } - - if (interval < 0) return; + if (!enable && imd->auto_refresh && imd->image_fd) + file_data_unregister_real_time_monitor(imd->image_fd); - if (interval == 0) interval = IMAGE_AUTO_REFRESH_TIME; + if (enable && !imd->auto_refresh && imd->image_fd) + file_data_register_real_time_monitor(imd->image_fd); - imd->auto_refresh_id = g_timeout_add((guint32)interval, image_auto_refresh_cb, imd); - imd->auto_refresh_interval = interval; + imd->auto_refresh = enable; } -void image_top_window_set_sync(ImageWindow *imd, gint allow_sync) +void image_top_window_set_sync(ImageWindow *imd, gboolean allow_sync) { imd->top_window_sync = allow_sync; @@ -1411,37 +1562,47 @@ void image_background_set_color(ImageWindow *imd, GdkColor *color) pixbuf_renderer_set_color((PixbufRenderer *)imd->pr, color); } +void image_background_set_color_from_options(ImageWindow *imd, gboolean fullscreen) +{ + GdkColor *color = NULL; + + if ((options->image.use_custom_border_color && !fullscreen) || + (options->image.use_custom_border_color_in_fullscreen && fullscreen)) + { + color = &options->image.border_color; + } + + image_background_set_color(imd, color); +} + void image_color_profile_set(ImageWindow *imd, - gint input_type, gint screen_type, - gint use_image) + gint input_type, + gboolean use_image) { if (!imd) return; - if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS || - screen_type < 0 || screen_type > 1) + if (input_type < 0 || input_type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS) { return; } imd->color_profile_input = input_type; - imd->color_profile_screen = screen_type; imd->color_profile_use_image = use_image; } -gint image_color_profile_get(ImageWindow *imd, - gint *input_type, gint *screen_type, - gint *use_image) +gboolean image_color_profile_get(ImageWindow *imd, + gint *input_type, + gboolean *use_image) { if (!imd) return FALSE; if (input_type) *input_type = imd->color_profile_input; - if (screen_type) *screen_type = imd->color_profile_screen; if (use_image) *use_image = imd->color_profile_use_image; return TRUE; } -void image_color_profile_set_use(ImageWindow *imd, gint enable) +void image_color_profile_set_use(ImageWindow *imd, gboolean enable) { if (!imd) return; @@ -1450,21 +1611,25 @@ void image_color_profile_set_use(ImageWindow *imd, gint enable) imd->color_profile_enable = enable; } -gint image_color_profile_get_use(ImageWindow *imd) +gboolean image_color_profile_get_use(ImageWindow *imd) { if (!imd) return FALSE; return imd->color_profile_enable; } -gint image_color_profile_get_from_image(ImageWindow *imd) +gboolean image_color_profile_get_status(ImageWindow *imd, gchar **image_profile, gchar **screen_profile) { + ColorMan *cm; if (!imd) return FALSE; - return imd->color_profile_from_image; + cm = imd->cm; + if (!cm) return FALSE; + return color_man_get_status(cm, image_profile, screen_profile); + } -void image_set_delay_flip(ImageWindow *imd, gint delay) +void image_set_delay_flip(ImageWindow *imd, gboolean delay) { if (!imd || imd->delay_flip == delay) return; @@ -1485,8 +1650,9 @@ void image_set_delay_flip(ImageWindow *imd, gint delay) } } -void image_to_root_window(ImageWindow *imd, gint scaled) +void image_to_root_window(ImageWindow *imd, gboolean scaled) { +#if !GTK_CHECK_VERSION(3,0,0) GdkScreen *screen; GdkWindow *rootwindow; GdkPixmap *pixmap; @@ -1501,7 +1667,7 @@ void image_to_root_window(ImageWindow *imd, gint scaled) screen = gtk_widget_get_screen(imd->widget); rootwindow = gdk_screen_get_root_window(screen); - if (gdk_drawable_get_visual(rootwindow) != gdk_visual_get_system()) return; + if (gdk_window_get_visual(rootwindow) != gdk_visual_get_system()) return; if (scaled) { @@ -1522,41 +1688,43 @@ void image_to_root_window(ImageWindow *imd, gint scaled) g_object_unref(pixmap); gdk_flush(); +#endif } void image_select(ImageWindow *imd, gboolean select) { - if (imd->has_frame) + if (!imd->has_frame) return; + + if (select) { - if (select) - { - gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED); - gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */ - } - else - gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL); + gtk_widget_set_state(imd->widget, GTK_STATE_SELECTED); + gtk_widget_set_state(imd->pr, GTK_STATE_NORMAL); /* do not propagate */ } + else + gtk_widget_set_state(imd->widget, GTK_STATE_NORMAL); } +void image_set_selectable(ImageWindow *imd, gboolean selectable) +{ + if (!imd->has_frame) return; + gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE); + gtk_container_set_border_width(GTK_CONTAINER(imd->frame), selectable ? 4 : 0); +} -void image_set_selectable(ImageWindow *imd, gboolean selectable) +void image_grab_focus(ImageWindow *imd) { if (imd->has_frame) { - if (selectable) - { - gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE); - gtk_container_set_border_width(GTK_CONTAINER(imd->frame), 4); - } - else - { - gtk_frame_set_shadow_type(GTK_FRAME(imd->frame), GTK_SHADOW_NONE); - gtk_container_set_border_width(GTK_CONTAINER(imd->frame), 0); - } + gtk_widget_grab_focus(imd->frame); + } + else + { + gtk_widget_grab_focus(imd->widget); } } + /* *------------------------------------------------------------------- * prefs sync @@ -1568,7 +1736,6 @@ static void image_options_set(ImageWindow *imd) g_object_set(G_OBJECT(imd->pr), "zoom_quality", options->image.zoom_quality, "zoom_2pass", options->image.zoom_2pass, "zoom_expand", options->image.zoom_to_fit_allow_expand, - "dither_quality", options->image.dither_quality, "scroll_reset", options->image.scroll_reset_method, "cache_display", options->image.tile_cache_max, "window_fit", (imd->top_window_sync && options->image.fit_window_to_image), @@ -1576,10 +1743,17 @@ static void image_options_set(ImageWindow *imd) "window_limit_value", options->image.max_window_size, "autofit_limit", options->image.limit_autofit_size, "autofit_limit_value", options->image.max_autofit_size, + "enlargement_limit_value", options->image.max_enlargement_size, NULL); pixbuf_renderer_set_parent((PixbufRenderer *)imd->pr, (GtkWindow *)imd->top_window); + + image_stereo_set(imd, options->stereo.mode); + pixbuf_renderer_stereo_fixed_set((PixbufRenderer *)imd->pr, + options->stereo.fixed_w, options->stereo.fixed_h, + options->stereo.fixed_x1, options->stereo.fixed_y1, + options->stereo.fixed_x2, options->stereo.fixed_y2); } void image_options_sync(void) @@ -1608,10 +1782,14 @@ static void image_free(ImageWindow *imd) { image_list = g_list_remove(image_list, imd); + if (imd->auto_refresh && imd->image_fd) + file_data_unregister_real_time_monitor(imd->image_fd); + + file_data_unregister_notify_func(image_notify_cb, imd); + image_reset(imd); image_read_ahead_cancel(imd); - image_auto_refresh(imd, -1); file_data_unref(imd->image_fd); g_free(imd->title); @@ -1619,27 +1797,74 @@ static void image_free(ImageWindow *imd) g_free(imd); } -static void image_destroy_cb(GtkObject *widget, gpointer data) +static void image_destroy_cb(GtkWidget *widget, gpointer data) { ImageWindow *imd = data; image_free(imd); } +#if GTK_CHECK_VERSION(3,0,0) +gboolean selectable_frame_draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data) +{ + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + gtk_paint_flat_box(gtk_widget_get_style(widget), + cr, + gtk_widget_get_state(widget), + gtk_frame_get_shadow_type(GTK_FRAME(widget)), + widget, + NULL, + allocation.x + 3, allocation.y + 3, + allocation.width - 6, allocation.height - 6); + if (gtk_widget_has_focus(widget)) + { + gtk_paint_focus(gtk_widget_get_style(widget), cr, GTK_STATE_ACTIVE, + widget, "image_window", + allocation.x, allocation.y, + allocation.width - 1, allocation.height - 1); + } + else + { + gtk_paint_shadow(gtk_widget_get_style(widget), cr, GTK_STATE_NORMAL, GTK_SHADOW_IN, + widget, "image_window", + allocation.x, allocation.y, + allocation.width - 1, allocation.height - 1); + } + return FALSE; +} + +#else gboolean selectable_frame_expose_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data) { - gtk_paint_flat_box(widget->style, - widget->window, - widget->state, - (GTK_FRAME(widget))->shadow_type, + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + gtk_paint_flat_box(gtk_widget_get_style(widget), + gtk_widget_get_window(widget), + gtk_widget_get_state(widget), + gtk_frame_get_shadow_type(GTK_FRAME(widget)), NULL, widget, NULL, - widget->allocation.x + 3, widget->allocation.y + 3, - widget->allocation.width - 6, widget->allocation.height - 6); - + allocation.x + 3, allocation.y + 3, + allocation.width - 6, allocation.height - 6); + if (gtk_widget_has_focus(widget)) + { + gtk_paint_focus(gtk_widget_get_style(widget), gtk_widget_get_window(widget), GTK_STATE_ACTIVE, + &event->area, widget, "image_window", + allocation.x, allocation.y, + allocation.width - 1, allocation.height - 1); + } + else + { + gtk_paint_shadow(gtk_widget_get_style(widget), gtk_widget_get_window(widget), GTK_STATE_NORMAL, GTK_SHADOW_IN, + &event->area, widget, "image_window", + allocation.x, allocation.y, + allocation.width - 1, allocation.height - 1); + } return FALSE; } +#endif void image_set_frame(ImageWindow *imd, gboolean frame) @@ -1653,37 +1878,39 @@ void image_set_frame(ImageWindow *imd, gboolean frame) if (frame) { imd->frame = gtk_frame_new(NULL); - gtk_widget_ref(imd->pr); + g_object_ref(imd->pr); if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr); gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr); - gtk_widget_unref(imd->pr); - g_signal_connect(G_OBJECT(imd->frame), "expose_event", - G_CALLBACK(selectable_frame_expose_cb), NULL); - GTK_WIDGET_SET_FLAGS(imd->frame, GTK_CAN_FOCUS); + g_object_unref(imd->pr); + gtk_widget_set_can_focus(imd->frame, TRUE); + gtk_widget_set_app_paintable(imd->frame, TRUE); + +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(imd->frame), "draw", + G_CALLBACK(selectable_frame_draw_cb), NULL); +#else + g_signal_connect(G_OBJECT(imd->frame), "expose_event", + G_CALLBACK(selectable_frame_expose_cb), NULL); +#endif g_signal_connect(G_OBJECT(imd->frame), "focus_in_event", G_CALLBACK(image_focus_in_cb), imd); - g_signal_connect(G_OBJECT(imd->frame), "focus_out_event", - G_CALLBACK(image_focus_out_cb), imd); - - g_signal_connect_after(G_OBJECT(imd->frame), "expose_event", - G_CALLBACK(image_focus_expose), imd); - - gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame); - gtk_widget_show(imd->frame); + gtk_box_pack_start(GTK_BOX(imd->widget), imd->frame, TRUE, TRUE, 0); + gtk_widget_show(imd->frame); } else { - gtk_widget_ref(imd->pr); + g_object_ref(imd->pr); if (imd->frame) { gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr); gtk_widget_destroy(imd->frame); imd->frame = NULL; } - gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr); - gtk_widget_unref(imd->pr); + gtk_box_pack_start(GTK_BOX(imd->widget), imd->pr, TRUE, TRUE, 0); + + g_object_unref(imd->pr); } gtk_widget_show(imd->pr); @@ -1691,63 +1918,30 @@ void image_set_frame(ImageWindow *imd, gboolean frame) imd->has_frame = frame; } -ImageWindow *image_new(gint frame) +ImageWindow *image_new(gboolean frame) { ImageWindow *imd; imd = g_new0(ImageWindow, 1); - imd->top_window = NULL; - imd->title = NULL; - imd->title_right = NULL; - imd->title_show_zoom = FALSE; - imd->unknown = TRUE; - imd->has_frame = -1; /* not initialized; for image_set_frame */ - imd->top_window_sync = FALSE; - imd->delay_alter_type = ALTER_NONE; - - imd->read_ahead_il = NULL; - imd->read_ahead_fd = NULL; - - imd->completed = FALSE; imd->state = IMAGE_STATE_NONE; - - imd->color_profile_enable = FALSE; - imd->color_profile_input = 0; - imd->color_profile_screen = 0; - imd->color_profile_use_image = FALSE; imd->color_profile_from_image = COLOR_PROFILE_NONE; - - imd->auto_refresh_id = -1; - imd->auto_refresh_interval = -1; - - imd->delay_flip = FALSE; - - imd->func_update = NULL; - imd->func_complete = NULL; - imd->func_tile_request = NULL; - imd->func_tile_dispose = NULL; - - imd->func_button = NULL; - imd->func_scroll = NULL; - imd->orientation = 1; imd->pr = GTK_WIDGET(pixbuf_renderer_new()); image_options_set(imd); - imd->widget = gtk_vbox_new(0, 0); image_set_frame(imd, frame); image_set_selectable(imd, 0); - g_signal_connect(G_OBJECT(imd->pr), "clicked", + g_signal_connect(G_OBJECT(imd->pr), "button_press_event", G_CALLBACK(image_click_cb), imd); g_signal_connect(G_OBJECT(imd->pr), "scroll_notify", G_CALLBACK(image_scroll_notify_cb), imd); @@ -1765,7 +1959,10 @@ ImageWindow *image_new(gint frame) g_signal_connect(G_OBJECT(imd->pr), "drag", G_CALLBACK(image_drag_cb), imd); + file_data_register_notify_func(image_notify_cb, imd, NOTIFY_PRIORITY_LOW); + image_list = g_list_append(image_list, imd); return imd; } +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */