Posts tagged ‘Vala’

Roxen Application Launcher 1.2.1

Roxen Application Launcher 1.2.1

There’s a new release of Roxen Application Launcher (come again?) for Linux.

Although the previous release, using GTK3, came quite recently this release has some new things.

GSettings

I dumped the “keyfile” solution for the application settings in favour to GSettings. So the settings is no longer stored in a file in the application directory but rather in the system’s application settings backend. GSettings is part of GIO – the GNOME networking library – and since RAL depends on GIO no new dependency is needed. The upside is that I could put a file of source code in the bin! Plus, it’s fun learning new stuff!

Editors and content types

Previously I have kept an editor – name and command line – for every content type. Anders at Roxen thought it’d be better if editors and content types were separated. I’ve thought about that before but never bothered to do anything about it.

But now, along with GTK3, there’s a new (I think) AppInfo class and the new AppChooserButton and AppChooserDialog widgets so I thought it’d be cool to use those. So selecting an editor for a new content type is way more simple now, and it also looks nicer. Plus we get the icon for the editor in the content type list under the “Applications” tab ;)

Simple logging

I also implemented some simple logging which can be viewed under the new “Logging” tab. This will be worked upon and at the moment not very useful information is written to the log, but at least it’s a start.

Default icons

The icons in the notification popup – which only are three to the number – is now fetched from the user’s default icon theme. They we’re bundled before.

SOUP all the way

Previously I have used a little hack for saving downloaded files to disk. The problem was that the Vapi bindings for libsoup casted the data to a string which totally scrambled binary content like images and such. My solution was to write a simple C-function which took a SoupMessageBody struct as argument and then wrote that to diskt always keeping the uint8[] type of the content.

I bug reported this way back and it’s now fixed in Vala so I dumped my solution and am now using Vala all the way. Gone is one C and one Vapi file.

While at it I changed from using blocking functions in libsoup to the async ones. You never really noticed blocking calls was used before, but right is right. Right?

And that’s that for this time I think!

Roxen Application Launcher 1.2.1

Sources is available at the Roxen Application Launcher Github repository

GTK TreeViewColumn with icon and text

TreeViewColumn with icon and text

The other day I wanted to put both an icon and text in the same GTK+ TreeViewColumn, and I had absolutely no idea how to do that. So I Google’d and Google’d but had trouble finding any examples. I even downloaded the source code of the Gnome System Monitor – where exactly what I wanted exist – but that was mostly written in C++ which I know very little of.

But I’m stubborn, and after a while I found and example in Python which I managed to interpret. Even though I know very little Python it’s not that hard to follow, and the example was short.

In short what’s needed is packing two CellRenderers in the same TreeViewColumn. Quite logical when you know about it. The example below is in Vala:

15 lines of Vala
  1. var tree_view = new TreeView ();
  2. var col = new TreeViewColumn ();
  3. col.title = title;
  4. col.resizable = true;
  5. var crp = new CellRendererPixbuf ();
  6. col.pack_start (crp, false);
  7. col.add_attribute (crp, "pixbuf", 0);
  8. var crt = new CellRendererText ();
  9. col.pack_start (crt, false);
  10. col.add_attribute (crt, "text", 1);
  11. tree_view.insert_column (col, -1);

I hacked up a simple application that shows all installed programs – that has a .desktop entry I guess – in a list (the screenshot above). The sources is available at my Github repository.

Happy coding!

Roxen Application Launcher 1.1

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

Screenshot of Roxen Application Launcher

There’s a new release of Roxen Application Launcher (come again?) for Linux.

I have updated the application launcher to use GTK3 so that it builds on Ubuntu 11.10 and any other Linux distribution using GTK3. This also made it possible to drop the dependency for libunique since Gtk.Application can handle single instance applications.

I also fixed a bug which made it impossible to use the appliction launcher on sites not running on port 80 or 443.

So there’s no new features in this release.

Roxen Application Launcher 1.1

Sources is available at the Roxen Application Launcher Github repository

Roxen Application Launcher 1.0.10

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

There’s a new release of Roxen Application Launcher (come again?) for Linux.

