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

Supporting multiple languages in your application – a simple gettext step-by-step example

First of all let’s create a small exemplary code, which should output some meaningless messages and save it in the file named “test_i18n.c”:

#include <libintl.h>
#include <locale.h>
#include <stdio.h>

#define PACKAGE "test_i18n"
#define LOCALEDIR "./"
#define _( str ) gettext( str )


void main( void ) 
{
  setlocale( LC_ALL, "" );
  bindtextdomain( PACKAGE, LOCALEDIR );
  textdomain( PACKAGE );

  printf( "msg: \"%s\".\n", _( "starting a new test" ) );
  printf( "msg: \"%s\".\n", gettext( "testing i18n" ) );
}

In the case you decide to translate your application with GNU gettext the code you need to include in each of your project is almost the same: a) The two header files from lines 1-2. The latter is needed to reset the locale category for all of the locale (LC_ALL). b) The three function calls from lines 12-14. The good thing is that you do not need to link against the implementation of libintl.h, when compiling with gcc, because it is already included in glibc. So, you can easily compile this example with:

$ gcc -o test_i18n test_i18n.c

Once compiled, the result can be tested even if no translation is done yet. The output of the just written example should be:

$ ./test_i18n 
msg: "starting a new test".
msg: "testing i18n".

At this state we can begin with the translation of our example in other desired languages. For this purpose we use the tool called “xgettext”, which will scan the source code and extract all the strings from there needed to be translated. All the string are the arguments of the function “gettext”. Additionally, one can pass an option like “–keyword=_” to xtettext denoting the abbreviation used instead of gettext function, introduced in line 7 of test_i18n.c file. Here is an example how to use it:

$ xgettext --package-name test_i18n --package-version 0.1 --default-domain test_i18n --keyword=_ --output=test_i18n.pot test_i18n.c

All the extracted strings will be saved in the file with the ending .pot – a so-called portable object template. Based on this template we can create translation files by coping it and translating the strings. Before doing so, it’s important to switch to the UTF-8 encoding. This is easily done by replacing CHARSET with UTF-8 in the “test_i18n.pot”.

$ sed --in-place test_i18n.pot --expression='s/CHARSET/UTF-8/'

Afterwards the pot file should have a similar look:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: test_i18n 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-03-01 21:24+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: test_i18n.c:16
msgid "starting a new test"
msgstr ""

#: test_i18n.c:17
msgid "testing i18n"
msgstr ""

Now we are ready to create a translation (test_german.po file) for a german locale (de_DE) by invoking the “msginit” tool and pointing it to the above mentioned template file as input.

$ msginit --no-translator --locale de_DE --output-file test_german.po --input test_i18n.pot

After providing the appropriate translation for each empty message string (msgstr “”) the test_german.po file should look similar to the following one:

# German translations for test_i18n package
# German messages for test_i18n.
# Copyright (C) 2012 THE test_i18n'S COPYRIGHT HOLDER
# This file is distributed under the same license as the test_i18n package.
# Automatically generated, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: test_i18n 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-03-01 21:24+0100\n"
"PO-Revision-Date: 2012-03-01 21:24+0100\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: test_i18n.c:16
msgid "starting a new test"
msgstr "Man startet einen neuen Test"

#: test_i18n.c:17
msgid "testing i18n"
msgstr "Teste I16g"

In contrast to a real application where the translation data is stored in the proper place, we will save the compiled binary data of translation locally. To do so requires a construction of the following directory structure:

$ mkdir --parents ./de_DE.utf8/LC_MESSAGES

We have already have chosen to do so by defining the locale directory to be in our working directory “./” in line 6 in the C source code and calling the function “bindtextdomain” in line 13 afterwards.
It’s time to create a MO file (machine object), which is a binary message catalog of a textual translation description, better suitable for an application execution.

$ msgfmt --check --verbose --output-file ./de_DE.utf8/LC_MESSAGES/test_i18n.mo test_german.po

Note here, that the name of the binary output file was given as was defined in line 5, respectively.
Congratulations, that’s it! Before testing it, let’s add support for one more language, for example russian. Doing so, just requires to repeat the steps were described above. Starting with:

