Well it’s been nearly a month since I first wrote about project freedom (as in financial) and I thought it might be time give a brief update on where I’m at. Given that we’ve just had Christmas and I’m currently on holidays progress hasn’t been all that dazzling. That said, I’m still pretty happy with what has been done all things considered. So what have I been doing? Well so far I’ve mainly been looking at different approaches to building the application.

The Java Way

Naturally I immediately jumped to looking at a Java based solution – after all it is what I’d call my “home” language. Anyone who’s been around a while and has had the opportunity to program in Java as well as a variety of other programming languages/paradigms would undoubtedly agree that it is a beautiful language. I for one really appreciate the consistency of the syntax, the uncompromising enforcement of the OOP paradigm, and most of all the rich standard library with its accompanying documentation.

Being that I work with this stuff quite a bit my head was filled with all sorts of ideas about how we could achieve our goals using Java as the weapon of choice. The first thing that came to mind was that I could utilize the Eclipse RCP and JFace to get some quick wins getting a basic application framework up and running. This approach has the following distinct advantages:

  1. Eclipse RCP contains an OSGi container built in (Equinox to be exact) which is a very powerful plugin framework in a manner of speaking. Potentially it means that each discrete piece of functionality can be build as a separate plugin (or bundle in OSGi-speak).
  2. SWT/JFace contain a rich component set which would do about 95% of what I require and look/behave just like native components on Mac, Windows and Linux.
  3. RCP comes with a tool that allows to generate an executable and budle a JRE with the application so you can avoid “but my system doesn’t have Java (or version required) installed” type support headaches. It just runs.
  4. It’ll run on Mac, Windows, and Linux with no issues whatsoever.

So why wouldn’t I take that approach?

  1. Personally I’ve found RCP very hard to come to grips with. Documentation is scarce and outdated from what I can determine.
  2. OSGi adds a large amount of overhead in terms of complexity. Now I’m not exactly the smartest guy going round, but I’m not a moron either. I’ve spent hours frigging around with manifests, configurations, interfaces, dodgy docos and classpath hassles getting very little done. It all feels like a tremendous waste of time at this stage.
  3. Need to learn and ORM mapping tool like Hibernate or similar to overcome the OO to Relational mapping mismatch. I’m predominantly a user interface specialist so I usually leave this kinda stuff to someone else. Alternatively I can just battle on through with JDBC (*shudder).

As far as abstractions go Donald Knuth is reputed to have once said:

“There is no complexity problem in programming that cannot be eased by adding a layer of indirection. And there is no performance problem in programming that cannot be eased by removing a layer of indirection.”

Ordinarily I’d agree with this statement. You only have to look as far as something like an ORM to see this principle at work. What could be simpler than just working with your domain objects and letting something else worry about the whole persistence issue? On the contrary though I’m inclined to say that the sheer number of abstractions present in the aforementioned solution actually add to its complexity – not reduce it as promised. As always in Java I seem to be forced to spend a lot of time thinking about the correct way to do something as opposed to just doing it and refactoring later.

So there it is, I’ve spent a whole lot of time without a great deal of success. About the best thing it’s got going for it so far is that I’ve managed to do some modelling of the domain level objects. So where do we go from here?

Back to the Future

Some might consider this a backward step from comfortable walled garden that is Java but I’ve been experimenting a bit lately with C and GTK+. Yes you read right C, not C++, just pure unadulterated structured programming. Why not C++ indeed.

I’ll probably get flamed for saying this, but I just don’t like it. With great power comes great responsibility, and it’s like a wild beast that can take on any form it likes depending on the wild mood swings of your average programmer. Every time I read C++ I get the impression that whoever’s driving the evolution of the language can’t quite decide what they want it to be. If Java is a well manicured, if somewhat anal, golfing green then C++ resembles a hoarders front yard. You know the ones, full of old car bodies and useless junk left over after you take all the useful stuff out. Don’t take my word for it though, ask Linus. That said you can always pick and choose the bits you like and leave out the bits you don’t.