No big news, but the GTK+ tree view of files is now sortable. The “minimize to tray” function is now actually invoked when the window is minimized rather than closed. A right click in the file list now also let you go the the file’s directory in the Sitebuilder.

Also fixed a bug where the locales didn’t get installed correctly and also fixed a bug which scrambled the configuration file a bit.

Roxen Application Launcher 1.0.10

Sources is available at the Roxen Application Launcher Github repository

Variable length argument segfaults valac

Hm, found a bug in valac (the Vala compiler) today. If an abstract or virtual method contains a variable length argument (va_list) valac will segmentation fault.

19 lines of Vala
  1. // valac -o test sample.vala
  2. int main(string[] args)
  3. {
  4. return 0;
  5. }
  6. public abstract class Base : Object
  7. {
  8. public abstract int query(string query, ... );
  9. }
  10. public class Child : Base
  11. {
  12. public override int query(string query, ... )
  13. {
  14. return 1;
  15. }
  16. }

I’ve filed a bug about it so we’ll see what the problem is and if it can be fixed rapidly.

Roxen Application Launcher 1.0.3

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

Screenshot of Roxen Application Launcher

In this release of Roxen Application Launcher (come again?) for Linux I’ve gotten rid of a few dependencies, namely: gconf, libgee and libgnome. The reason I dumped gconf and libgnome was to make it easier to install in KDE. I’ve verified it installs in KDE, although I noticed the translation doesn’t work and the Roxen SVG logo doesn’t show up in the window top border.

Screenshot of Roxen Application Launcher
Roxen Application Launcher in KDE

Libgee is a collections API written in Vala and since I used a newer version than what is available in most package managers, and I’m not sure all Linux distros provide libgee, I decided to dump it and implement the same functionality with the generic collection classes in Vala. And since the collections used in RAL is quite simple that worked out just fine.

I have also tried to implement bundled download, which is only used in Roxen Editorial Portal. Since I don’t have access to such an installation I haven’t been able to verify it works as expected. I re-implemented the same behavior as in the launcher written in Pike by the Roxen guys.

Oh, and if you already have an installation of my RAL your previously downloaded files and settings will not be available to the new install. Since I dumped gconf I now store the settings in a plain text file and I have put the RAL application directory in ~/.conf/roxenlauncher since ~/.conf is where you should put application specific data according to freedesktop.org. In previous versions of RAL I stored application data in ~/.roxenlauncher so if you want your previously downloaded files copy ~/.roxenlauncher/files to ~/.conf/roxenlauncher/files.

The sources is available at Github.

Roxen Appliction Launcher 1.0.3 00:43, Fri 24 September 2010 :: 384.8 kB

Roxen Application Launcher 1.0

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

Screenshot of Roxen Application Launcher with context menu

So I had a go at the Roxen Application Launcher (come again?) for Linux. I added a context menu – when you right click – to the file list. When you right click a file in the list you get the option to view that file in the Sitebuilder, edit it or remove it.

Other than that there’s nothing new. And since the application seems to be very stable I decided to bump the version number to 1.0.

The sources is available at Github.

Roxen Appliction Launcher 1.0 00:06, Sun 12 September 2010 :: 376.2 kB

Roxen Application Launcher 0.4.5

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

Screenshot of Roxen Application Launcher

Okey, here comes an update of my Roxen Application Launcher (come again?) for Linux.

There’s no major changes to this release. The connection to the Roxen server is now stored in a shared object so that it can use a “keep-alive” connection. Not that I think it matters a great deal.

There’s now an option to change the behavior of the applications window close button so that it hides the application to the tray – or notification area as it’s called in Gnome – rather than closes the application.

More Vala programming to the people – Sources at Github.

Roxen Appliction Launcher 0.4.5 23:00, Tue 13 April 2010 :: 375.9 kB

Roxen Application Launcher 0.4.4

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

So, here’s a new release of the Roxen Application Launcher for Linux (RAL). The previous versions used my home made (sloppy so) HTTP client which didn’t handle redirects or secure connections – thank you tec for the feed back – since I had some major problems getting libsoup working with binary files like images and such. Binary files was heavily scrambled when read from or written to disk so I made my own simple HTTP client that kept the data as a byte array to prevent some underlying libraries (GLib) from fiddling with it.

