From 2a497a06d9297712778b9bfde3f21a2bd867967c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ball=C3=B3=20Gy=C3=B6rgy?= <ballogyor@gmail.com>
Date: Tue, 21 Feb 2017 01:06:06 +0100
Subject: [PATCH] Fix displaying images with GTK3

We have to use the cairo context provided by the draw event, otherwise the scrolling does not work properly.

Don't paint the whole image when scale == 1, it's unneeded and slow.
---
 src/image-view.c | 86 +++++++++++++++++++++++++++++---------------------------
 1 file changed, 44 insertions(+), 42 deletions(-)

diff --git a/src/image-view.c b/src/image-view.c
index b367f2a..820b843 100644
--- a/src/image-view.c
+++ b/src/image-view.c
@@ -24,11 +24,10 @@
 static void image_view_finalize(GObject *iv);
 
 static void image_view_clear( ImageView* iv );
-static gboolean on_idle( ImageView* iv );
 static void calc_image_area( ImageView* iv );
-static void paint(  ImageView* iv, GdkRectangle* invalid_rect, GdkInterpType type );
 
 #if GTK_CHECK_VERSION(3, 0, 0)
+static void paint(  ImageView* iv, GdkRectangle* invalid_rect, GdkInterpType type, cairo_t* cr );
 
 static void image_view_paint(  ImageView* iv, cairo_t* cr );
 
@@ -37,6 +36,8 @@ static void on_get_preferred_height( GtkWidget* widget, gint* minimal_height, gi
 static gboolean on_draw_event(GtkWidget* widget, cairo_t* cr);
 
 #else // GTK2
+static gboolean on_idle( ImageView* iv );
+static void paint(  ImageView* iv, GdkRectangle* invalid_rect, GdkInterpType type );
 
 static void image_view_paint(  ImageView* iv, GdkEventExpose* evt );
 
@@ -268,16 +269,13 @@ void image_view_paint( ImageView* iv, cairo_t *cr )
         {
             cairo_rectangle_int_t rectangle;
             cairo_region_get_rectangle(region, i, &rectangle);
-            paint( iv, &rectangle, GDK_INTERP_NEAREST );
+            paint( iv, &rectangle, GDK_INTERP_NEAREST, cr );
         }
 
         cairo_region_destroy (region);
-
-        if( 0 == iv->idle_handler )
-            iv->idle_handler = g_idle_add( (GSourceFunc)on_idle, iv );
     }
 }
-#else
+#else // GTK2
 
 gboolean on_expose_event( GtkWidget* widget, GdkEventExpose* evt )
 {
@@ -390,6 +388,8 @@ void image_view_set_scale( ImageView* iv, gdouble new_scale, GdkInterpType type
     }
 }
 
+#if GTK_CHECK_VERSION(3, 0, 0)
+#else // GTK2
 gboolean on_idle( ImageView* iv )
 {
     GDK_THREADS_ENTER();
@@ -435,6 +435,7 @@ gboolean on_idle( ImageView* iv )
     iv->idle_handler = 0;
     return FALSE;
 }
+#endif
 
 void calc_image_area( ImageView* iv )
 {
@@ -460,7 +461,11 @@ void calc_image_area( ImageView* iv )
     }
 }
 
+#if GTK_CHECK_VERSION(3, 0, 0)
+void paint( ImageView* iv, GdkRectangle* invalid_rect, GdkInterpType type, cairo_t* cr )
+#else // GTK2
 void paint( ImageView* iv, GdkRectangle* invalid_rect, GdkInterpType type )