Anyway, so far I’m really impressed. Previously I’d thought that leaving OO behind would just be too painful however I was pleasantly surprised. To demonstrate a few concepts to myself I briefly knocked up this little demo which consists of a simple GTK+ interface sitting atop an SQLite database. As far as I’m concerned this a great “thin line” of technology from top to bottom which could conceivably be employed to write the app.

db_test.c

#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <sqlite3.h>

/* Database file name. */
const gchar *DB_FILENAME = "test.db";

/* A simple SQL query to select all rows from the person table. */
const gchar *DB_QUERY = "SELECT * FROM person;";

/* Index of the name column in the list view */
const gint LIST_COL_NAME = 0;

/* Index of the age column in the list view */
const gint LIST_COL_AGE = 1;

/* The total number of columns in the list view */
const gint LIST_NUM_COLS = 2;

/* Global reference to DB handle. */
static sqlite3 *db;

/* Callback that processes a single row returned from the database. The first
 * parameter is expected to be a pointer to a GtkTreeView. */
static int
process_db_results( gpointer  data,
                    gint      ncols,
                    gchar    *col_values[],
                    gchar    *col_names[] )
{
    GtkTreeView    *view;
    GtkListStore   *store;
    GtkTreeIter     iter;

    /* Get reference to underlying GtkListStore so we can add to it. */
    view = GTK_TREE_VIEW (data);
    store = GTK_LIST_STORE (gtk_tree_view_get_model (view));

    /* Append a row and populate it using the row data provided */
    gtk_list_store_append (store, &iter);
    gtk_list_store_set (store, &iter,
            LIST_COL_NAME, col_values[0],
            LIST_COL_AGE, col_values[1],
            -1);

    /* Auto-adjust columns to fit data. */
    gtk_tree_view_columns_autosize (view);

    /* Return a zero to let SQLite know it's okay to continue processing */
    return 0;
}

/* User clicked the "Load List" button. */
static void
button_load_clicked( gpointer data )
{
    gint rc;
    gchar *err_msg = 0;

    /* Populate the list component with data from the DB. */
    rc = sqlite3_exec (db, DB_QUERY, process_db_results, data, &err_msg);
    if (rc != SQLITE_OK)
      {
        fprintf (stderr, "SQL error: %s\n", err_msg);
        sqlite3_free (err_msg);
      }

    return;
}

/* User clicked the "Clear List" button. */
static void
button_clear_clicked( gpointer data )
{
    GtkTreeModel  *model; 

    /* Get reference to underlying GtkTreeModel so we can clear it. */
    model = gtk_tree_view_get_model (GTK_TREE_VIEW (data));

    /* Clear the list using gtk_list_store_clear. This is much faster than
     * calling gtk_list_store_remove once for each row. */
    gtk_list_store_clear( GTK_LIST_STORE (model));

    return;
}

/* This callback quits the program */
static gboolean
delete_event( GtkWidget *widget,
              GdkEvent  *event,
              gpointer   data )
{
    /* Close the database connection. */
    sqlite3_close (db);

    /* Terminate the main program loop. */
    gtk_main_quit ();

    return FALSE;
}

/* Creates a list view component consisting of two columns. The first column
 * is for a persons name, the second for their age. */
static GtkWidget *
create_list_view( void )
{
    GtkCellRenderer        *renderer;
    GtkTreeViewColumn	 *column;
    GtkListStore             *store;
    GtkTreeView             *view;

    view = GTK_TREE_VIEW (gtk_tree_view_new ());

    /* --- Column #1 --- */
    renderer = gtk_cell_renderer_text_new ();
    column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
            "text", LIST_COL_NAME,
			NULL);
    gtk_tree_view_column_set_resizable (column, TRUE);
    gtk_tree_view_insert_column (view, column, -1);

    /* --- Column #2 --- */
    renderer = gtk_cell_renderer_text_new ();
    column = gtk_tree_view_column_new_with_attributes ("Age", renderer,
            "text", LIST_COL_AGE,
            NULL);
    gtk_tree_view_insert_column (view, column, -1);

    store = gtk_list_store_new (LIST_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
    gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));

    return GTK_WIDGET (view);
}

