Vala, OpenGL and Gtk+ sample code with shaders on Gnu/Linux

This is the follow up post for the discoveries which I was doing for myself to unify OpenGL support with Gtk+. Here, you can find a first post, I have shared towards this direction.
The content of the trivial shader program: vertex-shader.txt

#version 130

attribute vec4 vPosition;

void main () {
	gl_Position = vPosition;
}

Here,
fragment-shader.txt

#version 130

precision mediump float;
uniform vec4 vColor;

void main () {
	gl_FragColor = vColor;
}
using GL;

namespace Evg {
	public class Shader {
		private bool loaded;
		private uint type;
		private uint id;

		public Shader () {
			this.loaded = false;
			this.id = 0;
		}

		~Shader () {
			this.delete ();
		}

		public bool load_from_string (string shader, uint type) {
			this.id = glCreateShader (type);

			stdout.printf ("id is %u\n", id);

			glShaderSource (id, shader);
			glCompileShader (id);

			int status;
			glGetShaderiv (id, GL_COMPILE_STATUS, out status);

			if (status == GL_FALSE) {
				stdout.printf ("shader info log: '%s'\n", glGetShaderInfoLog (this.id));
				return false;
			}

			this.type = type;
			this.loaded = true;

			return true;
		}

		public bool load_from_file (string path, uint type) {
			File file = File.new_for_path (path);

			if (!file.query_exists ()) {
				stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
				return false;
			}

			try {
				DataInputStream dis = new DataInputStream (file.read ());
				StringBuilder sb = new StringBuilder ();
				string line;

				while ((line = dis.read_line ()) != null) {
					sb.append_printf ("%s\n", line);
				}

				return this.load_from_string (sb.str, type);
			} catch (Error e) {
				error ("%s", e.message);
			}
		}

		public bool is_loaded () {
			return this.loaded;
		}

		public uint get_id () {
			return this.id;
		}

		public void delete () {
			if (!this.loaded) return;
			this.loaded = false;
			glDeleteShader (this.id);
		}
	}
}
using GL;

namespace Evg {
	public class Program {
		private bool linked;
		private uint id;

		public Program () {
			this.id = 0;
			this.linked = false;
		}

		public uint get_id () {
			return this.id;
		}

		public bool create () {
			this.id = glCreateProgram ();
			return (this.id != 0);
		}

		public bool attach_shader (Evg.Shader shader) {
			if (!shader.is_loaded ())
				return false;

			glAttachShader (this.id, shader.get_id ());
			return true;
		}

		public bool is_linked () {
			return this.linked;
		}

		public bool is_created () {
			return (this.id != 0);
		}

		public bool link () {
			glLinkProgram (this.id);

			int status;
			glGetProgramiv (this.id, GL_LINK_STATUS, out status);
			this.linked = (status == GL_TRUE);

			if (!this.linked) {
				stdout.printf ("program info log: '%s'\n", glGetProgramInfoLog (this.id));
			}

			return this.linked;
		}

		public void use () {
			if (this.linked)
				glUseProgram (this.id);
		}

		public void delete () {
			if (!this.linked)
				return;

			this.linked = false;
			glDeleteProgram (this.id);
			this.id = 0;
		}

		~Program () {
			this.delete ();
		}
	}
}
using GLX;
using GL;

class GLXSample : Gtk.Window {

    private unowned X.Display xdisplay;
    private GLX.Context context;
    private GLX.XVisualInfo xvinfo;

	private Evg.Shader vertex_shader;
	private Evg.Shader fragment_shader;
	private Evg.Program program;
	private Triangle triangle;

    public GLXSample () {
        this.title = "OpenGL with GLX";
        this.set_reallocate_redraws (true);
        this.destroy.connect (Gtk.main_quit);

        int[] attrlist = {
            GLX_RGBA,
            GLX_RED_SIZE, 1,
            GLX_GREEN_SIZE, 1,
            GLX_BLUE_SIZE, 1,
            GLX_DOUBLEBUFFER, 0
        };

        this.xdisplay = Gdk.x11_get_default_xdisplay ();

        if (!glXQueryExtension (xdisplay, null, null)) {
            stderr.printf ("OpenGL not supported\n");
        }

        this.xvinfo = glXChooseVisual (xdisplay,
									   Gdk.x11_get_default_screen (),
									   attrlist );

        if (xvinfo == null) {
            stderr.printf ("Error configuring OpenGL\n");
        }

        var drawing_area = new Gtk.DrawingArea ();
        drawing_area.set_size_request (300, 300);
        drawing_area.set_double_buffered (false);

        this.context = glXCreateContext (xdisplay, xvinfo, null, true);

        drawing_area.configure_event.connect (on_configure_event);
		drawing_area.realize.connect (on_realize);
        drawing_area.draw.connect (on_draw);

        this.add (drawing_area);
    }