But I solved the libsoup issue so now the RAL handles redirects and secure connections. This is how I solved it:

The libsoup issue

When uploading a file back to the Roxen server I use IOChannel (g_io_channel in plain C) instead of Gio. So the upload works like this:

13 lines of Vala
  1. var sess = new Soup.SessionSync();
  2. var mess = new Soup.Message("PUT", get_uri());
  3. mess.request_headers.append("Cookie", get_cookie());
  4. mess.request_headers.append("Translate", "f");
  5. IOChannel ch = new IOChannel.file(local_file, "r");
  6. ch.set_encoding(null); // Enables reading of binary data
  7. string data;
  8. size_t len;
  9. ch.read_to_end(out data, out len);
  10. mess.request_body.append(Soup.MemoryUse.COPY, data, len);
  11. sess.send_message(mess);

And that seems to work like a charm!

When downloading data it’s a bit more tricky! Of course I tried using IOChannel in this case also but that made no difference. Downloaded images ended up 4 bytes long! But then I thought: You can make your own C bindings in Vala (remember the Vala compiler generates C code) through what is called Vapi files. So what I did was writing a C function that takes a SoupMessageBody object/struct passed from Vala and writes the data part to a file given as argument.

19 lines of C/C++
  1. gboolean save_soup_data(SoupMessageBody *data, const char *file)
  2. {
  3. FILE *fh;
  4. if ((fh = fopen(file, "w")) == NULL) {
  5. fprintf(stderr, "Unable to open file \"%s\" for writing!\n", file);
  6. return FALSE;
  7. }
  8. int wrote = fwrite(data->data, 1, data->length, fh);
  9. if (wrote != (int)data->length) {
  10. fprintf(stderr, "wrote (%d) != data->length (%d). Data may have been "
  11. "truncated", wrote, (int)data->length);
  12. }
  13. fclose(fh);
  14. return TRUE;
  15. }

And this was then made available to Vala by the following Vapi file:

6 lines of Vala
  1. [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "")]
  2. namespace Soppa // Soppa is Swedish for Soup ;)
  3. {
  4. [CCode (cname = "save_soup_data")]
  5. public bool save_soup_data(Soup.MessageBody data, string file);
  6. }

And this is how the actual Vala code downloading the files looks like:

15 lines of Vala
  1. var sess = new Soup.SessionSync();
  2. var mess = new Soup.Message("GET", get_uri());
  3. mess.request_headers.append("Cookie", get_cookie());
  4. mess.request_headers.append("Translate", "f");
  5. sess.send_message(mess);
  6. if (mess.status_code == Soup.KnownStatusCode.OK) {
  7. // Here I call the C function made available through the Vapi file
  8. if (Soppa.save_soup_data(mess.response_body, local_file)) {
  9. message("The file was downloaded and written to disk OK");
  10. }
  11. else {
  12. message("Failed writing data to disk!");
  13. }
  14. }

So that’s that on that! ;)

The notification

I also – just for fun – implemented a notification mechanism through libnotify. Since I believe that can be rather annoying it’s not activated by default but can easily be activated by a checkbox in the user interface.

The packages

The Roxen Application Launcher for Linux can be downloaded at the download page at Github where also the work in progress sources is available or downloaded below!

Roxen Application Launcher 0.4.4 23:06, Wed 13 January 2010 :: 373.5 kB

Stay black!

Bitlyfier – A Bit.ly client for GNOME

Bitlyfier For those of us tweeting – or sharing web addresses in general – these long addresses with extensive query strings you wan’t to share isn’t too user friendly. So we have Bit.ly, among others, that lets you shorten a URL – or give it an alias if you like – and also gives you statistics on how many clicks it has and if it’s shared on Twitter and what not.

Since I’m on the quest of learning the programming language Vala I though why not making a Bit.ly desktop client for GNOME. So I did!

The desktop client

There’s really nothing extraordinary about it, in fact it’s quite simple. Put a long URL in the input field and hit “OK”. You’ll get the shortened URL back in the same input field.

NOTE! The screenshots is showing the Swedish translation but the interface is orginally in English.