/* Initialises the application's database connection. */
static void
init_db( void )
{
    gint rc;

    /* Open the database to initialise the connection object. */
    rc = sqlite3_open (DB_FILENAME, &db);
    if (rc)
      {
        fprintf (stderr, "Can't open database: %s\n", sqlite3_errmsg (db));
        sqlite3_close (db);
        exit(1);
      }
}

/* Initialises the application's user interface. */
static void
init_ui( void )
{
    GtkWidget *window;
    GtkWidget *vbox, *hbox;
    GtkWidget *scrolled_window;
    GtkWidget *list_view;
    GtkWidget *button_load, *button_clear;

    /* Create the main application window */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request (GTK_WIDGET (window), 300, 150);
    gtk_window_set_title (GTK_WINDOW (window), "GTK/SQLite DB Example");

    /* Configure app to terminate when closed */
    g_signal_connect (G_OBJECT (window), "delete_event",
			G_CALLBACK (delete_event), NULL);

    vbox = gtk_vbox_new (FALSE, 5);
    gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
    gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_widget_show (vbox);

    /* Create a scrolled window to pack the CList widget into */
    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
    		GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);

    gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
    gtk_widget_show (scrolled_window);

    /* Create the list view which will display the data. */
    list_view = create_list_view ();

    /* Add the list view widget to the vertical box and show it. */
    gtk_container_add (GTK_CONTAINER (scrolled_window), list_view);
    gtk_widget_show (list_view);

    /* Create a horizontal box to hold our buttons */
    hbox = gtk_hbox_new (FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
    gtk_widget_show (hbox);

    /* Create the buttons and add them to the window. */
    button_load = gtk_button_new_with_label ("Load List");
    button_clear = gtk_button_new_with_label ("Clear List");

    gtk_box_pack_start (GTK_BOX (hbox), button_load, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), button_clear, TRUE, TRUE, 0);

    /* Connect our callbacks to the three buttons */
    g_signal_connect_swapped (G_OBJECT (button_load), "clicked",
    		G_CALLBACK (button_load_clicked), list_view);
    g_signal_connect_swapped (G_OBJECT (button_clear), "clicked",
            G_CALLBACK (button_clear_clicked), list_view);

    gtk_widget_show (button_load);
    gtk_widget_show (button_clear);

	/* The interface is completely set up so we show the window. */
    gtk_widget_show (window);

    return;
}

int
main( gint   argc,
      gchar *argv[] )
{
    /* Before we even think about doing anything we must initialise GTK */
    gtk_init (&argc, &argv);

    /* Initialise the database connection */
    init_db ();

    /* Initialise the user interface */
    init_ui ();

    /* Now that everything's ready, start the main program loop. */
    gtk_main ();

    return 0;
}

Not bad for 236 lines of code huh? Feel free to use the code in any way you like. You'll have to create a new database using the sqlite command-line utility first before running it though:

$ sqlite3 temp.db
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> create table person (name varchar(30), age smallint);
sqlite> insert into person values ("Phillip J. Fry", 33);
sqlite> insert into person values ("Hubert J. Farnsworth", 167);
sqlite> insert into person values ("Zapp Brannigan", 45);
then type CTRL-D to exit

As far as I'm concerned writing this thing in C has a few compelling advantages:

  1. It's portable. C is arguably the most portable (not to mention widely used) language in the world. If binaries aren't available for your processor architecture, you can always compile it especially to suit that Z80 you've had sitting in your basement - just because you can.
  2. No special libraries or runtimes required here. Just run it baby.
  3. Glib, GTK+ again provide 95% of what I need for the app out of the box. Not to mention that the documentation is awesome and free. They're cross-platform too!
  4. Working with relational databases is a snack. No OO/RDBMS disparity here, it's all smooth sailing.
  5. It's really, really fast. There's no VM here, just bare-metal machine code.
  6. Like Java, there's heaps of free libraries and tools out there to take advantage of.