	private void on_realize (Gtk.Widget widget) {
		if (!glXMakeCurrent (xdisplay,
							 Gdk.X11Window.get_xid (widget.get_window ()),
							 context))
            return;

		stdout.printf ("Vendor: ........... %s\n", glGetString (GL_VENDOR));
		stdout.printf ("Renderer: ......... %s\n", glGetString (GL_RENDERER));
		stdout.printf ("Version: .......... %s\n", glGetString (GL_VERSION));
		stdout.printf ("GLSL version: ..... %s\n",
					   glGetString (GL_SHADING_LANGUAGE_VERSION));

		this.vertex_shader = new Evg.Shader ();

		stdout.printf ("loading vertex shader\n");
		vertex_shader.load_from_file ("vertex-shader.txt", GL_VERTEX_SHADER);
		stdout.printf ("vertex shader is loaded %s\n",
					   vertex_shader.is_loaded ().to_string ());

		this.fragment_shader = new Evg.Shader ();

		stdout.printf ("loading fragment shader\n");
		fragment_shader.load_from_file ("fragment-shader.txt", GL_FRAGMENT_SHADER);
		stdout.printf ("fragment shader is loaded %s\n",
					   fragment_shader.is_loaded ().to_string ());

		this.program = new Evg.Program ();
		this.program.create ();
		stdout.printf ("program is created %s\n", program.is_created ().to_string ());
		this.program.attach_shader (this.vertex_shader);
		this.program.attach_shader (this.fragment_shader);
		this.program.link ();
		this.program.use ();
		stdout.printf ("program is linked %s\n", program.is_linked ().to_string ());

		this.triangle = new Triangle (this.program.get_id ());
	}

    private bool on_configure_event (Gtk.Widget widget, Gdk.EventConfigure event) {
        if (!glXMakeCurrent (xdisplay,
							 Gdk.X11Window.get_xid (widget.get_window ()),
							 context))
            return false;

		int width = widget.get_allocated_width ();
		int height = widget.get_allocated_height ();
		int size = int.min (width, height);

		glViewport ((width - size) / 2, (height - size) / 2, size, size);

        return true;
    }

    private bool on_draw (Gtk.Widget widget, Cairo.Context cr) {
        if (!glXMakeCurrent (xdisplay,
							 Gdk.X11Window.get_xid (widget.get_window ()),
							 context))
            return false;

        glClear( GL_COLOR_BUFFER_BIT );

		this.triangle.draw ();

        glXSwapBuffers (xdisplay, Gdk.X11Window.get_xid (widget.get_window ()));

        return true;
    }
}

public class Triangle {
	private float[] color = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
	private float[] triangle_vertex = {
         0.0f,  0.622008459f, 0.0f,
        -0.5f, -0.311004243f, 0.0f,
         0.5f, -0.311004243f, 0.0f
    };

	private uint program_id;

	public Triangle (uint program_id) {
		this.program_id = program_id;
	}

	public void draw () {
		int position_id = glGetAttribLocation (this.program_id, "vPosition");
		glEnableVertexAttribArray (position_id);
		glVertexAttribPointer (position_id, 3, GL_FLOAT, false, 12, triangle_vertex);

		int color_id = glGetUniformLocation (this.program_id, "vColor");
		glUniform4fv(color_id, 1, color);

		glDrawArrays (GL_TRIANGLES, 0, 3);

		glDisableVertexAttribArray (position_id);
	}
}

void main (string[] args) {
    Gtk.init (ref args);

    var sample = new GLXSample ();
    sample.show_all ();

    Gtk.main ();
}

The content of the makefile:

all:
	valac-0.18 -o glx-test glx-test.vala evg-shader.vala evg-program.vala --vapidir ../vapi --pkg gl --pkg gl3 --pkg gio-2.0 --pkg gtk+-3.0 --pkg glx --pkg gdk-x11-3.0 #--ccode
Advertisements

GSOC with gnome-clocks – Final Report