Shortening a long URL
Shortening an URL with Bitlyfier

The shortened URL
The Bit.ly shortened URL

To use the application you will of course need a Bit.ly account. The first time Bitlyfier is launched it will ask for your Bit.ly account settings. Just fill in your username and API key (it’s found on your account page at http://bit.ly/account).

Bitlyfier account settings
The bitlyfier settings dialog

The command line interface

For the hacker you, Bitlyfier can also be used as a command line tool. These are the options:

11 lines of Plain text
  1. Usage:
  2. bitlyfier [OPTION...] - Bitlyfier, URL shortener/expander
  3. Help Options:
  4. -h, --help Show help options
  5. Application Options:
  6. -e, --expand Expands the given URL
  7. -s, --shorten Shortens the given URL
  8. -n, --no-gui Sets the application in command line mode
  9. -g, --gconf Invokes setting username and apikey

NOTE! You should quote the value of the ‘-s’ flag. If the URL to be shortened
contains a querystring with ampersands the URL will be truncated if it’s not
quoted.

So to shorten a long URL do like:

  user@machine:~$ bitlyfier -n -s "http://domain.com/long/url/to/shorten"

The Vala Bitly API classes

The Bitly API class I’ve written can of course be used standalone (it’s located in src/bitly.vala in the sources package downloadable below). Here’s an example of usage:

14 lines of Vala
  1. // main.vala
  2. // Compile: valac --pkg gee-1.0 --pkg json-glib-1.0 --pkg libsoup-2.4 -o main
  3. int main(string[] argv)
  4. {
  5. Bitly.Api api = new Bitly.Api("username", "R_the_api_key");
  6. Bitly.Response response = api.shorten("http://domain.com/the/long/url");
  7. stdout.printf("Short URL: %s\n", response.get_string("shortUrl"));
  8. response = api.stats("A2ma2z");
  9. stdout.printf("Clicks: %d\n", response.get_integer("clicks"));
  10. return 0;
  11. }

More about the Bit.ly API and what the API methods do can be read about at http://bit.ly/6HIqjS.

The sources

The development sources of this application is available at Bitlyfier at Github. The current stable release can be found at the Download page.

JavaScript URI class

The other day I needed an URI class for JavaScript. I was doing some stuff where I needed to alter certain parts of an URI. I bet there’s a couple of URI classes for JavaScript out there but I can be a bit nit-picky about code and how it’s written ;)

Anyway, I had a URI parser regexp lying which I wrote for a Vala class (before I found the Soup.URI class) and I thought that since that’s reusable I could hack up a JavaScript URI class myself. So I did!

Here’s some examples of usage:

5 lines of JavaScript
  1. var uri = new URI("http://poppa.se/blog/javascript-uri-class/");
  2. console.log(uri.scheme); //-> http
  3. console.log(uri.host); //-> poppa.se
  4. console.log(uri.path); //-> /blog/javascript-uri-class/
  5. console.log(uri.port); //-> 80

Now, if we want to alter the host so that it contains www we do:

2 lines of JavaScript
  1. uri.host = "www.poppa.se";
  2. console.log(uri.toString()); //-> http://www.poppa.se/blog/javascript-uri-class/

It’s also easy to alter query string variables:

4 lines of JavaScript
  1. var uri = new URI("http://host.com/?name=poppa&lang=se");
  2. uri.variables["name"] = 'Günther';
  3. uri.variables["lang"] = 'de';
  4. console.log(uri.toString()); //-> http://host.com/?name=Günther&lang=de

And I think that’s pretty smooth :)

Download the URI class

New Roxen Application Launcher for Linux written in Vala

This is not the latest version of Roxen Application Launcher. You'll find the latest version at the download page.

A couple of weeks ago I stumbled upon a fairly new programming language named Vala. I thought it looked promising and since Vala is developed by the GNOME project – with the purpose of making software development for, primarily, GNOME easier – and I’m an avid GNOME user I wanted to look deeper into the world of Vala.