Of course using something as raw as C/GTK+ isn't without its hangups:

  1. Memory management and pointers frighten the bejesus out of many programmers. I don't mind them so much, but I do understand that some have a pathological aversion to them.
  2. Cross-compilation isn't exactly what I'd call straight forward.
  3. If you've been spoilt, like I have, working in 4th gen languages with awesome support for stringsĀ  NULL terminated character arrays are a rude shock. Don't get me wrong, it's not difficult, it's just one extra thing to keep in mind.
  4. Very little in the way of syntactic sugar.
  5. GTK is still yet to be ported to Mac OSX. This is potentially a dealbreaker.

One thing in particular that I found was very nice was the GTK+ "Object Oriented" style interfaces which allow for a form of inheritance within a standard C program. This is a massive benefit because UI programming can get quite repetitive if you're unable to extend and modify components simply by subclassing them.

Well that's about all I've got for now. I'd be really interested in hearing what you think on the matter of technology choice, especially if you're looking to contribute in future.

First look at Intrepid Ibex

November 1, 2008

In the wee hours of this morning I decided to upgrade from my much loved Hardy Heron installation on my trusty Dell Inspiron 9400 (e1705 for you yanks out there) and give Intrepid Ibex a run. At this point I’d like to digress for a second and state that I’m convinced that the person who designed this laptop probably also is responsible for the design of the sherman tank. This thing is friggen’ huge – it’s claim to portability is roughly the same as that of a spare truck tyre. Sure you probably could drag one around but it really belongs strapped to 20 tons of Detroit muscle to make it easy. Once I had to carry it into work every day for a fortnight. I swear the resultant chiropractic bills coulda bought me a new cheaper, lighter laptop. Anyway enough whinging, gotta leave some room for what’s to come.

Although Intrepid doesn’t boast much in the way of new features, I was excited to hear that the Canonical team had spent a fair amount of time and effort improving the stability of the distro and fixing bugs. Considering I already thought Hardy Heron was getting pretty damn close to M$ Windows killer (I even managed to shun Vista entirely and used it exclusively for a period of about 3 months), I thought surely this latest release was gonna be “the one”.

Given that I already had an existing Ubuntu install with a separate home partition I thought I’d simply overwrite the root partition with the latest incarnation. I was impressed as always with the graphical installer, and the process of performing the upgrade was relatively painless. Feeling rather happy that it had all gone so smoothly I quickly rebooted and logged with baited breath. The system logged in and detected my wireless and ATI graphics card within seconds of logging in. I was really impressed at that point and decided to grab the latest updates off the web. Imagine my disappointment then, when everything came to a screeching halt about 5 min later and about halfway through downloading the latest kernel patch.

Now I’m no stranger to these sort of happenings in Linux, especially when it comes to laptops. The first thing I checked was the temperature of the case by running the back of my hand under the laptop and bingo! The thing was more steamed up than a shower scene with Sharon Stone. Immediately I thought to myself, oh great we’re back to the Edgy days when I’d struggle to keep a lid on the CPU temp of my Inspiron 5150 at 75 degrees Celsius (scary huh). To be honest I was majorly boned about this, I really though they’d sorted out all the ACPI shite in earlier releases. I was just about to give up and revert back to the venerable Heron when I noticed a curious thing. Then hot spot wasn’t anywhere near the CPU!

Turns out my Intel 3945ABG wifi card was trying to turn itself into a mini supernova right from the comfort of my desk. Disabling the wifi card and running using the wired NIC confirmed my suspicions. No lockups, nothing. She was solid as a rock. Turn the wifi card back on and bam! My laptop was cookies (as in baked) within a minute or two. Now that really had me scratching my head. What the hell had they done to the wireless driver stack to hurt my wifi card’s feelings so badly? I mean you shoulda been there, he was really hot under the collar about it all.

Thankfully I stumbled upon a post or two on the Ubuntu forums from people with the same card experiencing similar conflagrations breaking out on their desks spontaneously. The solution was rather straight forward. I simply went to http://linuxwireless.org/en/users/Download and followed their instructions to compile a new driver and presto I had my wireless back.

