diff --git a/src/image_viewer.c b/src/image_viewer.c index 912aabe..078115c 100644 --- a/src/image_viewer.c +++ b/src/image_viewer.c @@ -156,10 +156,6 @@ struct _RsttoImageViewerTransaction gdouble image_scale; gdouble scale; RsttoImageOrientation orientation; - - /* File I/O data */ - /*****************/ - guchar *buffer; }; static void @@ -223,16 +219,8 @@ rstto_image_viewer_set_scroll_adjustments(RsttoImageViewer *, GtkAdjustment *, G static void cb_rstto_image_viewer_value_changed(GtkAdjustment *adjustment, RsttoImageViewer *viewer); -static void -cb_rstto_image_viewer_read_file_ready (GObject *source_object, GAsyncResult *result, gpointer user_data); -static void -cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncResult *result, gpointer user_data); -static void -cb_rstto_image_loader_image_ready (GdkPixbufLoader *, RsttoImageViewerTransaction *); static void cb_rstto_image_loader_size_prepared (GdkPixbufLoader *, gint , gint , RsttoImageViewerTransaction *); -static void -cb_rstto_image_loader_closed (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction); static gboolean cb_rstto_image_viewer_update_pixbuf (RsttoImageViewer *viewer); static void @@ -1772,6 +1760,138 @@ rstto_image_viewer_set_file (RsttoImageViewer *viewer, RsttoFile *file, gdouble } } +static gboolean +rstto_image_viewer_transaction_finish (RsttoImageViewerTransaction *transaction) +{ + RsttoImageViewer *viewer = transaction->viewer; + + if (viewer->priv->transaction == transaction) + { + GtkWidget *widget = GTK_WIDGET (viewer); + if (NULL == transaction->error) + { + gint timeout = 0; + gtk_widget_set_tooltip_text (widget, NULL); + viewer->priv->image_scale = transaction->image_scale; + viewer->priv->image_width = transaction->image_width; + viewer->priv->image_height = transaction->image_height; + viewer->priv->orientation = transaction->orientation; + set_scale (viewer, transaction->scale); + + if (viewer->priv->iter) + { + g_object_unref (viewer->priv->iter); + viewer->priv->iter = NULL; + } + + if (viewer->priv->pixbuf) + { + g_object_unref (viewer->priv->pixbuf); + viewer->priv->pixbuf = NULL; + } + + if (viewer->priv->animation) + { + g_object_unref (viewer->priv->animation); + viewer->priv->animation = NULL; + } + + viewer->priv->animation = gdk_pixbuf_loader_get_animation (transaction->loader); + viewer->priv->iter = gdk_pixbuf_animation_get_iter (viewer->priv->animation, NULL); + + g_object_ref (viewer->priv->animation); + + timeout = gdk_pixbuf_animation_iter_get_delay_time (viewer->priv->iter); + + if (timeout > 0) + { + viewer->priv->animation_timeout_id = + gdk_threads_add_timeout (timeout, (GSourceFunc) cb_rstto_image_viewer_update_pixbuf, viewer); + } + else + { + /* This is a single-frame image, there is no need to copy the pixbuf since it won't change */ + viewer->priv->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (viewer->priv->iter); + g_object_ref (viewer->priv->pixbuf); + } + } + else + { + viewer->priv->image_scale = 1.0; + viewer->priv->image_width = 1.0; + viewer->priv->image_height = 1.0; + if (viewer->priv->pixbuf) + { + g_object_unref (viewer->priv->pixbuf); + viewer->priv->pixbuf = NULL; + } + + gtk_widget_set_tooltip_text (widget, transaction->error->message); + } + + viewer->priv->error = transaction->error; + transaction->error = NULL; + viewer->priv->transaction = NULL; + + gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); + } + g_signal_emit_by_name (transaction->viewer, "size-ready"); + rstto_image_viewer_transaction_free (transaction); + + return G_SOURCE_REMOVE; +} + +static void +rstto_image_viewer_transaction_run (RsttoImageViewerTransaction *transaction) +{ + GFileInputStream *stream; + + transaction->loader = gdk_pixbuf_loader_new_with_mime_type (rstto_file_get_content_type (transaction->file), NULL); + + /* HACK HACK HACK */ + if (transaction->loader == NULL) + { + transaction->loader = gdk_pixbuf_loader_new(); + } + + g_signal_connect(transaction->loader, "size-prepared", G_CALLBACK(cb_rstto_image_loader_size_prepared), transaction); + + stream = g_file_read (rstto_file_get_file (transaction->file), transaction->cancellable, &transaction->error); + if (transaction->error) + goto out; + + for (;;) + { + guchar buffer[RSTTO_IMAGE_VIEWER_BUFFER_SIZE]; + gssize read_bytes; + read_bytes = g_input_stream_read (G_INPUT_STREAM (stream), + buffer, + RSTTO_IMAGE_VIEWER_BUFFER_SIZE, + transaction->cancellable, + &transaction->error); + if (read_bytes < 0) + goto out; + + if (0 == read_bytes) + break; + + if (gdk_pixbuf_loader_write (transaction->loader, buffer, read_bytes, &transaction->error) == FALSE) + goto out; + } + /* Loading complete, transaction should not be free-ed */ + gdk_pixbuf_loader_close (transaction->loader, &transaction->error); + +out: + /* Clean up the input-stream */ + if (stream) + { + g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL); + g_object_unref (stream); + } + + g_idle_add ((GSourceFunc) rstto_image_viewer_transaction_finish, transaction); +} + static void rstto_image_viewer_load_image (RsttoImageViewer *viewer, RsttoFile *file, gdouble scale) { @@ -1787,30 +1907,14 @@ rstto_image_viewer_load_image (RsttoImageViewer *viewer, RsttoFile *file, gdoubl viewer->priv->transaction = NULL; } - transaction->loader = gdk_pixbuf_loader_new_with_mime_type (rstto_file_get_content_type (file), NULL); - - /* HACK HACK HACK */ - if (transaction->loader == NULL) - { - transaction->loader = gdk_pixbuf_loader_new(); - } - transaction->cancellable = g_cancellable_new(); - transaction->buffer = g_new0 (guchar, RSTTO_IMAGE_VIEWER_BUFFER_SIZE); transaction->file = file; transaction->viewer = viewer; transaction->scale = scale; - g_signal_connect(transaction->loader, "size-prepared", G_CALLBACK(cb_rstto_image_loader_size_prepared), transaction); - g_signal_connect(transaction->loader, "closed", G_CALLBACK(cb_rstto_image_loader_closed), transaction); - viewer->priv->transaction = transaction; - g_file_read_async (rstto_file_get_file (transaction->file), - 0, - transaction->cancellable, - (GAsyncReadyCallback)cb_rstto_image_viewer_read_file_ready, - transaction); + g_thread_new (NULL, (GThreadFunc) rstto_image_viewer_transaction_run, transaction); } static void @@ -1830,7 +1934,6 @@ rstto_image_viewer_transaction_free (RsttoImageViewerTransaction *tr) } g_object_unref (tr->cancellable); g_object_unref (tr->loader); - g_free (tr->buffer); g_free (tr); } @@ -2011,117 +2114,6 @@ cb_rstto_image_viewer_value_changed (GtkAdjustment *adjustment, RsttoImageViewer gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); } -static void -cb_rstto_image_viewer_read_file_ready (GObject *source_object, GAsyncResult *result, gpointer user_data) -{ - GFile *file = G_FILE (source_object); - RsttoImageViewerTransaction *transaction = (RsttoImageViewerTransaction *)user_data; - - GFileInputStream *file_input_stream = g_file_read_finish (file, result, NULL); - - if (file_input_stream == NULL) - { - return; - } - - g_input_stream_read_async (G_INPUT_STREAM (file_input_stream), - transaction->buffer, - RSTTO_IMAGE_VIEWER_BUFFER_SIZE, - G_PRIORITY_DEFAULT, - transaction->cancellable, - (GAsyncReadyCallback) cb_rstto_image_viewer_read_input_stream_ready, - transaction); -} - -static void -cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncResult *result, gpointer user_data) -{ - RsttoImageViewerTransaction *transaction = (RsttoImageViewerTransaction *)user_data; - gssize read_bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), result, &transaction->error); - - if (read_bytes == -1) - { - gdk_pixbuf_loader_close (transaction->loader, NULL); - return; - } - - if (read_bytes > 0) - { - if (gdk_pixbuf_loader_write (transaction->loader, (const guchar *)transaction->buffer, read_bytes, &transaction->error) == FALSE) - { - /* Clean up the input-stream */ - g_input_stream_close (G_INPUT_STREAM (source_object), NULL, NULL); - g_object_unref(source_object); - } - else - { - g_input_stream_read_async (G_INPUT_STREAM (source_object), - transaction->buffer, - RSTTO_IMAGE_VIEWER_BUFFER_SIZE, - G_PRIORITY_DEFAULT, - transaction->cancellable, - (GAsyncReadyCallback) cb_rstto_image_viewer_read_input_stream_ready, - transaction); - } - } - else { - /* Loading complete, transaction should not be free-ed */ - gdk_pixbuf_loader_close (transaction->loader, &transaction->error); - - /* Clean up the input-stream */ - g_input_stream_close (G_INPUT_STREAM (source_object), NULL, NULL); - g_object_unref (source_object); - } -} - - -static void -cb_rstto_image_loader_image_ready (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction) -{ - gint timeout = 0; - RsttoImageViewer *viewer = transaction->viewer; - - if (viewer->priv->transaction == transaction) - { - if (viewer->priv->iter) - { - g_object_unref (viewer->priv->iter); - viewer->priv->iter = NULL; - } - - if (viewer->priv->pixbuf) - { - g_object_unref (viewer->priv->pixbuf); - viewer->priv->pixbuf = NULL; - } - - if (viewer->priv->animation) - { - g_object_unref (viewer->priv->animation); - viewer->priv->animation = NULL; - } - - viewer->priv->animation = gdk_pixbuf_loader_get_animation (loader); - viewer->priv->iter = gdk_pixbuf_animation_get_iter (viewer->priv->animation, NULL); - - g_object_ref (viewer->priv->animation); - - timeout = gdk_pixbuf_animation_iter_get_delay_time (viewer->priv->iter); - - if (timeout > 0) - { - viewer->priv->animation_timeout_id = - gdk_threads_add_timeout (timeout, (GSourceFunc) cb_rstto_image_viewer_update_pixbuf, viewer); - } - else - { - /* This is a single-frame image, there is no need to copy the pixbuf since it won't change */ - viewer->priv->pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (viewer->priv->iter); - g_object_ref (viewer->priv->pixbuf); - } - } -} - static void cb_rstto_image_loader_size_prepared (GdkPixbufLoader *loader, gint width, gint height, RsttoImageViewerTransaction *transaction) { @@ -2180,50 +2172,6 @@ cb_rstto_image_loader_size_prepared (GdkPixbufLoader *loader, gint width, gint h transaction->orientation = rstto_file_get_orientation (transaction->file); } -static void -cb_rstto_image_loader_closed (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction) -{ - RsttoImageViewer *viewer = transaction->viewer; - GtkWidget *widget = GTK_WIDGET (viewer); - - if (viewer->priv->transaction == transaction) - { - if (NULL == transaction->error) - { - gtk_widget_set_tooltip_text (widget, NULL); - viewer->priv->image_scale = transaction->image_scale; - viewer->priv->image_width = transaction->image_width; - viewer->priv->image_height = transaction->image_height; - viewer->priv->orientation = transaction->orientation; - set_scale (viewer, transaction->scale); - - cb_rstto_image_loader_image_ready (loader, transaction); - } - else - { - viewer->priv->image_scale = 1.0; - viewer->priv->image_width = 1.0; - viewer->priv->image_height = 1.0; - if (viewer->priv->pixbuf) - { - g_object_unref (viewer->priv->pixbuf); - viewer->priv->pixbuf = NULL; - } - - gtk_widget_set_tooltip_text (widget, transaction->error->message); - } - - viewer->priv->error = transaction->error; - transaction->error = NULL; - viewer->priv->transaction = NULL; - - gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); - } - - g_signal_emit_by_name (transaction->viewer, "size-ready"); - rstto_image_viewer_transaction_free (transaction); -} - static gboolean cb_rstto_image_viewer_update_pixbuf (RsttoImageViewer *viewer) {