I, and most programmers I believe, work in that way that I need a real and useful project when learning a new programming language. So I thought why not re-writing the Roxen Application Launcher I wrote in C#/Mono a couple of years ago in Vala – which by the way is syntactically very, very similar to C# and Java. I’d gotten tired of always having to fiddle with the C# code with every new version of Mono since something always broke when Mono was updated so a re-write wasn’t going to be totally pointless. The good thing about Vala is that the Vala compiler generates C code and that’s what you compile the program from. Fast code and hopefully more mature and stable libraries that won’t break backwards compatibility with every new release.

What about Vala

So, on I went about it and I think that Vala is a really promising language. It’s still a very young language so some library bindings isn’t behaving exactly as expected and the documentation isn’t directly redundant – although the Vala reference documentation site isn’t half bad. But since Vala pretty much is a wrapper for, or binding to, the underlying C libraries you can find answers to your questions that way. All in all I think Vala has a promising future: Way more simple than C and almost as fast and light on memory (remember the Vala compiler generates C code) and way faster than C#/Mono and free from any Microsoft associations ;) .

What about the Roxen Application Launcher

In this new version I utilize GConf for storing application settings. I also made use of – for the first time – the GNU Build Tools for compilation which also makes it easier to distribute and for others to compile from the sources. This also means that the distributed version compiles from the C sources and not the Vala sources so there’s no need for the Vala compiler to build the program.

Other than that there’s nothing fancy about it. The Vala sources is available at my Github repository.

Roxen Appliction Launcher 0.4.2 19:38, Sun 20 December 2009 :: 374 kB

Screenshots

The screenshots is showing the Swedish translation.

List of downloaded files
Screenshot 1 of the Roxen Application Launcher

Adding support for new file type
Screenshot 2 of the Roxen Application Launcher

The GNOME status icon
Screenshot 3 of the Roxen Application Launcher

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