$ msginit --no-translator --locale ru_RU --output-file test_russian.po --input test_i18n.pot

And obtainging the resulted translation file:

# Russian translations for test_i18n package.
# Copyright (C) 2012 THE test_i18n'S COPYRIGHT HOLDER
# This file is distributed under the same license as the test_i18n package.
# Automatically generated, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: test_i18n 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-03-01 21:24+0100\n"
"PO-Revision-Date: 2012-03-01 21:24+0100\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

#: test_i18n.c:16
msgid "starting a new test"
msgstr "начинается новый тест"

#: test_i18n.c:17
msgid "testing i18n"
msgstr "тестируется и12я"

Now, finally, it’s time to test everything. To locally simulate the change of locale language one could overwrite the variable “LANG”, as shown below:

$ LANG="de_DE.utf8" ./test-i18n
msg: "Man startet einen neuen Test".
msg: "Teste I16g".

$ LANG="ru_RU.utf8" ./test-i18n
msg: "начинается новый тест".
msg: "тестируется и12я".

What is if something went wrong?! And the displayed strings are not translated. The first thing need to be checked is the list of available locales on our system:

 $ locale -a
C
POSIX
de_DE
de_DE.iso88591
de_DE.iso885915@euro
de_DE.utf8
de_DE@euro
deutsch
...

If you wish to extent the locale list, one possible way would be to modify the “/etc/locale.gen” file and executing “locale-gen” to generate them. More information can be found, here and here. If all was fine, then you could try to figure out if your launched application was not able to locate the translation files, using the “strace” tool:

