/** * uni_image_view_fast_scroll: * * Actually scroll the views window using gdk_draw_drawable(). * GTK_WIDGET (view)->window is guaranteed to be non-NULL in this * function. **/ static void uni_image_view_fast_scroll (UniImageView * view, int delta_x, int delta_y) { GdkDrawable *drawable = GTK_WIDGET (view)->window; int src_x, src_y; int dest_x, dest_y; if (delta_x < 0) { src_x = 0; dest_x = -delta_x; } else { src_x = delta_x; dest_x = 0; } if (delta_y < 0) { src_y = 0; dest_y = -delta_y; } else { src_y = delta_y; dest_y = 0; } /* First move the part of the image that did not become hidden or shown by this operation. gdk_draw_drawable is probably very fast because it does not involve sending any data to the X11 server. Remember that X11 is weird shit. It does not remember how windows beneath other windows look like. So if another window overlaps this window, it will temporarily look corrupted. We fix that later by turning on "exposures." See below. */ GdkGC *gc = gdk_gc_new (drawable); Size alloc = uni_image_view_get_allocated_size (view); gdk_gc_set_exposures (gc, TRUE); gdk_draw_drawable (drawable, gc, drawable, src_x, src_y, dest_x, dest_y, alloc.width - abs (delta_x), alloc.height - abs (delta_y)); g_object_unref (gc); /* If we moved in both the x and y directions, two "strips" of the image becomes visible. One horizontal strip and one vertical strip. */ GdkRectangle horiz_strip = { 0, (delta_y < 0) ? 0 : alloc.height - abs (delta_y), alloc.width, abs (delta_y) }; uni_image_view_repaint_area (view, &horiz_strip); GdkRectangle vert_strip = { (delta_x < 0) ? 0 : alloc.width - abs (delta_x), 0, abs (delta_x), alloc.height }; uni_image_view_repaint_area (view, &vert_strip); /* Here is where we fix the weirdness mentioned above. I do not * really know why it works, but it does! */ GdkEvent *ev; while ((ev = gdk_event_get_graphics_expose (drawable)) != NULL) { GdkEventExpose *expose = (GdkEventExpose *) ev; int exp_count = expose->count; uni_image_view_repaint_area (view, &expose->area); gdk_event_free (ev); if (exp_count == 0) break; } }
static VALUE gdkevent_s_get_graphics_expose(G_GNUC_UNUSED VALUE self, VALUE window) { return make_gdkevent(gdk_event_get_graphics_expose(GDK_WINDOW(RVAL2GOBJ(window)))); }