Well people, the summer is sadly long gone, at least for me, and my summer of coding is approaching its end as well. I must say, that I am very thankful to Google for this opportunity to work in concert with my preferred desktop environment, which is still GNOME. I am glad, that I have seized this frame to finally move myself toward the first contribution to the GNOME project. I really enjoy this time and it’s a great pleasure for me, may be due my awesome mentor Paolo Borelli, I luckily have chosen for me. Thank you. ­čÖé Moreover, during this period I have improved my knowledge in different areas and gained a lot of experience.

About the project results: as were reported many times geolocation support has managed to land in last minute to the 3.10 release, which is for sure great!
Moreover, there is even a not yet documented option for our users to toggle the geolocation service:

$ echo "Turn off geolocation support"
$ gsettings set org.gnome.clocks geolocation 'false'
$ echo "Turn on again"
$ gsettings set org.gnome.clocks geolocation 'true'

There is an experimental city images support in gnome-clocks available in the wip/cityimages branch try it out.
Screenshot from 2013-09-21 18:53:33 A youtube video is also available: city images – preview. The video illustrates the functionality of the implemented image providers: flickr image provider requests the corresponding images from the gnome-clocks flickr group, and downloads them for you, so the next time you launch the application they appear instantaneously. The capabilities of the local image provider are also demonstrated: It means, that you always have a possibility to overwrite the suggested image by the flickr provider with your own, you would like to see in gnome-clocks. Therefore you just need to put the corresponding image file into the folder:

~/.local/share/gnome-clocks/city-images/

Be aware of the following name convention for the image files. They should be named like: “berlin-germany-day.jpg” At the moment you can have two images for each location; one for a day and one for a night, the latter having the suffix “…-night.jpg” in its file name.

More information about gnome-clocks enhancements are available on the project page. Take care ­čÖé

Aaaah, and one more thank you for my sponsored travel to the GUADEC this year, it was just amazing ­čÖé
sponsored-badge-simple

Vala support for the Libgweather

The recent version of libgweather library from git master comes with the Vala bindings support. At least the Clocks App (gnome-clocks) will heavily rely on this bindings support and therefore we are very thankful to Giovanni Campagna for his fruitful cooperation and good and friendly support.

Please note additionally, that the new version of libgweather will deprecate some function calls. To obtain a new instance of the Location object the function “gweather_location_get_world” should be used instead of “gweather_location_new_world”. “gweather_location_new_world” is deprecated and should be omitted in the newly written code. There are many more, so for more details please refer to the official documentation.

In favour of this good announcement I would like to share with you a small sample code written in Vala, in which some capabilities of the libgweather library are briefly demonstrated: This example reveals how to obtain a timezone name for almost all corresponding major cities.
libgweather
Sample app:

public class LocationInfo {
    private Gtk.Window window;
    private Gtk.Box box;
    private GWeather.LocationEntry location_entry;
    private Gtk.Label city_label;
    private Gtk.Label timezone_label;

    public LocationInfo () {
        Gtk.Builder builder = new Gtk.Builder ();

        try {
            builder.add_from_file ("window.ui");
        } catch (Error e) {}

        this.window = builder.get_object ("window") as Gtk.Window;

        this.window.title = "libgweather testing";
        this.window.border_width = 10;
        this.window.window_position = Gtk.WindowPosition.CENTER;
        this.window.destroy.connect (Gtk.main_quit);

        this.box = builder.get_object ("box") as Gtk.Box;
        this.location_entry =
          new GWeather.LocationEntry (GWeather.Location.get_world ());
        this.location_entry.set_activates_default (true);
        this.location_entry.changed.connect (this.location_defined);
        this.box.pack_start (location_entry);

        this.city_label = builder.get_object ("city") as Gtk.Label;
        this.timezone_label = builder.get_object ("time_zone") as Gtk.Label;
    }

    public void show () {
        this.window.show_all ();
    }

    private void location_defined () {
        GWeather.Location? l = null;
        GWeather.Timezone? t = null;

        if (this.location_entry.get_text () != "") {
            l = this.location_entry.get_location ();
        }

		if (l != null) {
			t = l.get_timezone ();

			this.city_label.set_text (l.get_city_name ());

			if (t != null)
				this.timezone_label.set_text (t.get_tzid ());
			else
				this.timezone_label.set_text ("Unknown");
		}
		else {
			this.city_label.set_text ("");
			this.timezone_label.set_text ("");
		}
	}