239 lines of Vala
  1. /* main.vala
  2. *
  3. * Copyright (C) 2009 Pontus Östlund <spam@poppa.se>
  4. *
  5. * No license what so ever. Do what ever you like...
  6. *
  7. * Author:
  8. * Pontus Östlund <spam@poppa.se>
  9. */
  10. // GLib isn't really neccessary since it's imported automatically
  11. using GLib, Gee, GConf;
  12. /**
  13. * User defined exception types
  14. */
  15. errordomain IOError {
  16. FILE_NOT_FOUND,
  17. NOT_A_DIRECTORY
  18. }
  19. /**
  20. * Main class
  21. */
  22. public class Main
  23. {
  24. /**
  25. * Used as reference in option parser
  26. */
  27. static int arg_delay;
  28. /**
  29. * Application command line options
  30. */
  31. const OptionEntry[] options = {
  32. { "delay", 'd', 0, OptionArg.INT, ref arg_delay,
  33. "Number of minutes to wait before swapping background", null },
  34. { null }
  35. };
  36. /**
  37. * Main method
  38. *
  39. * @param args
  40. * Command line arguments
  41. */
  42. public static int main (string[] args)
  43. {
  44. try {
  45. var opt = new OptionContext("\"/path/to/wallpapers\"");
  46. opt.set_help_enabled(true);
  47. opt.add_main_entries(options, null);
  48. opt.parse(ref args);
  49. }
  50. catch (GLib.Error e) {
  51. stderr.printf("Error: %s\n", e.message);
  52. stderr.printf("Run '%s --help' to see a full list of available "+
  53. "options\n", args[0]);
  54. return 1;
  55. }
  56. if (args.length < 2) {
  57. stderr.printf("Missing argument!\n");
  58. stderr.printf("Run '%s --help' for usage\n", args[0]);
  59. return 1;
  60. }
  61. // Default time before changing background is 30 minutes
  62. int delay = arg_delay > 0 ? arg_delay*60 : 60*30;
  63. try {
  64. WallpaperIterator bg = new WallpaperIterator(args[1], delay);
  65. bg.run();
  66. bg.stop();
  67. }
  68. catch (IOError e) {
  69. stderr.printf("Error: %s\n", e.message);
  70. return 1;
  71. }
  72. finally {
  73. stderr.printf("Finally block reached!\n");
  74. }
  75. return 0;
  76. }
  77. }
  78. /**
  79. * Class that handles changeing of desktop wallpapers on a per interval way
  80. */
  81. public class WallpaperIterator : GLib.Object
  82. {
  83. /**
  84. * Number of seconds to wait before changeing wallpaper
  85. */
  86. private int delay = 0;
  87. /**
  88. * Current index in the images list
  89. */
  90. private int index = 0;
  91. /**
  92. * List of images to change between
  93. */
  94. private ArrayList<string> files = new ArrayList<string>();
  95. /**
  96. * List of allowed content types
  97. */
  98. private ArrayList<string> allow = new ArrayList<string>();
  99. /**
  100. * GConf client object
  101. */
  102. private GConf.Client gclient = null;
  103. /**
  104. * GConf registry where the background image is set
  105. */
  106. private string gconf_key = "/desktop/gnome/background/picture_filename";
  107. /**
  108. * Background being used when the application is started
  109. */
  110. private string default_bg = null;
  111. /**
  112. * Constructor
  113. *
  114. * @param dir
  115. * The directory to collect wallpapers in
  116. * @param delay
  117. * Time to wait - in seconds - before swapping wallpaper
  118. */
  119. public WallpaperIterator(string dir, int delay)
  120. throws IOError
  121. {
  122. assert(delay > 0);
  123. allow.add("image/jpeg");
  124. allow.add("image/png");
  125. var f = File.new_for_path(dir);
  126. if (!f.query_exists(null))
  127. throw new IOError.FILE_NOT_FOUND(" \"%s\" doesn't exits!".printf(dir));
  128. if (f.query_file_type(0, null) != FileType.DIRECTORY) {
  129. throw new IOError.NOT_A_DIRECTORY(" \"%s\" is not a directory!"
  130. .printf(dir));
  131. }
  132. collect(f.get_path());
  133. if (files.size < 2) {
  134. warning("Not enough images found for this application to be useful!\n");
  135. return;
  136. }
  137. this.delay = delay;
  138. }
  139. /**
  140. * Run the application. Starts a MainLoop
  141. */
  142. public void run()
  143. {
  144. gclient = GConf.Client.get_default();
  145. default_bg = gclient.get_string(gconf_key);
  146. MainLoop loop = new MainLoop(null, false);
  147. var time = new TimeoutSource(delay*1000);
  148. time.set_callback(() => { swap(); });
  149. time.attach(loop.get_context());
  150. loop.run();
  151. }
  152. /**
  153. * Stop the application. Tries to reset the background
  154. */
  155. public void stop()
  156. {
  157. try {
  158. if (default_bg != null)
  159. gclient.set_string(gconf_key, default_bg);
  160. }
  161. catch (GLib.Error e) {
  162. warning("Failed to restore background!\n");
  163. }
  164. }
  165. /**
  166. * Does the actual background swapping
  167. */
  168. private void swap()
  169. {
  170. if (index >= files.size) {
  171. debug("Restart...\n");
  172. index = 0;
  173. }
  174. debug("Callback...%-2d (%s)\n", index, files[index]);
  175. try {
  176. gclient.set_string(gconf_key, files[index]);
  177. }
  178. catch (GLib.Error e) {
  179. warning("Failed to set background: %s\n", e.message);
  180. }
  181. index++;
  182. }
  183. /**
  184. * Collect images
  185. *
  186. * @param path
  187. */
  188. private void collect(string path)
  189. {
  190. try {
  191. var dir = File.new_for_path(path).enumerate_children(
  192. "standard::name,standard::type,standard::content-type",
  193. 0, null
  194. );
  195. FileInfo fi;
  196. string fp;
  197. while ((fi = dir.next_file(null)) != null) {
  198. fp = path + "/" + fi.get_name();
  199. if (fi.get_file_type() == FileType.DIRECTORY)
  200. collect(fp);
  201. else {
  202. if (fi.get_content_type() in allow)
  203. files.add(fp);
  204. else
  205. warning("Skipping \"%s\" due to unallowed content type\n", fp);
  206. }
  207. }
  208. }
  209. catch (GLib.Error e) {
  210. warning("Error: %s\n", e.message);
  211. }
  212. }
  213. }

I think Vala looks promising and I will try it out trying to write a more complex application when I find the time.