Vala – the new programming language for Gnome
This Friday when I read the last issue (in Sweden) of Linux Format there was an article on a new programming language named Vala. The goal for Vala is to provide a modern programming language for, primarily, developing Gnome applications. There is of course Mono, but Vala doesn’t run in a virtual machine but is complied to machine code. But Vala resembles C# syntactically and has borrowed a lot of concepts from C#.
From what I understand Vala code is first translated into plain old C code, and then compiled with the ordinary GCC compiler. The benefit is that you don’t have to get head aches about memory management and so forth.
Vala seems pretty interesting and I downloaded it and compiled it without any difficulties. There are precompiled packages for most Linux distros – it’s available in the Ubuntu repository – but since Vala is new and still under development the distro packages is far behind in version.
There’s also a Vala IDE and plugins for GEdit, Anjuta and Eclipse.
Anyway, just to try Vala out I made a little program – using Val(a)ide – that changes the desktop wallpaper on a per interval basis. Send the program a path to a directory with images and the background will change among those images every *nth minutes.
This program needs libgee which at the moment needs to be added manually.
Compile: valac --pkg gconf-2.0 --pkg gee-1.0 --pkg gio-2.0 main.vala -o wallpaper-iterator
- /* main.vala
- *
- * Copyright (C) 2009 Pontus Östlund <spam@poppa.se>
- *
- * No license what so ever. Do what ever you like...
- *
- * Author:
- * Pontus Östlund <spam@poppa.se>
- */
- // GLib isn't really neccessary since it's imported automatically
- using GLib, Gee, GConf;
- /**
- * User defined exception types
- */
- errordomain IOError {
- FILE_NOT_FOUND,
- NOT_A_DIRECTORY
- }
- /**
- * Main class
- */
- public class Main
- {
- /**
- * Used as reference in option parser
- */
- static int arg_delay;
- /**
- * Application command line options
- */
- const OptionEntry[] options = {
- { "delay", 'd', 0, OptionArg.INT, ref arg_delay,
- "Number of minutes to wait before swapping background", null },
- { null }
- };
- /**
- * Main method
- *
- * @param args
- * Command line arguments
- */
- public static int main (string[] args)
- {
- try {
- var opt = new OptionContext("\"/path/to/wallpapers\"");
- opt.set_help_enabled(true);
- opt.add_main_entries(options, null);
- opt.parse(ref args);
- }
- catch (GLib.Error e) {
- stderr.printf("Error: %s\n", e.message);
- stderr.printf("Run '%s --help' to see a full list of available "+
- "options\n", args[0]);
- return 1;
- }
- if (args.length < 2) {
- stderr.printf("Missing argument!\n");
- stderr.printf("Run '%s --help' for usage\n", args[0]);
- return 1;
- }
- // Default time before changing background is 30 minutes
- int delay = arg_delay > 0 ? arg_delay*60 : 60*30;
- try {
- WallpaperIterator bg = new WallpaperIterator(args[1], delay);
- bg.run();
- bg.stop();
- }
- catch (IOError e) {
- stderr.printf("Error: %s\n", e.message);
- return 1;
- }
- finally {
- stderr.printf("Finally block reached!\n");
- }
- return 0;
- }
- }
- /**
- * Class that handles changeing of desktop wallpapers on a per interval way
- */
- public class WallpaperIterator : GLib.Object
- {
- /**
- * Number of seconds to wait before changeing wallpaper
- */
- private int delay = 0;
- /**
- * Current index in the images list
- */
- private int index = 0;
- /**
- * List of images to change between
- */
- private ArrayList<string> files = new ArrayList<string>();
- /**
- * List of allowed content types
- */
- private ArrayList<string> allow = new ArrayList<string>();
- /**
- * GConf client object
- */
- private GConf.Client gclient = null;
- /**
- * GConf registry where the background image is set
- */
- private string gconf_key = "/desktop/gnome/background/picture_filename";
- /**
- * Background being used when the application is started
- */
- private string default_bg = null;
- /**
- * Constructor
- *
- * @param dir
- * The directory to collect wallpapers in
- * @param delay
- * Time to wait - in seconds - before swapping wallpaper
- */
- public WallpaperIterator(string dir, int delay)
- throws IOError
- {
- assert(delay > 0);
- allow.add("image/jpeg");
- allow.add("image/png");
- var f = File.new_for_path(dir);
- if (!f.query_exists(null))
- throw new IOError.FILE_NOT_FOUND(" \"%s\" doesn't exits!".printf(dir));
- if (f.query_file_type(0, null) != FileType.DIRECTORY) {
- throw new IOError.NOT_A_DIRECTORY(" \"%s\" is not a directory!"
- .printf(dir));
- }
- collect(f.get_path());
- if (files.size < 2) {
- warning("Not enough images found for this application to be useful!\n");
- return;
- }
- this.delay = delay;
- }
- /**
- * Run the application. Starts a MainLoop
- */
- public void run()
- {
- gclient = GConf.Client.get_default();
- default_bg = gclient.get_string(gconf_key);
- MainLoop loop = new MainLoop(null, false);
- var time = new TimeoutSource(delay*1000);
- time.set_callback(() => { swap(); });
- time.attach(loop.get_context());
- loop.run();
- }
- /**
- * Stop the application. Tries to reset the background
- */
- public void stop()
- {
- try {
- if (default_bg != null)
- gclient.set_string(gconf_key, default_bg);
- }
- catch (GLib.Error e) {
- warning("Failed to restore background!\n");
- }
- }
- /**
- * Does the actual background swapping
- */
- private void swap()
- {
- if (index >= files.size) {
- debug("Restart...\n");
- index = 0;
- }
- debug("Callback...%-2d (%s)\n", index, files[index]);
- try {
- gclient.set_string(gconf_key, files[index]);
- }
- catch (GLib.Error e) {
- warning("Failed to set background: %s\n", e.message);
- }
- index++;
- }
- /**
- * Collect images
- *
- * @param path
- */
- private void collect(string path)
- {
- try {
- var dir = File.new_for_path(path).enumerate_children(
- "standard::name,standard::type,standard::content-type",
- 0, null
- );
- FileInfo fi;
- string fp;
- while ((fi = dir.next_file(null)) != null) {
- fp = path + "/" + fi.get_name();
- if (fi.get_file_type() == FileType.DIRECTORY)
- collect(fp);
- else {
- if (fi.get_content_type() in allow)
- files.add(fp);
- else
- warning("Skipping \"%s\" due to unallowed content type\n", fp);
- }
- }
- }
- catch (GLib.Error e) {
- warning("Error: %s\n", e.message);
- }
- }
- }
I think Vala looks promising and I will try it out trying to write a more complex application when I find the time.