$ LANG="de_DE.utf8" strace -e trace=open ./test_i18n
open("/etc/ld.so.cache", O_RDONLY)      = 3
open("/lib64/libc.so.6", O_RDONLY)      = 3
open("/usr/lib64/locale/locale-archive", O_RDONLY) = 3
open("/usr/share/locale/locale.alias", O_RDONLY) = 3
open("/home/dev/test-i18n/.//de_DE.utf8/LC_MESSAGES/test_i18n.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/dev/test-i18n/.//de_DE/LC_MESSAGES/test_i18n.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/dev/test-i18n/.//de.utf8/LC_MESSAGES/test_i18n.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/home/dev/test-i18n/.//de/LC_MESSAGES/test_i18n.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
msg: "starting a new test".
msg: "testing i18n".

As was shown above, something was mixed up and the file “test_i18n.mo” could not be located in none of the listed directories. Fixing it will result a fully working example!

$  LANG="de_DE.utf8" strace -e trace=open ./test-i18n
open("/etc/ld.so.cache", O_RDONLY)      = 3
open("/lib64/libc.so.6", O_RDONLY)      = 3
open("/usr/lib64/locale/locale-archive", O_RDONLY) = 3
open("/usr/share/locale/locale.alias", O_RDONLY) = 3
open("/home/dev/test-i18n/.//de_DE.utf8/LC_MESSAGES/test_i18n.mo", O_RDONLY) = 3
open("/usr/lib64/gconv/gconv-modules.cache", O_RDONLY) = 3
msg: "Man startet einen neuen Test".
msg: "Teste I16g".

Mighty Perl-like regular expressions (Regex) with Glib and Vala

A new version of Glib 2.32 has been released just about a week ago. Inspired by this fact, or by another one I started to read the glib documentation, regarding the regular expression syntax and play around with it. To do so the GRegex structure has to be created by calling g_regex_new function, where the first parameter received is the regular expression pattern, followed by compile and match flags. The last parameter is the address of the error pointer, which is created, in the case that, the function fails to interpret the pattern. In the example I want to catch the occurrence of words “moon, soon and noon” summarized by the pattern “(m|n|s)oon” in the given string.

#include <glib.h>
#include <stdlib.h>


typedef void (*HandleFunc)( void );

void 
handle_error( GError **error, HandleFunc func_pointer );

void exit_app( void ) { exit( 1 ); }

int
main( int argc, char **argv )
{
	GError *error = NULL;
	GRegex *regex;
	GMatchInfo *match_info;
	
	gchar *input_string = "soon you will see the moon in the afternoon";
	gchar *pattern_string = "(m|n|s)oon";
	
	regex = g_regex_new( pattern_string, 0, 0, &error );
	
	handle_error( &error, exit_app );
	
	g_regex_match( regex, input_string, 0, &match_info );
	
	g_print( "searching for a match \"%s\" in the string:\n\"%s\"\n\n", pattern_string, input_string );
	
	
	while( g_match_info_matches( match_info ) ) {
		gchar *match = g_match_info_fetch( match_info, 0 );
		
		g_print( "found match: \"%s\"\n", match );
		
		g_match_info_next( match_info, &error );
		
		handle_error( &error, NULL );
	
		g_free( match );
	}
	
	g_match_info_free( match_info );
	g_regex_unref( regex );
	
	return 0;
}

void 
handle_error( GError **error, HandleFunc func_pointer )
{
	if( error != NULL && *error != NULL ) {
		g_print( "%s\n", (*error)->message );
		g_clear_error( error );
		
		if( func_pointer != NULL ) func_pointer( );	
	}
}

The above example can be compiled with the following makefile:

APP = regex-test

${APP}: ${APP}.c
	gcc -o $@ $^ $(shell pkg-config --cflags --libs glib-2.0) -Wall -pedantic
	
clean:
	rm -rf ${APP}

Here is one more example written in Vala, dealing with parentheses issues, containing the balanced number of opening and closing brackets:

void main( ) {
	string exp1_pattern = "(?<exp1>( [^()]* | (?>[^()]*) (?<pn> \\( ( (?>[^()]*) | (?&pn) )* \\) ) [^()]* ))";
	string exp2_pattern = "(?<exp2>( [^()]* | (?>[^()]*) (?<pm> \\( ( (?>[^()]*) | (?&pm) )* \\) ) [^()]* ))";
	
	string pattern = "^" + exp1_pattern + "\\s(?<opn>(and|or|xor))\\s" + exp2_pattern + "$";
	
	string[] text_lines = new string[]
	{ "true and (x)", "a and b", "(ab(cd)e or y", "(a(b)cde) xor ( s )",
	  "(true and x) or (y and (not x ))", "xandy", " and b", 
	  " (x  and y) or ( true or y()) ", "a and b or c" };
	
	Regex regex;
	MatchInfo match_info;
	
	try {
		regex = new Regex( pattern, RegexCompileFlags.EXTENDED );
		foreach( string text in text_lines ) {
			stdout.printf( "\"%s\"\n", text );
			regex.match( text, 0, out match_info );
	
			while( match_info.matches( ) ) {
				stdout.printf( "\t\"%s\"\n", match_info.fetch( 0 ) );
				stdout.printf( "\toperator name: \"%s\"\n", match_info.fetch_named( "opn" ) );
				stdout.printf( "\t     left exp: \"%s\"\n", match_info.fetch_named( "exp1" ) );
				stdout.printf( "\t    right exp: \"%s\"\n", match_info.fetch_named( "exp2" ) );
				match_info.next( );
			}
		} 
	} catch( RegexError re ) {
			stderr.printf( "%s\n", re.message );	
	}	
}

This one can be compiled with:

# valac regex-test.vala

“Hello World” example in Vala using Gtk+3

screenshot of gtk3 based vala example
Today I decided to rewrite a simple code of the “Hello World” example written in python by Micah Carrick almost a year ago. And I decided to do it in Vala! Vala has a modern syntax, compared to C# or java and brings many useful object oriented features. Vala’s compiler named “valac” translates your written code and based on it generates a C output, which it then compiles. I frequently observed how this project emerges, because I was fascinated by this idea from the beginning and soon realized, that I like to write in Vala myself too. Especially as I saw that the quadrapassel’s game code (a tetrix derivate in GNOME) was moved from C++ to Vala. So, here is a code of “hello_world.vala”:

namespace TestingWorld {
	class HelloWorld : Gtk.Application {
		public HelloWorld( ) {
			Object( application_id: "testing.hello.world",
					flags: ApplicationFlags.FLAGS_NONE );
		}
		
		public override void activate( ) {
			var window = new Gtk.Window( );
			window.set_title( "Gtk3 Vala Example" );
			window.set_default_size( 250, -1 );
			window.set_border_width( 24 );
			window.destroy.connect( () => { Gtk.main_quit( ); } );

			var label = new Gtk.Label( "Hello World!\nМиру Мир!" );
			window.add( label );
			window.show_all( );
			this.add_window( window );
		}

		public static void main( string[] args ) {
			var app = new HelloWorld( );
			app.run( );
		}
	}
}

This tiny example can be easily compiled with:

valac hello_world.vala --pkg gtk+-3.0 

Here, the created class “HelloWorld” is inherited from the Gtk.Application, which should replace the libunique functionallity. By providing a “application_id”, all the later launched instances join the same main loop. So, once you destroy it with “Gtk.main_quit”, all running application instances will be terminated. The “Gtk.Application”, additionally, provides many more usefull features, such as communication between running application instances.
If you do not like to write “Gtk.” every time when referring to classes from the GTK+ library, you can insert

 using Gtk;

at the beginning of the file. By doing so, you can omit the need of specifying the work space from where the classes you would like to use comes from. For example, you can then just write for the line number 15 the following:

 var label = new Label( "Hello World!" );

Why can’t I chain up to base constructor?

Deriving a custom class from GObject

This post demonstrates how to create a custom class derived from GObject. In this example it is a class named “Hamster”. Furthermore, it is shown, how to define a private class members, in this case the “name” of the hamster. The way custom properties can be defined is also illustrated.
There is no much explanation yet, so consider it as a work in progress…

source code of the header file mz-hamster.h:

#ifndef __MZ_HAMSTER_H__
#define __MZ_HAMSTER_H__

#include <glib-object.h>

G_BEGIN_DECLS

#define MZ_TYPE_HAMSTER			( mz_hamster_get_type( ) )
#define MZ_HAMSTER( obj )		( G_TYPE_CHECK_INSTANCE_CAST( (obj), MZ_TYPE_HAMSTER, MzHamster ) )
#define MZ_IS_HAMSTER( obj )		( G_TYPE_CHECK_INSTANCE_TYPE( (obj), MZ_TYPE_HAMSTER ) )
#define MZ_HAMSTER_CLASS( klass )	( G_TYPE_CHECK_CLASS_CAST( (klass), MZ_TYPE_HAMSTER, MzHamsterClass ) )
#define MZ_IS_HAMSTER_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE( (klass), MZ_TYPE_HAMSTER ) )
#define MZ_HAMSTER_GET_CLASS( obj )	( G_TYPE_INSTANCE_GET_CLASS( (obj), MZ_TYPE_HAMSTER, MzHamsterClass ) )

typedef struct _MzHamster      MzHamster;
typedef struct _MzHamsterClass MzHamsterClass;

struct _MzHamster
{
  GObject parent;
};

struct _MzHamsterClass
{
  GObjectClass parent_class;
};

GType mz_hamster_get_type( void ) G_GNUC_CONST;

MzHamster * mz_hamster_new( const gchar *name );

gchar * mz_hamster_get_name( MzHamster *hamster );
void mz_hamster_set_name( MzHamster *hamster, const gchar *name );

G_END_DECLS

#endif	/* __MZ_HAMSTER_H__ */

source code of mz-hamster.c:

#include <glib/gprintf.h>
#include "mz-hamster.h"

#define MZ_HAMSTER_GET_PRIVATE( obj )	  ( G_TYPE_INSTANCE_GET_PRIVATE( (obj), MZ_TYPE_HAMSTER, MzHamsterPrivate ) )

G_DEFINE_TYPE( MzHamster, mz_hamster, G_TYPE_OBJECT )

typedef struct _MzHamsterPrivate MzHamsterPrivate;

struct _MzHamsterPrivate
{
  gchar *name;
};

enum
{
  PROP_0,

  PROP_NAME
};

static void mz_hamster_finalize( GObject *hamster );

static void
mz_hamster_set_property( GObject *object,
			 guint prop_id,
			 const GValue *value,
			 GParamSpec *pspec );

static void
mz_hamster_get_property( GObject *object, guint prop_id, GValue *value, GParamSpec *pspec );

static void 
mz_hamster_class_init( MzHamsterClass *klass )
{
  GObjectClass *gobject_class = G_OBJECT_CLASS( klass );

  gobject_class->finalize = mz_hamster_finalize;

  g_type_class_add_private( klass, sizeof( MzHamsterPrivate ) );

  gobject_class->get_property = mz_hamster_get_property;
  gobject_class->set_property = mz_hamster_set_property;

  g_object_class_install_property( gobject_class,
				   PROP_NAME,
				   g_param_spec_string( "name",
							"Name",
							"hamster's name",
							NULL,
							G_PARAM_READWRITE ) );
}

static void
mz_hamster_init( MzHamster *hamster )
{
  MzHamsterPrivate *priv = MZ_HAMSTER_GET_PRIVATE( hamster );

  g_printf( "...instance init" );

  priv->name = g_strdup( "unnamed" );
}
  
static void
mz_hamster_finalize( GObject *object )
{
  MzHamster *hamster = MZ_HAMSTER( object );
  MzHamsterPrivate *priv = MZ_HAMSTER_GET_PRIVATE( hamster );
  GObjectClass *parent_class = G_OBJECT_CLASS( mz_hamster_parent_class );

  g_printf( "...instance finalize\n" );

  g_free( priv->name );

  ( *parent_class->finalize )( object );
}

MzHamster *
mz_hamster_new( const gchar *name )
{
  MzHamster *hamster;

  hamster = MZ_HAMSTER( g_object_new( MZ_TYPE_HAMSTER, NULL ) );

  if( name != NULL )
    mz_hamster_set_name( hamster, name );
  
  return hamster;
}

gchar *
mz_hamster_get_name( MzHamster *hamster )
{
  MzHamsterPrivate *priv;
  
  g_return_val_if_fail( MZ_IS_HAMSTER( hamster ), NULL );

  priv = MZ_HAMSTER_GET_PRIVATE( hamster );

  return g_strdup( priv->name );
}

void
mz_hamster_set_name( MzHamster *hamster, const gchar *name )
{
  MzHamsterPrivate *priv;
  
  g_return_if_fail( name );
  g_return_if_fail( MZ_IS_HAMSTER( hamster ) );

  priv = MZ_HAMSTER_GET_PRIVATE( hamster );

  if( priv->name != NULL )
    g_free( priv->name );

  priv->name = g_strdup( name );
}

static void
mz_hamster_set_property( GObject *object,
			 guint prop_id,
			 const GValue *value,
			 GParamSpec *pspec )
{
  MzHamster *hamster = MZ_HAMSTER( object );

  switch( prop_id ) {
    case PROP_NAME:
      mz_hamster_set_name( hamster, g_value_get_string( value ) );
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
  }
}
      
static void
mz_hamster_get_property( GObject *object,
			 guint prop_id,
			 GValue *value,
			 GParamSpec *pspec )
{
  MzHamster *hamster = MZ_HAMSTER( object );

  switch( prop_id ) {
    case PROP_NAME:
      g_value_set_string( value, mz_hamster_get_name( hamster ) );
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
  }
}

main.c file:

#include <glib-object.h>
#include <glib/gprintf.h>

#include "mz-hamster.h"

int main( void )
{
  MzHamster *hamster;
  gchar *name;
  GValue value = { 0, };	/* GValue instance must contain zeros! */

  g_type_init( );

  hamster = mz_hamster_new( NULL );
  
  name = mz_hamster_get_name( hamster );
  g_printf( "name: %s\n", name );
  g_free( name );

  mz_hamster_set_name( hamster, "хoмяк" );
  name = mz_hamster_get_name( hamster );
  g_printf( "new name: %s\n", name );

  g_free( name );
  g_object_unref( G_OBJECT( hamster ) );
  
  g_printf( "bye!\n" );

  g_printf( "...checking properties...\n" );
  hamster = mz_hamster_new ( "karry" );
  
  g_value_init( &value, G_TYPE_STRING );
  g_value_set_string( &value, "papa" );
  g_object_set_property( G_OBJECT( hamster ), "name", &value );
  name = mz_hamster_get_name( hamster );
  g_printf( "new name: %s\n", name ); 
  
  mz_hamster_set_name( hamster, "mama" );
  g_object_get_property( G_OBJECT( hamster ), "name", &value );
  name = g_value_dup_string( &value );
  g_printf( "another hamster named: %s\n", name );
  
  return 0;
}

makefile:

SHELL=/bin/bash

deps=$(shell pkg-config --libs --cflags gobject-2.0 )
flags=-Wall -pedantic

hamster: main.c mzhamster.o
	gcc -o $@ $^ ${deps} ${flags}

%.o: %.c %.h
	gcc -o $@ -c $< ${deps} ${flags}

clean:
	rm -rf *.o hamster

output from the shell:

$ ./hamster 
...instance init
name: unnamed
new name: хoмяк
...instance finalize
bye!
...checking properties...
...instance init
new name: papa
another hamster named: mama

In the object oriented language like Vala this example looks rather trivial (property.vala):

namespace Mz {
	public class Hamster : Object {
		// Definition of a property with a standard get and set methods
		public string name { get; set; }
		
		public Hamster( string name = "unnamed" ) {
			stdout.printf( "...instance init\n" );
			Object( name: name );
		}
		
		// Destructor
		~Hamster( ) {
			stdout.printf( "...instance named %s is finalized\n", this.name );
		}
		
		public static void main( string[] args ) {
			var hamster = new Hamster( );
			
			stdout.printf( "name: %s\n", hamster.name );
			
			hamster.name = "хoмяк";
			stdout.printf( "new name: %s\n", hamster.name );
			
			hamster = new Hamster( "karry" );
			stdout.printf( "bye\n" );
			
			stdout.printf( "...checking properties...\n" );
			Value svalue = "papa";
			hamster.set_property( "name", svalue );
			stdout.printf( "new name: %s\n", hamster.name );
			
			hamster.set( "name", "mama" );
			string name;
			hamster.get( "name", out name );
			stdout.printf( "another hamster named: %s\n", name );
		}
	}
}

This one can be easiliar compiled with:

valac-0.14 property.vala

Vala compiler is also able to generate the corresponding C code by invoiking the command:

 valac-0.14 property.vala --ccode

By doing so the file “property.c” will be created containing a similiar C code, introduced above. There are more detailed examples how properties can be defined in Vala, shown here. Line 28 shows, that Vala has a build-in auto-(un)boxing support for Glib’s Value structure, which saves you from writing the following lines:

// to initialize structures no "new" keyword is needed 
Value svalue = Value( typeof( string ) );
svalue.set_string( "papa" );

Further examples of using GLib.Value structure can be found here.

By comparing the amount of code needed to create a custom class written in C with the code written in a object-oriented language like python, C++ or Vala very often the question arises: “What is the benefit of writing so many complicated at the first look and unnecessary lines of code in C to create a class, if in another language it is almost a trivial task?”

If one knows the background hiding behind this decision to still write in C, it’s very easy to understand this situation. First of all, C is a very tiny programming language without any modern language features. It’s available almost on every device, and if not, it can be rather easily integrated than other heavier languages. Additionally, big part of gnu/linux based operating systems are written in C, including a rich collections of libraries, which can be integrated in the new C based projects. GObject, on the other side, is the one of the possible ways bringing the object-oriented capabilities to the C programming language, which allows the use of the modern design. The model used in GObject should in first place simplify the construction and intregration of binding to another languages, so the libraries on top of it, e.g. Gtk+, can be easily used to create window based applications.