+#endif
 {
     GdkRectangle rect;
     if( ! gdk_rectangle_intersect( invalid_rect, &iv->img_area, &rect ) )
@@ -470,51 +475,48 @@ void paint( ImageView* iv, GdkRectangle* invalid_rect, GdkInterpType type )
     int dest_y;
 
     GdkPixbuf* src_pix = NULL;
-    if( iv->scale == 1.0 )  // original size
-    {
-        src_pix = (GdkPixbuf*)g_object_ref( iv->pix );
-        dest_x = iv->img_area.x;
-        dest_y = iv->img_area.y;
-    }
-    else    // scaling is needed
+    GdkPixbuf* scaled_pix = NULL;
+
+    dest_x = rect.x;
+    dest_y = rect.y;
+
+    rect.x -= iv->img_area.x;
+    rect.y -= iv->img_area.y;
+
+    int src_x = (int)floor( ((gdouble)rect.x) / iv->scale + 0.5 );
+    int src_y = (int)floor( ((gdouble)rect.y) / iv->scale + 0.5 );
+    int src_w = (int)floor( ((gdouble)rect.width) / iv->scale + 0.5 );
+    int src_h = (int)floor( ((gdouble)rect.height) / iv->scale + 0.5 );
+    if( src_y > gdk_pixbuf_get_height( iv->pix ) )
+        src_y = gdk_pixbuf_get_height( iv->pix );
+    if( src_x + src_w > gdk_pixbuf_get_width( iv->pix ) )
+        src_w = gdk_pixbuf_get_width( iv->pix ) - src_x;
+    if( src_y + src_h > gdk_pixbuf_get_height( iv->pix ) )
+        src_h = gdk_pixbuf_get_height( iv->pix ) - src_y;
+    //g_debug("orig src: x=%d, y=%d, w=%d, h=%d",
+    //        src_x, src_y, src_w, src_h );
+
+    if ((src_w > 0) && (src_h > 0))
     {
-        dest_x = rect.x;
-        dest_y = rect.y;
-
-        rect.x -= iv->img_area.x;
-        rect.y -= iv->img_area.y;
-
-        GdkPixbuf* scaled_pix = NULL;
-        int src_x = (int)floor( ((gdouble)rect.x) / iv->scale + 0.5 );
-        int src_y = (int)floor( ((gdouble)rect.y) / iv->scale + 0.5 );
-        int src_w = (int)floor( ((gdouble)rect.width) / iv->scale + 0.5 );
-        int src_h = (int)floor( ((gdouble)rect.height) / iv->scale + 0.5 );
-        if( src_y > gdk_pixbuf_get_height( iv->pix ) )
-            src_y = gdk_pixbuf_get_height( iv->pix );
-        if( src_x + src_w > gdk_pixbuf_get_width( iv->pix ) )
-            src_w = gdk_pixbuf_get_width( iv->pix ) - src_x;
-        if( src_y + src_h > gdk_pixbuf_get_height( iv->pix ) )
-            src_h = gdk_pixbuf_get_height( iv->pix ) - src_y;
-        //g_debug("orig src: x=%d, y=%d, w=%d, h=%d",
-        //        src_x, src_y, src_w, src_h );
-
-        if ((src_w > 0) && (src_h > 0))
-        {
-            src_pix = gdk_pixbuf_new_subpixbuf( iv->pix, src_x, src_y,  src_w, src_h );
-            scaled_pix = gdk_pixbuf_scale_simple( src_pix, rect.width, rect.height, type );
-            g_object_unref( src_pix );
-            src_pix = scaled_pix;
-        }
-
+        src_pix = gdk_pixbuf_new_subpixbuf( iv->pix, src_x, src_y,  src_w, src_h );
+        scaled_pix = gdk_pixbuf_scale_simple( src_pix, rect.width, rect.height, type );
+        g_object_unref( src_pix );
+        src_pix = scaled_pix;
     }
 
     if( G_LIKELY(src_pix) )
     {
         GtkWidget* widget = (GtkWidget*)iv;
+#if GTK_CHECK_VERSION(3, 0, 0)
+#else // GTK2
         cairo_t *cr = gdk_cairo_create (gtk_widget_get_window(widget));
+#endif
         gdk_cairo_set_source_pixbuf (cr, src_pix, dest_x, dest_y);
         cairo_paint (cr);
+#if GTK_CHECK_VERSION(3, 0, 0)
+#else // GTK2
         cairo_destroy (cr);
+#endif
 
         g_object_unref( src_pix );
     }
-- 
2.11.1