    public static void main (string[] args)	{
        Gtk.init (ref args);

        var location_info = new LocationInfo ();
        location_info.show ();
	
		Gtk.main ();
	}
}

The code can be compiled with the following Makefile:

all:
	valac --pkg gtk+-3.0 --target-glib=2.38 gweather-sample.vala \
		--pkg gweather-3.0 -X -DGWEATHER_I_KNOW_THIS_IS_UNSTABLE

The source code can be found here: libgweather-vala.tar.gz.

Emacs: How to use white spaces instead of tabs when writing C or Vala code

Many projects have their own policy regarding the code style, so it can happen to you that while working on one of them it is required to use white spaces as indentation instead of commonly used tabs. To activate this feature within the emacs editor only when working with C or Vala source code you can place this in your ~/.emacs file:

(add-hook 'c-mode-hook (lambda () (setq indent-tabs-mode nil)))
(add-hook 'vala-mode-hook (lambda () (setq indent-tabs-mode nil)))

A small note: If it should be applicable for a specific project one can combine the above feature with Directory Variables.

Additional references: spaces instead of tabs

Turorial for OpenGL and Gtk3+ combined, written in Vala

This post is still work in progress!
The main target of this code sample, even if it’s trivial one, is to run a openGL based application on top of the modern window library Gtk+3 on Gnu/Linux. It must be possible to run this openGL code combined with Gtk+ on windows, but I personally do not know how to do it, as I rarely use windows myself. Well, actually, I use it only to set up it for my girlfriend or to solve the endless number of issues my girlfriend has ran into. If you, by the way, know howto extend this simple example, written in vala, so it can be launched on windows, please share it with me.)) The reason for this incompatibility is that here the X11 related functions calls are used to establish the incorporation between Gtk3, Gdk and OpenGL on the other side.

This sample code for simplicity reasons covers only the openGL 1 API. The example with vertex and fragment shaders, respectively, will be considered in the succeeding posts.
Here, therefore we first create a new custom window by inheriting the Gtk window class functionality and add a drawing area to it. The drawing area afterwards will be responsible for the GL context. Below you can find a class template, which includes the step by step recipe, needed yet to be implemented.

/* here the opengl and X related libraries are included */
using GLX;
using GL;

class GLXSample : Gtk.Window {
    public GLXSample( ) {
        /* 1. adding custom setting for the newly created window */

        /* 2. preparing and intializing the opengl context */

        /* 3. creating the drawing area and adding it to the window */
        var drawing_area = new Gtk.DrawingArea( );
        /* adjusting the drawing area parameters */

        /* adding two events listeners: */
        /* the first handles the opengl content on window resize events */
        /* followed by the event which is responsible for the drawing */
        drawing_area.configure_event.connect( on_configure_event );
        drawing_area.draw.connect( on_draw );

        this.add( drawing_area );
    }

    private bool on_configure_event( Gtk.Widget widget, Gdk.EventConfigure event ) {
        /* adapting the opengl content on window size change */
        return true;
    }

    private bool on_draw( Gtk.Widget widget, Cairo.Context cr ) {
        /* drawing the opengl content here */
        return true;
    }
}

void main( string[] args ) {
    Gtk.init( ref args );

    var sample = new GLXSample( );
    sample.show_all( );

    Gtk.main( );
}

So, after implementing all the introduced steps will result in the following working code sample:

using GLX;
using GL;

class GLXSample : Gtk.Window {

    private unowned X.Display xdisplay;
    private GLX.Context context;
    private GLX.XVisualInfo xvinfo;

    public GLXSample( ) {
        this.title = "OpenGL with GLX";
        this.set_reallocate_redraws( true );
        this.destroy.connect( Gtk.main_quit );

        int[] attrlist = {
            GLX_RGBA,
            GLX_RED_SIZE, 1,
            GLX_GREEN_SIZE, 1,
            GLX_BLUE_SIZE, 1,
            GLX_DOUBLEBUFFER, 0
        };

        this.xdisplay = Gdk.x11_get_default_xdisplay( );
        
        if( !glXQueryExtension( xdisplay, null, null ) ) {
            stderr.printf( "OpenGL not supported\n" );
        }

        this.xvinfo = glXChooseVisual( xdisplay, Gdk.x11_get_default_screen( ), attrlist );
        
        if( xvinfo == null ) {
            stderr.printf( "Error configuring OpenGL\n" );
        }

        var drawing_area = new Gtk.DrawingArea( );
        drawing_area.set_size_request( 300, 300 );
        drawing_area.set_double_buffered( false );

        this.context = glXCreateContext( xdisplay, xvinfo, null, true );

        drawing_area.configure_event.connect( on_configure_event );
        drawing_area.draw.connect( on_draw );

        add( drawing_area );
    }

