diff --git a/configure.ac.in b/configure.ac.in index 0af4d57..6a080aa 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -64,6 +64,7 @@ XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-1], [4.10.0]) XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.10.0]) XDT_CHECK_PACKAGE([CAIRO], [cairo], [1.8.0]) +XDT_CHECK_PACKAGE([ABYDOS], [abydos], [0.1.0]) XDT_CHECK_LIBX11() diff --git a/src/Makefile.am b/src/Makefile.am index e6d41e0..461bf24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,6 +33,7 @@ ristretto_CFLAGS = \ $(XFCONF_CFLAGS) \ $(EXO_CFLAGS) \ $(CAIRO_CFLAGS) \ + $(ABYDOS_CFLAGS) \ $(LIBXFCE4UTIL_CFLAGS) \ $(LIBXFCE4UI_CFLAGS) \ $(LIBX11_CFLAGS) \ @@ -51,6 +52,7 @@ ristretto_LDADD = \ $(XFCONF_LIBS) \ $(EXO_LIBS) \ $(CAIRO_LIBS) \ + $(ABYDOS_LIBS) \ $(LIBXFCE4UTIL_LIBS) \ $(LIBXFCE4UI_LIBS) \ $(LIBX11_LIBS) \ diff --git a/src/image_viewer.c b/src/image_viewer.c index 9a5106f..d7ae9b0 100644 --- a/src/image_viewer.c +++ b/src/image_viewer.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -82,7 +83,7 @@ struct _RsttoImageViewerPriv GError *error; RsttoImageViewerTransaction *transaction; - GdkPixbuf *pixbuf; + abydos_t *ar; RsttoImageOrientation orientation; struct { @@ -102,8 +103,7 @@ struct _RsttoImageViewerPriv /* Animation data for animated images (like .gif/.mng) */ /*******************************************************/ - GdkPixbufAnimation *animation; - GdkPixbufAnimationIter *iter; + gdouble animation_time; gint animation_timeout_id; gint refresh_timeout_id; @@ -137,16 +137,10 @@ struct _RsttoImageViewerTransaction RsttoImageViewer *viewer; RsttoFile *file; GCancellable *cancellable; - GdkPixbufLoader *loader; + abydos_t *ar; GError *error; - gint image_width; - gint image_height; - gdouble image_scale; - gdouble scale; - RsttoImageOrientation orientation; - /* File I/O data */ /*****************/ guchar *buffer; @@ -216,11 +210,11 @@ cb_rstto_image_viewer_read_file_ready (GObject *source_object, GAsyncResult *res static void cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncResult *result, gpointer user_data); static void -cb_rstto_image_loader_area_prepared (GdkPixbufLoader *, RsttoImageViewerTransaction *); +cb_rstto_image_loader_update (RsttoImageViewerTransaction *, abydos_t *, cairo_rectangle_int_t *); static void -cb_rstto_image_loader_size_prepared (GdkPixbufLoader *, gint , gint , RsttoImageViewerTransaction *); +cb_rstto_image_loader_info (RsttoImageViewerTransaction *); static void -cb_rstto_image_loader_closed (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction); +cb_rstto_image_loader_closed (RsttoImageViewerTransaction *transaction); static gboolean cb_rstto_image_viewer_update_pixbuf (RsttoImageViewer *viewer); static void @@ -278,6 +272,14 @@ rstto_image_viewer_transaction_free (RsttoImageViewerTransaction *tr); static GtkWidgetClass *parent_class = NULL; static GdkScreen *default_screen = NULL; +static double +get_monotime() +{ + struct timespec monotime; + clock_gettime(CLOCK_MONOTONIC,&monotime); + return monotime.tv_sec+(gdouble)monotime.tv_nsec/1000000000; +} + GType rstto_image_viewer_get_type (void) { @@ -672,15 +674,10 @@ rstto_image_viewer_destroy(GtkObject *object) g_object_unref (viewer->priv->missing_icon); viewer->priv->missing_icon = NULL; } - if (viewer->priv->pixbuf) - { - g_object_unref (viewer->priv->pixbuf); - viewer->priv->pixbuf = NULL; - } - if (viewer->priv->iter) + if (viewer->priv->ar) { - g_object_unref (viewer->priv->iter); - viewer->priv->iter = NULL; + abydos_destroy (viewer->priv->ar); + viewer->priv->ar = NULL; } g_free (viewer->priv); viewer->priv = NULL; @@ -1182,7 +1179,7 @@ paint_image (GtkWidget *widget, cairo_t *ctx) gtk_widget_get_allocation (widget, &allocation); - if (viewer->priv->pixbuf) + if (viewer->priv->ar) { switch (viewer->priv->orientation) { @@ -1234,7 +1231,7 @@ paint_image (GtkWidget *widget, cairo_t *ctx) y_offset = floor ( viewer->priv->rendering.y_offset ); /* BEGIN PAINT CHECKERED BACKGROUND */ - if (TRUE == gdk_pixbuf_get_has_alpha (viewer->priv->pixbuf)) + if (TRUE /* == gdk_pixbuf_get_has_alpha (viewer->priv->pixbuf) */) { cairo_set_source_rgba (ctx, 0.8, 0.8, 0.8, 1.0); cairo_rectangle ( @@ -1423,12 +1420,7 @@ paint_image (GtkWidget *widget, cairo_t *ctx) (viewer->priv->scale/viewer->priv->image_scale), (viewer->priv->scale/viewer->priv->image_scale)); - gdk_cairo_set_source_pixbuf ( - ctx, - viewer->priv->pixbuf, - 0.0, - 0.0); - cairo_paint (ctx); + abydos_render (viewer->priv->ar, ctx, 0); } else { @@ -1737,20 +1729,10 @@ rstto_image_viewer_set_file (RsttoImageViewer *viewer, RsttoFile *file, gdouble } else { - if (viewer->priv->iter) - { - g_object_unref (viewer->priv->iter); - viewer->priv->iter = NULL; - } - if (viewer->priv->animation) - { - g_object_unref (viewer->priv->animation); - viewer->priv->animation = NULL; - } - if (viewer->priv->pixbuf) + if (viewer->priv->ar) { - g_object_unref (viewer->priv->pixbuf); - viewer->priv->pixbuf = NULL; + abydos_destroy (viewer->priv->ar); + viewer->priv->ar = NULL; } if (viewer->priv->transaction) { @@ -1798,23 +1780,26 @@ 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->ar = abydos_create (rstto_file_get_content_type (file)); transaction->cancellable = g_cancellable_new(); transaction->buffer = g_new0 (guchar, RSTTO_IMAGE_VIEWER_BUFFER_SIZE); transaction->file = file; transaction->viewer = viewer; - transaction->scale = scale; + if(transaction->ar != NULL) + { + abydos_load_begin(transaction->ar, + (abydos_info_callback_t)cb_rstto_image_loader_info, + (abydos_update_callback_t)cb_rstto_image_loader_update, + transaction); + } + +#if 0 g_signal_connect(transaction->loader, "area-prepared", G_CALLBACK(cb_rstto_image_loader_area_prepared), transaction); 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); +#endif viewer->priv->transaction = transaction; @@ -1841,7 +1826,10 @@ rstto_image_viewer_transaction_free (RsttoImageViewerTransaction *tr) g_error_free (tr->error); } g_object_unref (tr->cancellable); - g_object_unref (tr->loader); + if (tr->ar) + { + abydos_destroy(tr->ar); + } g_free (tr->buffer); g_free (tr); } @@ -2011,6 +1999,98 @@ rstto_image_viewer_set_menu (RsttoImageViewer *viewer, GtkMenu *menu) } +static void +rstto_image_viewer_setup_image (RsttoImageViewer *viewer, RsttoImageViewerTransaction *transaction) +{ + gint s_width = gdk_screen_get_width (default_screen); + gint s_height = gdk_screen_get_height (default_screen); + gboolean limit_quality = transaction->viewer->priv->limit_quality; + abydos_info_t info; + gint timeout = 0; + + if (viewer->priv->transaction != transaction) + { + return; + } + + if (transaction->error != NULL) + { + viewer->priv->image_scale = 1.0; + viewer->priv->image_width = 1.0; + viewer->priv->image_height = 1.0; + if (viewer->priv->ar) + { + g_object_unref (viewer->priv->ar); + viewer->priv->ar = NULL; + } + + gtk_widget_set_tooltip_text (GTK_WIDGET (viewer), transaction->error->message); + + viewer->priv->error = transaction->error; + transaction->error = NULL; + return; + } + + /* + * By default, the image-size won't be limited to screen-size (since it's smaller) + * or, because we don't want to reduce it. + * Set the image_scale to 1.0 (100%) + */ + viewer->priv->image_scale = 1.0; + + abydos_get_info(transaction->ar, &info); + viewer->priv->image_width = info.width; + viewer->priv->image_height = info.height; + + if (limit_quality == TRUE) + { + /* + * Set the maximum size of the loaded image to the screen-size. + * TODO: Add some 'smart-stuff' here + */ + if (s_width < info.width || s_height < info.height) + { + /* + * The image is loaded at the screen_size, calculate how this fits best. + * scale = MIN(width / screen_width, height / screen_height) + * + */ + if(((gdouble)info.width / (gdouble)s_width) < ((gdouble)info.height / (gdouble)s_height)) + { + viewer->priv->image_scale = (gdouble)s_width / (gdouble)info.width; + } + else + { + viewer->priv->image_scale = (gdouble)s_height / (gdouble)info.height; + } + } + } + + viewer->priv->orientation = rstto_file_get_orientation (transaction->file); + + if (viewer->priv->ar != NULL) + { + if (viewer->priv->animation_timeout_id) + { + g_source_remove (viewer->priv->animation_timeout_id); + viewer->priv->animation_timeout_id = 0; + } + abydos_destroy (viewer->priv->ar); + } + viewer->priv->ar = abydos_reference (transaction->ar); + + viewer->priv->animation_time = get_monotime(); + timeout = ceil(abydos_get_delay (viewer->priv->ar) * 1000); + if (timeout > 0) + { + viewer->priv->animation_timeout_id = g_timeout_add(timeout, (GSourceFunc)cb_rstto_image_viewer_update_pixbuf, viewer); + } + + gtk_widget_set_tooltip_text (GTK_WIDGET (viewer), NULL); + set_scale (viewer, viewer->priv->scale); + + viewer->priv->error = NULL; +} /************************/ /** CALLBACK FUNCTIONS **/ @@ -2054,16 +2134,30 @@ cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncRes RsttoImageViewerTransaction *transaction = (RsttoImageViewerTransaction *)user_data; gssize read_bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), result, &transaction->error); + if (NULL == transaction->ar) + { + return; + } + if (read_bytes == -1) { - gdk_pixbuf_loader_close (transaction->loader, NULL); + if (abydos_load_end (transaction->ar) < 0) + { + /* FIXME!! set transaction->error */ + abydos_destroy(transaction->ar); + transaction->ar = NULL; + } + cb_rstto_image_loader_closed (transaction); return; } if (read_bytes > 0) { - if(gdk_pixbuf_loader_write (transaction->loader, (const guchar *)transaction->buffer, read_bytes, &transaction->error) == FALSE) + if(abydos_load_feed (transaction->ar, (const gchar *)transaction->buffer, read_bytes) < 0) { + /* FIXME!! set transaction->error */ + abydos_destroy(transaction->ar); + transaction->ar = NULL; /* Clean up the input-stream */ g_input_stream_close (G_INPUT_STREAM (source_object), NULL, NULL); g_object_unref(source_object); @@ -2081,7 +2175,13 @@ cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncRes } else { /* Loading complete, transaction should not be free-ed */ - gdk_pixbuf_loader_close (transaction->loader, &transaction->error); + if(abydos_load_end (transaction->ar) < 0) + { + /* FIXME!! set transaction->error */ + abydos_destroy(transaction->ar); + transaction->ar = NULL; + } + cb_rstto_image_loader_closed (transaction); /* Clean up the input-stream */ g_input_stream_close (G_INPUT_STREAM (source_object), NULL, NULL); @@ -2090,157 +2190,37 @@ cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncRes } +/* + * This function is called each time there is more of the image available + * to display. Any updated are in the area specified by rect. + */ static void -cb_rstto_image_loader_area_prepared (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction) +cb_rstto_image_loader_update (RsttoImageViewerTransaction *transaction, + abydos_t *ar, + cairo_rectangle_int_t *rect) { - 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 = g_timeout_add(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); - } - } } +/* + * This function is called as soon as the information about the image is + * known and there is something to display. + */ static void -cb_rstto_image_loader_size_prepared (GdkPixbufLoader *loader, gint width, gint height, RsttoImageViewerTransaction *transaction) +cb_rstto_image_loader_info (RsttoImageViewerTransaction *transaction) { - gint s_width = gdk_screen_get_width (default_screen); - gint s_height = gdk_screen_get_height (default_screen); - gboolean limit_quality = transaction->viewer->priv->limit_quality; - - /* - * By default, the image-size won't be limited to screen-size (since it's smaller) - * or, because we don't want to reduce it. - * Set the image_scale to 1.0 (100%) - */ - transaction->image_scale = 1.0; - - transaction->image_width = width; - transaction->image_height = height; - - - if (limit_quality == TRUE) - { - /* - * Set the maximum size of the loaded image to the screen-size. - * TODO: Add some 'smart-stuff' here - */ - if (s_width < width || s_height < height) - { - /* - * The image is loaded at the screen_size, calculate how this fits best. - * scale = MIN(width / screen_width, height / screen_height) - * - */ - if(((gdouble)width / (gdouble)s_width) < ((gdouble)height / (gdouble)s_height)) - { - transaction->image_scale = (gdouble)s_width / (gdouble)width; - gdk_pixbuf_loader_set_size ( - loader, - s_width, - (gint)((gdouble)height/(gdouble)width*(gdouble)s_width)); - } - else - { - transaction->image_scale = (gdouble)s_height / (gdouble)height; - gdk_pixbuf_loader_set_size ( - loader, - (gint)((gdouble)width/(gdouble)height*(gdouble)s_height), - s_height); - } - } - else - { - /* - * Image-size won't be limited to screen-size (since it's smaller) - * Set the image_scale to 1.0 (100%) - */ - transaction->image_scale = 1.0; - } - } - - transaction->orientation = rstto_file_get_orientation (transaction->file); } static void -cb_rstto_image_loader_closed (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction) +cb_rstto_image_loader_closed (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 (GTK_WIDGET (viewer), 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); - } - 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 (GTK_WIDGET (viewer), transaction->error->message); - } - - - viewer->priv->error = transaction->error; - transaction->error = NULL; - viewer->priv->transaction = NULL; - - gdk_window_invalidate_rect ( - gtk_widget_get_window (widget), + rstto_image_viewer_setup_image (viewer, transaction); + gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE); - } + viewer->priv->transaction = NULL; g_signal_emit_by_name(transaction->viewer, "size-ready"); rstto_image_viewer_transaction_free (transaction); @@ -2251,26 +2231,14 @@ cb_rstto_image_viewer_update_pixbuf (RsttoImageViewer *viewer) { GtkWidget *widget = GTK_WIDGET(viewer); gint timeout = 0; + double now = get_monotime(); - if (viewer->priv->iter) - { - if(gdk_pixbuf_animation_iter_advance (viewer->priv->iter, NULL)) - { - /* Cleanup old image */ - if (viewer->priv->pixbuf) - { - g_object_unref (viewer->priv->pixbuf); - viewer->priv->pixbuf = NULL; - } + viewer->priv->animation_timeout_id = 0; - /* The pixbuf returned by the GdkPixbufAnimationIter might be reused, - * lets make a copy for myself just in case. Since it's a copy, we - * own the only reference to it. There is no need to add another. - */ - viewer->priv->pixbuf = gdk_pixbuf_copy (gdk_pixbuf_animation_iter_get_pixbuf (viewer->priv->iter)); - } + abydos_add_time(viewer->priv->ar, now - viewer->priv->animation_time); + viewer->priv->animation_time = now; - timeout = gdk_pixbuf_animation_iter_get_delay_time (viewer->priv->iter); + timeout = ceil(abydos_get_delay (viewer->priv->ar) * 1000); if (timeout > 0) { @@ -2283,8 +2251,6 @@ cb_rstto_image_viewer_update_pixbuf (RsttoImageViewer *viewer) FALSE); return FALSE; - } - return FALSE; } static gboolean