[Xfce4-commits] <ristretto:master> The image-viewer now shows images
Stephan Arts
noreply at xfce.org
Mon Aug 8 15:04:02 CEST 2011
Updating branch refs/heads/master
to e4bf2eab287dc9e06b35083f88caa829e5ed9db4 (commit)
from e795ea4e4cc1f69717fc91a935985d6f3122a4b4 (commit)
commit e4bf2eab287dc9e06b35083f88caa829e5ed9db4
Author: Stephan Arts <stephan at xfce.org>
Date: Sun Jul 17 08:36:02 2011 +0200
The image-viewer now shows images
src/image_viewer.c | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 406 insertions(+), 9 deletions(-)
diff --git a/src/image_viewer.c b/src/image_viewer.c
index 52c746e..34833ff 100644
--- a/src/image_viewer.c
+++ b/src/image_viewer.c
@@ -36,6 +36,13 @@
#define RSTTO_IMAGE_VIEWER_BUFFER_SIZE 131072
#endif
+typedef enum
+{
+ RSTTO_PICTURE_VIEWER_MOTION_STATE_NORMAL = 0,
+ RSTTO_PICTURE_VIEWER_MOTION_STATE_BOX_ZOOM,
+ RSTTO_PICTURE_VIEWER_MOTION_STATE_MOVE
+} RsttoPictureViewerMotionState;
+
typedef struct _RsttoImageViewerTransaction RsttoImageViewerTransaction;
struct _RsttoImageViewerPriv
@@ -44,6 +51,8 @@ struct _RsttoImageViewerPriv
RsttoSettings *settings;
RsttoImageViewerTransaction *transaction;
+ GdkPixbuf *pixbuf;
+ GdkPixbuf *dst_pixbuf;
/* Animation data for animated images (like .gif/.mng) */
/*******************************************************/
@@ -51,6 +60,23 @@ struct _RsttoImageViewerPriv
GdkPixbufAnimationIter *iter;
gint animation_timeout_id;
+ struct
+ {
+ gint idle_id;
+ gboolean refresh;
+ } repaint;
+
+ struct
+ {
+ gdouble x;
+ gdouble y;
+ gdouble current_x;
+ gdouble current_y;
+ gint h_val;
+ gint v_val;
+ RsttoPictureViewerMotionState state;
+ } motion;
+
/* CALLBACKS */
/*************/
void (*cb_value_changed)(GtkAdjustment *, RsttoImageViewer *);
@@ -90,6 +116,8 @@ rstto_image_viewer_paint (GtkWidget *widget);
static gboolean
rstto_image_viewer_set_scroll_adjustments(RsttoImageViewer *, GtkAdjustment *, GtkAdjustment *);
+static void
+rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer, gboolean);
static void
cb_rstto_image_viewer_value_changed(GtkAdjustment *adjustment, RsttoImageViewer *viewer);
@@ -103,6 +131,10 @@ 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 gboolean
+cb_rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer);
static void
rstto_image_viewer_load_image (RsttoImageViewer *viewer, GFile *file);
@@ -150,7 +182,13 @@ rstto_image_viewer_init(RsttoImageViewer *viewer)
viewer->priv->cb_value_changed = cb_rstto_image_viewer_value_changed;
viewer->priv->settings = rstto_settings_new();
- gtk_widget_set_redraw_on_allocate(GTK_WIDGET(viewer), TRUE);
+ gtk_widget_set_double_buffered (GTK_WIDGET(viewer), TRUE);
+
+ /* Set to false, experimental...
+ * improves performance, but I am not sure what will give.
+ */
+ gtk_widget_set_redraw_on_allocate(GTK_WIDGET(viewer), FALSE);
+
gtk_widget_set_events (GTK_WIDGET(viewer),
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
@@ -279,7 +317,7 @@ rstto_image_viewer_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
/**
* TODO: Check if we really nead a refresh
*/
- //rstto_image_viewer_queued_repaint (viewer, TRUE);
+ rstto_image_viewer_queued_repaint (viewer, TRUE);
}
/**
@@ -296,7 +334,7 @@ rstto_image_viewer_expose(GtkWidget *widget, GdkEventExpose *event)
/**
* TODO: Check if we really nead a refresh
*/
- //rstto_image_viewer_queued_repaint (viewer, TRUE);
+ rstto_image_viewer_queued_repaint (viewer, TRUE);
return FALSE;
}
@@ -345,6 +383,265 @@ rstto_image_viewer_set_scroll_adjustments(RsttoImageViewer *viewer, GtkAdjustmen
static void
rstto_image_viewer_paint (GtkWidget *widget)
{
+ g_debug("%s", __FUNCTION__);
+
+ RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (widget);
+
+ GdkColor *bg_color = NULL;
+ GValue val_bg_color = {0, }, val_bg_color_override = {0, }, val_bg_color_fs = {0, };
+ GdkPixbuf *pixbuf = viewer->priv->dst_pixbuf;
+ /** BELOW THIS LINE THE VARIABLE_NAMES GET MESSY **/
+ GdkColor color;
+ GdkColor line_color;
+ GdkPixbuf *n_pixbuf = NULL;
+ gint width, height;
+ gdouble m_x1, m_x2, m_y1, m_y2;
+ gint x1, x2, y1, y2;
+ gint i, a;
+ /** ABOVE THIS LINE THE VARIABLE_NAMES GET MESSY **/
+
+ g_value_init (&val_bg_color, GDK_TYPE_COLOR);
+ g_value_init (&val_bg_color_fs, GDK_TYPE_COLOR);
+ g_value_init (&val_bg_color_override, G_TYPE_BOOLEAN);
+
+ g_object_get_property (G_OBJECT(viewer->priv->settings), "bgcolor", &val_bg_color);
+ g_object_get_property (G_OBJECT(viewer->priv->settings), "bgcolor-override", &val_bg_color_override);
+ g_object_get_property (G_OBJECT(viewer->priv->settings), "bgcolor-fullscreen", &val_bg_color_fs);
+
+ /* required for transparent pixbufs... add double buffering to fix flickering*/
+ if(GTK_WIDGET_REALIZED(widget))
+ {
+ GdkPixmap *buffer = gdk_pixmap_new(NULL, widget->allocation.width, widget->allocation.height, gdk_drawable_get_depth(widget->window));
+ GdkGC *gc = gdk_gc_new(GDK_DRAWABLE(buffer));
+
+ if(gdk_window_get_state(gdk_window_get_toplevel(GTK_WIDGET(viewer)->window)) & GDK_WINDOW_STATE_FULLSCREEN)
+ {
+ bg_color = g_value_get_boxed (&val_bg_color_fs);
+ }
+ else
+ {
+ if (g_value_get_boxed (&val_bg_color) && g_value_get_boolean (&val_bg_color_override))
+ {
+ bg_color = g_value_get_boxed (&val_bg_color);
+ }
+ else
+ {
+ bg_color = &(widget->style->bg[GTK_STATE_NORMAL]);
+ }
+ }
+
+ gdk_window_set_background (widget->window, bg_color);
+
+ gdk_colormap_alloc_color (gdk_gc_get_colormap (gc), bg_color, FALSE, TRUE);
+ gdk_gc_set_rgb_bg_color (gc, bg_color);
+
+ gdk_draw_rectangle(GDK_DRAWABLE(buffer), gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
+
+ /* Check if there is a destination pixbuf */
+ if(pixbuf)
+ {
+ g_debug ("Draw image");
+ x1 = (widget->allocation.width-gdk_pixbuf_get_width(pixbuf))<0?0:(widget->allocation.width-gdk_pixbuf_get_width(pixbuf))/2;
+ y1 = (widget->allocation.height-gdk_pixbuf_get_height(pixbuf))<0?0:(widget->allocation.height-gdk_pixbuf_get_height(pixbuf))/2;
+ x2 = gdk_pixbuf_get_width(pixbuf);
+ y2 = gdk_pixbuf_get_height(pixbuf);
+
+ /* We only need to paint a checkered background if the image is transparent */
+ if(gdk_pixbuf_get_has_alpha(pixbuf))
+ {
+ for(i = 0; i <= x2/10; i++)
+ {
+ if(i == x2/10)
+ {
+ width = x2-10*i;
+ }
+ else
+ {
+ width = 10;
+ }
+ for(a = 0; a <= y2/10; a++)
+ {
+ if(a%2?i%2:!(i%2))
+ color.pixel = 0xcccccccc;
+ else
+ color.pixel = 0xdddddddd;
+ gdk_gc_set_foreground(gc, &color);
+ if(a == y2/10)
+ {
+ height = y2-10*a;
+ }
+ else
+ {
+ height = 10;
+ }
+
+ gdk_draw_rectangle(GDK_DRAWABLE(buffer),
+ gc,
+ TRUE,
+ x1+10*i,
+ y1+10*a,
+ width,
+ height);
+ }
+ }
+ }
+ gdk_draw_pixbuf(GDK_DRAWABLE(buffer),
+ NULL,
+ pixbuf,
+ 0,
+ 0,
+ x1,
+ y1,
+ x2,
+ y2,
+ GDK_RGB_DITHER_NONE,
+ 0,0);
+ if(viewer->priv->motion.state == RSTTO_PICTURE_VIEWER_MOTION_STATE_BOX_ZOOM)
+ {
+ gdk_gc_set_foreground(gc,
+ &(widget->style->fg[GTK_STATE_SELECTED]));
+
+ if (viewer->priv->motion.x < viewer->priv->motion.current_x)
+ {
+ m_x1 = viewer->priv->motion.x;
+ m_x2 = viewer->priv->motion.current_x;
+ }
+ else
+ {
+ m_x1 = viewer->priv->motion.current_x;
+ m_x2 = viewer->priv->motion.x;
+ }
+ if (viewer->priv->motion.y < viewer->priv->motion.current_y)
+ {
+ m_y1 = viewer->priv->motion.y;
+ m_y2 = viewer->priv->motion.current_y;
+ }
+ else
+ {
+ m_y1 = viewer->priv->motion.current_y;
+ m_y2 = viewer->priv->motion.y;
+ }
+ if (m_y1 < y1)
+ m_y1 = y1;
+ if (m_x1 < x1)
+ m_x1 = x1;
+
+ if (m_x2 > x2 + x1)
+ m_x2 = x2 + x1;
+ if (m_y2 > y2 + y1)
+ m_y2 = y2 + y1;
+
+ if ((m_x2 - m_x1 >= 2) && (m_y2 - m_y1 >= 2))
+ {
+ GdkPixbuf *sub = gdk_pixbuf_new_subpixbuf(pixbuf,
+ m_x1-x1,
+ m_y1-y1,
+ m_x2-m_x1,
+ m_y2-m_y1);
+ if(sub)
+ {
+ sub = gdk_pixbuf_composite_color_simple(sub,
+ m_x2-m_x1,
+ m_y2-m_y1,
+ GDK_INTERP_BILINEAR,
+ 200,
+ 200,
+ widget->style->bg[GTK_STATE_SELECTED].pixel,
+ widget->style->bg[GTK_STATE_SELECTED].pixel);
+
+ gdk_draw_pixbuf(GDK_DRAWABLE(buffer),
+ gc,
+ sub,
+ 0,0,
+ m_x1,
+ m_y1,
+ -1, -1,
+ GDK_RGB_DITHER_NONE,
+ 0, 0);
+
+ gdk_pixbuf_unref(sub);
+ sub = NULL;
+ }
+ }
+
+ gdk_draw_rectangle(GDK_DRAWABLE(buffer),
+ gc,
+ FALSE,
+ m_x1,
+ m_y1,
+ m_x2 - m_x1,
+ m_y2 - m_y1);
+ }
+
+ }
+ else
+ {
+ /* HACK HACK HACK HACK */
+ guint size = 0;
+ if ((GTK_WIDGET (viewer)->allocation.width) < (GTK_WIDGET (viewer)->allocation.height))
+ {
+ size = GTK_WIDGET (viewer)->allocation.width;
+ }
+ else
+ {
+ size = GTK_WIDGET (viewer)->allocation.height;
+ }
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
+ "ristretto",
+ (size*0.8),
+ GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
+ if (pixbuf)
+ {
+ gdk_pixbuf_saturate_and_pixelate (pixbuf, pixbuf, 0, TRUE);
+ n_pixbuf = gdk_pixbuf_composite_color_simple (pixbuf, (size*0.8), (size*0.8), GDK_INTERP_BILINEAR, 40, 40, bg_color->pixel, bg_color->pixel);
+ g_object_unref (pixbuf);
+ pixbuf = n_pixbuf;
+
+ x1 = (widget->allocation.width-gdk_pixbuf_get_width(pixbuf))<0?0:(widget->allocation.width-gdk_pixbuf_get_width(pixbuf))/2;
+ y1 = (widget->allocation.height-gdk_pixbuf_get_height(pixbuf))<0?0:(widget->allocation.height-gdk_pixbuf_get_height(pixbuf))/2;
+ x2 = gdk_pixbuf_get_width(pixbuf);
+ y2 = gdk_pixbuf_get_height(pixbuf);
+
+ gdk_draw_pixbuf(GDK_DRAWABLE(buffer),
+ NULL,
+ pixbuf,
+ 0,
+ 0,
+ x1,
+ y1,
+ x2,
+ y2,
+ GDK_RGB_DITHER_NONE,
+ 0,0);
+ }
+ }
+
+ gdk_draw_drawable(GDK_DRAWABLE(widget->window),
+ gdk_gc_new(widget->window),
+ buffer,
+ 0,
+ 0,
+ 0,
+ 0,
+ widget->allocation.width,
+ widget->allocation.height);
+ g_object_unref(buffer);
+
+ }
+}
+
+static void
+rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer, gboolean refresh)
+{
+ if (viewer->priv->repaint.idle_id > 0)
+ {
+ g_source_remove(viewer->priv->repaint.idle_id);
+ }
+ if (refresh)
+ {
+ viewer->priv->repaint.refresh = TRUE;
+ }
+ viewer->priv->repaint.idle_id = g_idle_add((GSourceFunc)cb_rstto_image_viewer_queued_repaint, viewer);
}
@@ -441,6 +738,8 @@ rstto_image_viewer_load_image (RsttoImageViewer *viewer, GFile *file)
transaction->file = file;
transaction->viewer = viewer;
+ 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);
viewer->priv->transaction = transaction;
@@ -516,6 +815,7 @@ cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncRes
/* TODO: FIXME -- Clean up the transaction*/
if (read_bytes == -1)
{
+ gdk_pixbuf_loader_close (transaction->loader, NULL);
rstto_image_viewer_transaction_free (transaction);
return;
}
@@ -526,6 +826,7 @@ cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncRes
{
g_input_stream_close (G_INPUT_STREAM (source_object), NULL, NULL);
+ gdk_pixbuf_loader_close (transaction->loader, NULL);
rstto_image_viewer_transaction_free (transaction);
}
else
@@ -551,17 +852,43 @@ cb_rstto_image_viewer_read_input_stream_ready (GObject *source_object, GAsyncRes
}
}
-static void
-cb_rstto_image_loader_closed (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction)
-{
- g_debug("%s", __FUNCTION__);
-
-}
static void
cb_rstto_image_loader_area_prepared (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction)
{
+ gint timeout = 0;
+ RsttoImageViewer *viewer = transaction->viewer;
+ if (viewer->priv->transaction == transaction)
+ {
+ 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 != -1)
+ {
+ /* fix borked stuff */
+ if (timeout == 0)
+ {
+ g_warning("timeout == 0: defaulting to 40ms");
+ timeout = 40;
+ }
+
+ 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);
+
+ rstto_image_viewer_queued_repaint (viewer, TRUE);
+ }
}
static void
@@ -578,5 +905,75 @@ cb_rstto_image_loader_size_prepared (GdkPixbufLoader *loader, gint width, gint h
{
gdk_pixbuf_loader_set_size (loader, s_width, s_height);
}
+
+}
+
+static void
+cb_rstto_image_loader_closed (GdkPixbufLoader *loader, RsttoImageViewerTransaction *transaction)
+{
+ g_debug("%s", __FUNCTION__);
+
+ rstto_image_viewer_queued_repaint (transaction->viewer, TRUE);
+}
+
+static gboolean
+cb_rstto_image_viewer_update_pixbuf (RsttoImageViewer *viewer)
+{
+ gint timeout = 0;
+
+ 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;
+ }
+
+ /* The pixbuf returned by the GdkPixbufAnimationIter might be reused,
+ * lets make a copy for myself just in case
+ */
+ viewer->priv->pixbuf = gdk_pixbuf_copy (gdk_pixbuf_animation_iter_get_pixbuf (viewer->priv->iter));
+ }
+
+ timeout = gdk_pixbuf_animation_iter_get_delay_time (viewer->priv->iter);
+
+ if (timeout != -1)
+ {
+ if (timeout == 0)
+ {
+ g_warning("timeout == 0: defaulting to 40ms");
+ timeout = 40;
+ }
+ viewer->priv->animation_timeout_id = g_timeout_add(timeout, (GSourceFunc)cb_rstto_image_viewer_update_pixbuf, viewer);
+ }
+
+ rstto_image_viewer_queued_repaint (viewer, TRUE);
+
+ return FALSE;
+ }
+ return FALSE;
}
+static gboolean
+cb_rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer)
+{
+ g_debug("%s", __FUNCTION__);
+ g_source_remove (viewer->priv->repaint.idle_id);
+ viewer->priv->repaint.idle_id = -1;
+ viewer->priv->repaint.refresh = FALSE;
+
+ if (viewer->priv->pixbuf)
+ {
+ viewer->priv->dst_pixbuf = gdk_pixbuf_scale_simple (viewer->priv->pixbuf,
+ (GTK_WIDGET(viewer)->allocation.width),
+ (GTK_WIDGET(viewer)->allocation.height),
+ GDK_INTERP_BILINEAR);
+ }
+ rstto_image_viewer_paint (GTK_WIDGET (viewer));
+
+
+
+}
More information about the Xfce4-commits
mailing list