Now where was I? Oh yeah I was supposed to be feeding you some sycophantic review about how good Intrepid (ergo Linux) is and how much M$ suck. Well I’m not going to – go to ITWire if you want to read one of those.

So what do I think? Well driver issues aside Intrepid’s not bad, I particularly like the new dark theme. Given the aim of this release I think I’m going to withhold judgement till I’ve been living with it for a few weeks and see if it lives up to Canonical’s claims of a more stable and reliable OS.

There a lots of great ways to improve your desktop experience in Linux. If the default stylings of GNOME or KDE just aren’t your cup of tea, or you really want a Mac but can’t afford one like me, then read on.

Vista, really?

I’m first to admit, and rather shamelessly, that I really like a bit of eye candy in an OS, especially 3D candy. For all it’s underwhelming glory, I do quite enjoy the shinyness of Vista. If I was really going to make the total conversion over to Linux once and for all, I was really going to miss those effects. Unfortunately for Vista, and consequently the reason I’m trying Linux, is that it’s a bit like a photo of a hooker; looks good, but doesn’t do much. But I digress.

Turning on a bit of visual flair in Ubuntu requires that you have a graphics card with some form of graphics acceleration available. My faithful laptop has an absolute clanger of a video card, an ATI Radeon Mobility X1400 to be precise. I can almost hear you stifling a yawn – it really does suck that much – or so I thought…

Driver dramas

Being OSS, Ubuntu doesn’t include proprietary drivers in the distribution due to the license restrictions many of the EULAs impose. This means that by default you’re using an open source equivalent driver for your hardware. This is fine for every day 2D office related tasks. This won’t do with what we’re proposing however as they don’t support many of the advanced features your graphics card offers – we’re gonna need those. Now before you break out in a cold sweat and start fretting about compiling, editing X config files or anything silly like that, take a deep breath. EnvyNG is a great tool that takes care of all the driver updates for you. It detects and installs the correct proprietary video card driver for you in a matter of minutes. Easy huh?

Mac on a mortgage

Mac4Lin Desktop

After a reboot you should now be ready to turn on advanced desktop effects (Compiz-Fusion for those in the know). This will enable all kinds of funky effects on your desktop like wobbly windows, 3D cube desktop selection etc.

Impressive eh? Well this is where it gets really fun. Head on over to SourceForge and grab all the latest files from the Mac4Lin project. This should include everything you need, including instructions on how you tweak your desktop till it’s damn near unrecognisable as Linux. I’m not real sure how Steve Jobs would feel if he saw this.

One thing I’m really impressed with is the speed at which all these effects run. Under Vista one could have been forgiven for thinking that Dell had given me the worst graphics card known to man. In fact I’ve always been slighly disappointed with my laptop’s performance until now. Ubuntu runs like a scalded cat on a hot tin roof, and I’m smiling from ear to ear about it.

Sorry Vista, looks like another nail in your already sealed coffin.

Click here For a more in depth look at more things you can do in Hardy Heron.

Ubuntu

Well it looks like Canonical finally hit some of the right stuff with their latest incarnation of the Debian based Ubuntu: Hardy Heron (8.04).

A couple of weeks back I installed Ubuntu Linux in a dual boot configuration on my laptop along side Vista after getting a good review from a friend about it. Some of you might remember that I’ve tried to do this before with prior versions of Ubuntu but been met with stiff oposition from my Dell laptop’s stubborn drivers. In fact it damn near killed my laptop due to a faulty ACPI implementation that caused my processor to cook itself. Not a great day at the office really.

Anyway my experiences lately have been chalk and cheese. The install process was so straightforward, fast and easy that I actually managed to install the distro on the bus on the way to work (I’m a dork and I make no apologies for it). All my applications and drivers installed fine, and there was no baked chips to speak of. It just worked. In fact I think it was easier and faster to install that Windows – very nice.

It looks like Linux on the laptop has come a long way.

Follow

Get every new post delivered to your Inbox.