    private bool on_configure_event( Gtk.Widget widget, Gdk.EventConfigure event ) {
        if( !glXMakeCurrent( xdisplay, Gdk.X11Window.get_xid( widget.get_window( ) ), context ) )
            return false;

        GLsizei width = widget.get_allocated_width( );
        GLsizei height = widget.get_allocated_height( );
        GLsizei size = int.min( width, height );
		
        glViewport( (width - size ) / 2, (height - size ) / 2, size , size );

        return true;
    }

    private bool on_draw( Gtk.Widget widget, Cairo.Context cr ) {
        if( !glXMakeCurrent( xdisplay, Gdk.X11Window.get_xid( widget.get_window( ) ), context ) )
            return false;

        glClear( GL_COLOR_BUFFER_BIT );

        glBegin( GL_TRIANGLES );
            glIndexi( 0 );
            glColor3f( 1.0f, 0.0f, 0.0f );
            glVertex2i( 0, 1 );
            glIndexi( 0 );
            glColor3f( 0.0f, 1.0f, 0.0f );
            glVertex2i( -1, -1 );
            glIndexi( 0 );
            glColor3f( 0.0f, 0.0f, 1.0f );
            glVertex2i( 1, -1 );
        glEnd( );

        glXSwapBuffers( xdisplay, Gdk.X11Window.get_xid( widget.get_window( ) ) );

        return true;
    }
}

void main( string[] args ) {
    Gtk.init( ref args );

    var sample = new GLXSample( );
    sample.show_all( );

    Gtk.main( );
}

Here you can find a working makefile, which should make the compilation process easier.

all:
	valac --pkg gtk+-3.0 --pkg gdk-x11-3.0 --vapidir ../vapi --pkg gl --pkg glx glx-sample.vala -o glx-sample

Syntaxunterst├╝tzung f├╝r die Programmiersprache Vala in Emacs-Editor

Vala ist eine sehr moderne und eine auf Open-Source-Konzepte bassierende Programmiersprache mit einer sehr vergleichbaren mit Java- bzw. C#-Syntax und ist damit immer eine gute Wahl f├╝r jeden Programmierer. Jedoch ist deren Synteaxunterst├╝tzung noch nicht in vielen bekannten Editoren wie Emacs standartm├Ą├čig eingerichtet. Manuell aber l├Ąsst sich das sehr leicht beheben.

Seit Version 24 kommt Emacs mit dem preintallierten Packet “package.el” und bietet somit die Option andere Funktionserweiterungen aus den verschiedenen Repositorien nachzur├╝sten. Marmalade ist zum Beispiel so ein Package-Archieve, welches auch die Erweiterung “vala-mode” enth├Ąlt. Um diese zu aktivieren ben├Âtigt man folgende Schritte:

  1. Die “~/.emacs“-Datei wird mit dem folgenden Inhalt bereichert:
    (require 'package)
    (add-to-list 'package-archives
        '("marmalade" . "http://marmalade-repo.org/packages/"))
    (package-initialize)
  2. Danach werden die eben hinzugef├╝gte Funktionen mit dem Befehl “M-x eval-buffer” ausgef├╝hrt und die Liste der Erweterungen mit dem Befehl “M-x package-refresh-contents” aktualisiert.
  3. Anschlie├čend kann man die Unterst├╝tzung von Vala-Syntax mit dem Befehl “M-x package-install vala-mode” freischalten.

F├╝r die ├Ąlteren Versionen von Emacs kann man entweder das Packet “package.el” nachinstallieren, um die oben erw├Ąhneten Schritte machen zu k├Ânnen oder die vala-mode-Datei manuall in den Ordner “~/.emacs.d/” zu verschieben und die “~/.emacs“-Datei mit den folgenden Funktionen zu erweitern.

 (add-to-list 'load-path (expand-file-name "~/.emacs.d"))
(autoload 'vala-mode "vala-mode" "Major mode for editing Vala code." t)
(add-to-list 'auto-mode-alist '("\\.vala$" . vala-mode))
(add-to-list 'auto-mode-alist '("\\.vapi$" . vala-mode))
(add-to-list 'file-coding-system-alist '("\\.vala$" . utf-8))
(add-to-list 'file-coding-system-alist '("\\.vapi$" . utf-8))

Nun sollte einem erfolgreichen Vala-Projekt nichts im Wege stehen!

Referenz: Vala syntax support for Emacs

Using librsvg library and cairo graphics with vala

Recently, I was doing some research regarding possibilities of chess pieces drawing on a gtk+ widget. Taking out the most of the ideas from the glchess source code I have written a little application with vala, which shows a preview of chess pieces, found on wikipedia’s chess piece site or here on wikimedia and I would like to memorize it for me and share it with you. Especially, I liked the Maurizio Monge chess piece set.

So, in the following code snippet is demonstrated how to:

  • draw something in gtk+-3.0 within a widget named DrawingArea
  • access and read svg vector graphic files with a librsvg library and to render them afterwards with cairo
  • proceed mouse wheel and mouse click events using gdk and gtk+ respectively
  • transfer a svg file to a temporary created surface in memory for a later accelerated rendering on the widget

So, there are snapshots:



And the code below:

class PiecePreviewWindow : Gtk.Window
{
	public PiecePreviewWindow( ) {
		set_title( "Piece Preview" );
		add( new PieceView( ) );
		show_all( );
	}

	public override void destroy( ) {
		Gtk.main_quit( );
	}

	public static int main( string[] args ) {
		Gtk.init( ref args );
		new PiecePreviewWindow( );
		Gtk.main( );

		return 0;
	}
}

class PieceView : Gtk.DrawingArea
{
	public PieceView( ) {
		set_size_request( 400, 400 );
		add_events( Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.SCROLL_MASK );

		temp_surface = new Cairo.ImageSurface( Cairo.Format.ARGB32, 12 * square_size, square_size );

		string format = "./pieces/Maurizio Monge/Chess_Maurizio_Monge_Fantasy_%s%s.svg";
		string[] color = { "b", "w" };
		string[] piece = { "p", "r", "n", "b", "q", "k" };

		for( int c = 0; c < 2; c ++ ) {
			for(int p = 0; p < 6; p ++ ) {
				render_piece( format.printf( color[c], piece[p] ), 6 * c + p );
			}
		}
	}

	public override bool draw( Cairo.Context cr ) {
		cr.set_source_rgb( 0.5, 0.5, 0.5 );
		cr.rectangle( 0.0, 0.0, 400.0, 400.0 );
		cr.fill( );

		cr.scale( 400.0 / square_size, 400.0 / square_size );
		cr.set_source_surface( temp_surface, -offset * square_size, 0 );
		cr.rectangle( 0, 0, square_size, square_size );
		cr.clip( );
		cr.paint( );

		return false;
	}

	void render_piece( string file_name, int offset ) {
		Rsvg.Handle handle;
		try {
			handle = new Rsvg.Handle.from_file( file_name );
		} catch( Error e ) {
			stderr.printf( "can not open svg file\n" );
			return;
		}

		temp_cr = new Cairo.Context( temp_surface );
		temp_cr.save( );
		temp_cr.translate( square_size * offset, 0 );
		temp_cr.scale( (double) square_size / handle.width, (double) square_size / handle.height );
		handle.render_cairo( temp_cr );
		temp_cr.restore( );
	}

	public override bool button_press_event( Gdk.EventButton event ) {
		if( event.button  == 1 ) {
		 	change_piece( true );
		} else if( event.button == 3 ) {
			change_piece( false );
		} else
			return false;

		return true;
	}

	public override bool scroll_event( Gdk.EventScroll event ) {
		if( event.direction == Gdk.ScrollDirection.UP ) {
			change_piece( true );
		} else if( event.direction == Gdk.ScrollDirection.DOWN ) {
			change_piece( false );
		} else
			return false;
		return true;
	}

	private void change_piece( bool forward ) {
		if( forward ) offset ++;
		else offset --;

		if( offset < 0 ) offset = 11; 		if( offset > 11) offset = 0;

		queue_draw( );
	}

	private Cairo.ImageSurface temp_surface;
	private Cairo.Context temp_cr;
	private int square_size = 500;
	private int offset;
}

All this can be compiled with

# valac gtk-svg.vala --pkg librsvg-2.0 --pkg gtk+-3.0