ApplicationCommandLine

In Terminix I’m making some improvements to how I’m handling the command-line by moving away from D’s getopts to the GTK method of dealing with it. The primary driver for this is to get the command line sent from the local application to the primary one. To do this, I registered my Options via setMainOptions, added a handler to addOnCommandLine and included the flag HANDLES_COMMAND_LINE when creating the application.

It all worked swimmingly except for one issue, while the primary got the command line just fine, the local instance would just hang and never return. After scratching my head for a bit and asking on the GTK IRC channel, a pointer to a C example gave me the nudge I needed. Looking more closely at the documentation for ApplicationCommandLine, I see this line:

For the case of a remote invocation, the remote process will typically exit when the last reference is dropped on @cmdline.

The issue here is that since D is GC’ed, the ApplicationCommandLine doesn’t get collected in a deterministic fashion. The solution was quite easy, simply destroy it at the end via a scope(exit) block. I’m going to file an issue with GtkD to see if this shouldn’t be made a Scoped reference.

GtkD and Localization

On my todo list for awhile has been adding localization support to Terminix. Unfortunately at this time D does not have an official i18n package nor are there any libraries supporting the GNU gettext which has become a De facto standard for localization over the years. While there are some localization libraries available for D, I really wanted to stick with gettext given the huge eco-system it has in terms of support tooling and websites.

While examining my options, I stumbled on the fact that the GTK GLib library supports gettext and that GtkD has already wrapped them in the glib.Internalization class. After refreshing my knowledge of how gettext works I was able to put together a basic working localization system in about an evenings worth of work. The remainder of the post will describe the steps involved with getting it working.

I knew in Terminix that I would need to support localization, so from day one I had a module gx.i18n.l10n that contained a single function following the gnu gettext pattern as follows:

string _(string text) {
    return text;
}

Whenever something in Terminix would eventually need to be localized, I would simply wrap it in a call to this function. Obviously at this early stage the function does nothing beyond returning the original text. An example of its usage is as follows:

string msg = _("This is a localized string");

For those of you familiar with the usage of gettext in C or other languages this will all seem familiar. For anyone else, in gettext any text you want to localize is wrapped in this function and becomes the key for retrieving a localized version. If no localized version is available, i.e. for a language for which a translation does not yet exist, the key is used as the text that is displayed. in my opinion, this system is much superior to localization systems that require programmers to have to embed artificial keys in the code and is one reason why gettext is so popular.

The next step was to simply incorporate the glib.Internationalization class from GtkD, so I updated my _() method as follows:

string _(string text) {
    return Internationalization.dgettext(_textdomain, text);
}

The textdomain parameter above is used by gettext to differentiate this application from others and will be discussed in more detail later. At this point, the application now supports localization but the real work begins as we need to prepare all of the localization materials that gettext requires. In gettext there are three types of files required for localization:

  • Template. This file, with a .pot extension, is used as the template for the localization. For a given application there is typically only one template file.
  • Portable Object (po). These files, with the extension .po, contain the localization for a specific locale, for example en.po or fr.po. These files are in the same format as the template file.
  • Machine Object (mo). These are the binary files that are used at runtime and are created by the msgfmt utility. These files have a 1:1 mapping with a po file in that each mo file is created from a po file.

Here’s an extract showing what a template/po file looks like:

msgid "Match entire word only"
msgstr "Match entire word only"

msgid "IBeam"
msgstr "IBeam"

msgid "Run command as a login shell"
msgstr "Run command as a login shell"

msgid "Exit the terminal"
msgstr "Exit the terminal"

in the extract above, the msgid is the key while the msgstr is the actual localization and as per above in the template file these will be identical. Additionally for most applications there is no need to provide a localization file for the locale the developer is using since that locale is already embedded in the source code by default.

The challenge at this point was creating the template file, while the gettext program has a utility called xgettext that can extract all of the localized strings from source code, unfortunately D is not one of the languages supported. I thought about creating a version of xgettext using the excellent libdparse, however I opted for a quick and dirty method as Terminix doesn’t have a large amount of strings needing localization.

What I ended up doing is adding some code to my l10n module to capture all the localization requests and then write it out a file when the application terminates. This has the advantage of being relatively easy to do but the disadvantage that you have to exercise the app pretty completely to capture all the strings. For Terminix there were only a few areas I couldn’t exercise easily and for those I simply updated the template file after the fact. Below is the code I used to generate the template file, note the use of the Version specification so this code only gets included in a specific build configuration. I’ve removed some of the comments for the sake of conciseness, you can view the original code in github.

module gx.i18n.l10n;
 
import glib.Internationalization;
 
version (Localize) {
 
    import std.experimental.logger;
    import std.file;
    import std.string;
 
    string[string] messages;
 
    void saveFile(string filename) {
        string output;
        foreach(key,value; messages) {
            if (key.indexOf("%") >= 0) {
                output ~= "#, c-format\n";
            }
            if (key.indexOf("\n") >= 0) {
                string lines;
                foreach(s;key.splitLines()) {
                    lines ~= "\"" ~ s ~ "\"\n"; 
                }
                output ~= ("msgid \"\"\n" ~ lines);
                output ~= ("msgstr \"\"\n" ~ lines ~ "\n");
            } else {
                output ~= "msgid \"" ~ key ~ "\"\n";
                output ~= "msgstr \"" ~ key ~ "\"\n\n";
            }
        }
        write(filename, output);
    } 
}
 
void textdomain(string domain) {
    _textdomain = domain;
}
 
string _(string text) {
    version (Localize) {
        trace("Capturing key " ~ text);
        messages[text] = text;
    }
 
    return Internationalization.dgettext(_textdomain, text);
}
 
private:
string _textdomain;

When capturing text, there are a couple of special cases in gettext to be aware of. The first is that the xgettext utility puts a special comment in front of strings that use C style formatting, i.e. %d or %s. I don’t think this comment is used but I wanted to keep it. The second is that the key for multi-line strings is generated with each line separated. That’s why in the code above you see the check for newline and the splitLines call.

Once the template file is completed we are ready to create our first localization. In my case, I created an English localization as Terminix has some programmatic terms (shortcut identifiers) that were intended to be localized to human friendly language rather then shown directly to the user. Creating the en.po file is just a matter of copying the terminix.pot file to en.po. While gettext has a utility for this, msginit, I just opted to copy it for simplicity.

Once the en.po localization was completed it needs to be compiled into a mo file. In Linux, mo files are stored in usr/share/locale/${LOCALE}/LC_MESSAGES where ${LOCALE} is the standard language/country code. The mo files for the application are named after the textdomain for the application and this is how gettext locates the right file for the application. For example, in Terminix’s case the full path to the English mo file would be usr/share/locale/en/LC_MESSAGES/terminix.mo.

To compile the mo file, simply use the gettext msgfmt utility as follows:

sudo msgfmt en.po -o /usr/share/locale/en/LC_MESSAGES/terminix.mo

Obviously you would want to script the above process as part of creating an installation package, you can see how Terminix does this here.

Using the GAction Framework

In GUI development you typically want to centralize event handlers given that it is pretty common to have multiple GUI elements (button, menu item, etc) invoking the same event. In many frameworks these centralized event handlers are typically referred to as actions. In GTK the action framework is part of GIO and is referred to as GAction. An overview of the framework can be found in the Gnome wiki in this How Do I entry.

Having done Delphi development 15 years ago I had some familiarity with the concept but it still took a bit of time to get up to speed on GActions. While the Gnome wiki provided some basic information, I still found it confusing in some spots so I thought I’d write a bit about my experience using GActions in Terminix as it specifically relates to the D language and the GtkD framework.

First some basics, every GAction has two elements that identify it, a prefix and a name. The prefix is a way to categorize actions and within a prefix the name of the action must be unique. The prefix and the name together, with a period between them, make a detailed action name and this is how you reference actions when binding them to UI elements. So if you have a prefix of “terminal” and a name of “copy” the detailed name would be “terminal.copy”.

Actions are stored in containers which typically implement the interfaces gio.ActionMapIF and gio.ActionGroupIF. Out of the box, GTK implements these interfaces in Application and ApplicationWindow. Actions registered against these objects are automatically assigned the prefix of “app” and “win” respectively. Typically actions registered against the Application object are used in the Gnome application menu and actions registered against ApplicationWindow operate against that window.

An important thing to understand though is you are not limited to registering actions against just Application and ApplicationWindow, you can register actions against any widget in your application using custom prefixes. The key is using the gio.SimpleActionGroup to create your own container to register actions against. You can then bind the SimpleActionGroup to a widget via the method insertActionGroup. An example of this is shown below:

SimpleActionGroup sagTerminalActions = new SimpleActionGroup();
//...create actions and register to the group
insertActionGroup(“terminal”, sagTerminalActions);

Understanding how to create your own action groups gives you a lot of flexibility in organizing your actions. Terminix is an application where the UI is heavily nested and generally I wanted to keep each layer isolated from each other. I didn’t want the Terminal to know too much about the containers it is nested within. Being able to create these custom action groups allows the terminal to have it’s own set of actions without needing a mechanism to bind them to the window.

The other benefit to this approach is that the GIO framework will allow you to have multiple instances of the same action and will determine which instance get’s invoked based on the scope. In Terminix I have multiple terminals each with the same set of “terminal” actions registered. The GAction framework automatically invokes the right action instance based on the terminal that has focus presumably by walking up the widget hierarchy until it finds the first widget with the action it is looking for.

To register an action, you simply create an instance of gio.SimpleAction which is a concrete implementation of the ActionIF interface and the add it to the desired ActionMap. A simple example would look like:

action = new SimpleAction(“copy”, null);
action.addOnActivate(delegate(Variant, SimpleAction) {
vte.copyClipboard();
});
sagTerminalActions.add(action)

Once you have your action, the next step is to bind it to a user interface element. One thing to be aware of is that in GTK there are actually two action frameworks, the one in the gio package (SimpleAction, SimpleActionGroup) and one in the gtk package (Action, ActionGroup). The one in GTK is considered deprecated and it is highly recommended to use the GIO action framework where possible. In general, GTK widgets that work with GIO actions use the method setActionName to specify the target action, the method setActionTargetValue is used by the GTK framework.

To bind the action to a UI element, you simply call the setActionName method with the detailed action name, for example:

button.setActionName(“terminal.copy);

Actions can be represented in menus using a variety of UI elements such as check and radio buttons. This involves declaring that an action has state which is represented by a GLib Variant in the Activate signal. I won’t spend any time on this topic, however for those interested I wrote an actions demo showing how to do this with popovers and it is available in the GtkD repository here.

If you want your action to have an accelerator, i.e. a keyboard shortcut, you need to register the key and the detailed action name with the your global GTK Application instance using the method Application.setAccelsForAction. Here is an example of this:

app.setAccelsForAction(“terminal.copy”, [“c”]);

This concludes the article on GActions, hopefully as you can see this provides a powerful framework for centralizing your event handlers within a GTK application. One final note, for the purposes of this article I’ve been using strings directly for prefixes and names for illustration. Obviously, you should declare these as constants in your code to ensure consistency. If you need to change the name of a prefix or action, having the string declared in one spot makes that job much easier.

Iterating over TreeIter

I’m working on a GTK application and found there were a few spots where I needed to iterate over a TreeModel. Doing this in GtkD is a bit of a pain since TreeModelT isn’t implemented as a Range and so you are forced to use the model methods rather then the convenience of foreach.

To make my life easier, I created a small struct that can be used to wrap a TreeModelIF interface and allows it to be used in D’s foreach construct as per this example:

foreach(TreeIter iter; TreeIterRange(lsProfiles)) {
	if (lsProfiles.getValue(iter, COLUMN_UUID).getString() == window.uuid) {
		lsProfiles.setValue(iter, COLUMN_NAME, profile.name); 
	}
}
/**
 * An implementation of a range that allows using foreach over a range
 */
struct TreeIterRange {
 
private:
    TreeModelIF model;
    TreeIter iter;
    bool _empty;
 
public:
    this(TreeModelIF model) {
        this.model = model;
        _empty = model.getIterFirst(iter);
    }
 
    @property bool empty() {
        return _empty;
    }
 
    @property auto front() {
        return iter;
    }
 
    void popFront() {
        _empty = !model.iterNext(iter);
    }
 
    /**
     * Based on the example here https://www.sociomantic.com/blog/2010/06/opapply-recipe/#.Vm8mW7grKEI
     */
    int opApply(int delegate(ref TreeIter iter) dg) {
        int result = 0;
        TreeIter iter;
        bool hasNext = model.getIterFirst(iter);
        while (hasNext) {
            result = dg(iter);
            if (result) break;
            hasNext = model.iterNext(iter);
        }
        return result;
    }
}

Creating Complex Popovers in D and GtkD

I’m working on a new terminal emulator in my spare time and one UI element I definitely wanted to make use of was Popovers. While creating a simple Popover is quite easy, I was struggling a bit with how to handle the more complex layouts like horizontal buttons as the documentation does not make it very clear. Fortunately, Christian Hergert of Builder fame was on IRC one night and was able to point me in the right direction.

The Popover I created is shown in the image below, in the terminal emulator I’m working on it allows you to split the terminal into multiple views or tiles so the user can see multiple views at the same time in an easily managed container. The Popover allows the user to split the terminal horizontally or vertically (note the icons are temporary, plan on “borrowing” Builder’s icons for this at some point).

Popover

The issue I was struggling with was where to set the display-hint, the section being a gio.Menu doesn’t have methods to set an attribute. What Christian pointed out to me is that you need to create an empty MenuItem to represent the section, add the section to that and then add it the menu used in the Popover. You can then set the necessary attributes on the empty MenuItem to get the items displayed in the way you want.

Here is the code I ended up with:

Popover createPopover(Widget parent) {
GMenu model = new GMenu();
 
GMenuItem splitH = new GMenuItem(null, "view.splith");
splitH.setAttributeValue("verb-icon", new GVariant("go-next-symbolic"));
splitH.setIcon(new ThemedIcon("go-next-symbolic"));
 
GMenuItem splitV = new GMenuItem(null, "view.splitv");
splitV.setAttributeValue("verb-icon", new GVariant("go-down-symbolic"));
splitV.setIcon(new ThemedIcon("go-down-symbolic"));
 
GMenu section = new GMenu();
section.appendItem(splitH);
section.appendItem(splitV);
 
GMenuItem splits = new GMenuItem(null, null);
splits.setSection(section);
splits.setLabel("Split");
splits.setAttributeValue("display-hint", new GVariant("horizontal-buttons"));
 
model.appendItem(splits);
 
Popover pm = new Popover(parent, model);
return pm;
}

Learning D and GTK

Quite awhile ago I wrote a post about learning Python and GTK, unfortunately while I played around with it a bit I never really took to Python. The dynamic typing and the usage of whitespacing as delimiters were not my style. Additionally, I was doing a lot of travel for work at the time and could never really muster the energy at the time to overcome my initial dislike of Python.

So as work slowed down a bit I figured I’d try something new this time. I decided to pick up D due to a number of factors including:

  • It’s derived from the C family so has some similarities to Java
  • It’s a compiled language so performance is excellent
  • Has a garbage collector so again similar to Java.
  • And most importantly, has full and up to date bindings for GTK

I had also considered trying Go, but the last point put a bullet in that the available GTK bindings appear to have a ways to go.

So to put the conclusion first, I did end up writing a small utility in D and GTK called Visual Grep. It’s a GTK based GUI for grep that follows Gnome Human Interface Guidelines (HIG) as much as possible. A screenshot is below, if you are interested in trying it out you can find it on Github.

Visual Grep

Learning D

I’ve had my eye on D for a number of years as a possible language to use for building GUI applications. The language itself is well designed and as a lot of advantages in the GUI space with safety features such as garbage collection combined with high performance as a compiled language.

Learning the D language itself is relatively straight forward and I didn’t find the learning curve to be that high. Coming from Java, the biggest hurdle was understanding ranges which is core to many features in D. I found it helpful as a starting point to think of ranges as an advanced version of Java’s Iterator class. The other key features in D, such as templates, can be learned over time but Ranges are core to D and need to be understood right up front so I’d recommend dedicating some time to it right at the beginning.

The next aspect of learning D is understanding the standard library called phobos. This library can be thought of as occupying a similar space as the core J2SE libraries. Learning the library and features available is not overly difficult, however the documentation available on dlang can often be overly succint. Additionally, in the Java world if you google on any API you can find a wealth of information, discussion and examples. Since D is much less popular, the amount of resources available is also consequently much less (a theme that will re-occur in subsequent sections).

Having said that, the D community is big enough that questions on forums and the irc channel got answered and I never found myself blocked on any particular issue.

The only issue with D, and reflected in phobos, is the general lack of a library eco-system. In more mainstream environments like Java and Python, there are a plethora of libraries to pretty much cover any use case. Want to create and parse XML, work with PDF files, do localization, interface with USB, etc you have your pick of libraries. In D not so much, while most core functions are available, some key ones are not. For example, there is currently no standard i18n package available for localization, logging is deigned experimental, etc.

This lack of resources is also reflected in phobos itself in terms of implementation and execution. For example, D has an excellent design with respect to multi-threaded communication based on message passing. D also supports the concept of declaring variables as immutable which would seem to be a perfect fit with respect to this message passing. From a design perspective it should work, however due to limitations in the implementation of variants in D you can’t actually use an immutable variable in this scenario. Either you pass a shared variable (D’s way of declaring a variable to be shared among multiple threads) or pass a pointer to the immutable variable and de-reference it on the receive.

Finally the last area of D that I struggled with a bit is pointers. While I have done some work with pointers in the past in Delphi, the usage of pointers in Delphi tended to be very rare. I have to be careful and not exaggerate as by no means is the usage of pointers in D constant need when building GTK apps, it’s just I did find I needed to work with them more then I did in Delphi due to the need to interface with C. Having coded only in Java for the last 12 years, coming back to pointers was a bit of a culture shock.

Learning GTK

My previous experience with GUI frameworks includes Java Swing (hate it) and Delphi VCL (love it).. D has a very complete set of bindings for GTK called GTKD and is highly recommended, Mike Wey does a great job keeping these up to date for each release of GTK. Based on my experiences with Swing and VCL, learning and getting productive with the basics of GTK was very easy with two notable exceptions.

The first is the GTK Treeview which, despite the name, is really an all encompassing listbox/treeview which serves multiple use cases. While it is undeniably powerful, I found it’s API a bit obtuse and difficult to accomplish the basic use cases. The sheer variety of objects related to the TreeView (TreeView, TreeModel, TreePath, TreeIter, CellRenderer, etc) is a bit overwhelming to the newbie.

The other aspect I struggled with a bit was the multi-threading. In GTK, the preferred approach to multi-threading is to setup a callback gdk-threads-add-idle. While not an issue in GTK per se, GTKD does not really give any examples on how best to integrate this with D. Looking at the design though, I went with integrating this with D’s threaded message passing infrastructure and it turned out to work very well but I burned quite a lot of time prototyping and testing to make sure I understood how everything worked.

An invaluable resource for learning GTK and GtkD was the grestful application, an open source D/GtkD application for testing REST requests. I borrowed quite a bit of code from that application including the plumbing for being able to tie in a D delegate to the GTK thread idle callback so a big thanks to that project for this.

Finally, I’d really recommend having some basic proficiency in another language with full bindings in GTK, either C or Python. The reason for this is that there is very little information out there on using D with GTK but GTK examples in other languages are easily ported to D providing you can work through the code of the example. My C and Python knowledge is pretty sparse but I found I knew enough to get by.

Tool Chain

The tool chain for D is somewhat primitive in comparison to Java but is imminently useable. I do all my development on Linux and so ended up using Mono-D and generally had a pretty positive experience. My only complaints are as follows:

  • When trying to run a program, you can an error about failing to create a console. Turns out this is an issue with gnome-terminal as documented here. Unsetting the GNOME_DESKTOP_SESSION_ID variable fixed the problem.
  • Code completion seems a bit hit and miss, most of the time it works great but once in a while you hit the’.’ and nothing happens.

Debugging can be done in Mono-D using the GDB plugin and I found this to work quite as well when I was dealing with segmentation faults with my multi-threading code.

For builds I used DUB which is somewhat similar to Maven in the Java world in that it is based on convention not configuration and manages dependencies. I found DUB worked quite well for me and have been pretty happy with it though admittedly my two projects are pretty simple.

Conclusion

Based on my experience so far, I think D and GtkD are a great combination for creating GTK applications in Linux. The learning curve is far shorter then using C and the language itself is much more productive then I say that as a C neophyte so take that with a pinch of salt. Additionally, the safety features of D (GC, RAII, exceptions, etc) make for more reliable software in comparison to C.

Python would also be a very good choice, but coming from a Java background D just felt much more comfortable to me.

Lavender Redux

A few months ago I posted a theme called Lavender for Gnome Shell and GTK, this theme took the excellent Numix theme and tweaked the colors to use the same scheme as Sam Hewitt’s excellent but now unsupported Orchis theme. Unfortunately the Numix theme hasn’t been keeping up with newer versions of the GTK so with Gnome 3.18 I ended up re-basing Lavender on Adwaita instead.

Similar to the original Lavender theme the goals were as follows:

  1. Tweak the colors to match the Orchis theme in order to work well with Sam Hewitt’s excellent Moka icons
  2. Minimize customization to the base theme files in order to make it maintainable so as new versions of the base theme, Adwaita in this case, come out it’s easy to upgrade
  3. As a corollary to #2, any CSS changes should reside in an external file if at all possible as I really don’t want to re-edit Adwaita everytime a new version comes out.

So in a nutshell, this is a slight tweaking of Adwaita. If you don’t like Adwaita you probably won’t like this as well. Here’s a screenshot of what it looks like:

Screenshot from 2015-10-13 10-09-16

While I miss the Dark titlebars from Numix, I’m happy with the results at this point. Hopefully once the Numix sass port is ready for prime-time I’ll switch back to that as a base.

A couple of additional comments on this tweaked theme:

  1. I fixed the annoyling line in Chrome between the titlebar and the tabs, it’s also fixed in other apps like Firefox
  2. There is a chrome extension which is just a copy of the Adwaita scrollbar extension but the color is changed to match this theme
  3. Nautilus has been slightly tweaked with alternating row colors and sidebar color to match the original Orchis theme

You can download the Lavender theme here. Note this has only been tested with GTK 3.18, not sure how it will work with earlier versions.

Lavender GTK Theme

I really like the work that Sam Hewitt’s Moka Project has put together with their icons, Moka gnome shell and Orchis GTK themes. Unfortunately the Orchis theme isn’t fully compatible with GTK 3.14 and has a number of small issues that were annoying me. As much as I stuck with it due to the outstanding design of Orchis still those issues kept bugging me.

I initially ended up forking Orchis and fixing a few of the most egregious issues, at least to me, and submitted a pull request back to the project. As I was looking at fixing more things though it became apparent that this would take more time then I had available due to my general unfamiliarity with GTK theming and not understanding the nuances of the changes between 3.12 and 3.14 at the theme level. Also, while I’m comfortable with CSS having done Java development for web sites at various points in my career, I’m certainly not a designer nor a CSS guru.

So I ended up looking for alternatives and I came across the Numix theme. It was also well designed and supported 3.14 however the color palette was not to my taste. Having said, I had a look at how it was coded out of curiousity and noticed that it would be very easy to change it’s color palette. Rolling up the sleeves, I spent a couple of days playing with things and soon had a variant of Numix that used the Orchis color palette and assets and worked acceptably for my needs, thus was born Lavender.

Lavender Theme

Lavender Theme

Lavender is my first attempt at customizing a GTK theme. Lavender includes the GTK 2, GTK 3 and metacity themes from Numix with minor modifications, to the best of my ability, to support the Orchis color schemes. It also replaces the Numix assets for radio buttons, checkboxes, etc with the equivalent ones from Orchis. Lavender is not as attractive as Orchis, which is a superb design, but it gets the job done and works well with GTK 3.14 so it meets my needs.

Lavender also includes a slightly modified version of the Moka gnome shell theme. The primary change being a small purple bar shown to the left of running applications, similar to what Vertex does, to make them easier to pick out. As I get older I find I’m having trouble seeing contrast differences in blacks so this change was geared to my older eyes.

Finally let me clear that my effort pales in comparison to what the folks who originally built Numix and Moka/Orchis have put into their themes. Quite literally this work would not exist without those two giants, if you like this theme please, please donate to both these projects using the links below.

Moka Donation Page: mokaproject.com/donate/
Numix Donation Page: numixproject.org/

You can download Lavender at DeviantArt.

Learning Python, GNOME and GTK+3

While it’s a new year and I thought for my new years resolution that I would get back into doing a side project in my spare time. In my day job I do a lot of Java development but in the past I’ve typically taken on a side project doing something different from what I do for work to exercise the brain and keep my skills sharp. The last side project I did was an Android application called OnTrack Diabetes and it was a good experience that gave me some appreciation for mobile development.

I’ve been using Linux now for almost three years with the GNOME desktop environment so this time around I figured I’d get into writing a GTK+ 3 application and blog about the experience here. In terms of an application, I’m going to start with something relatively simple which is a Visual Grep tool. While I’m perfectly comfortable using grep from the command line, there are use cases for me where I like to have a GUI as I’m doing some analysis on code or other files that requires me to access the grep results in a random but persistent way.

So my first task was selecting a language for the development of this application. The two languages I considered are Python and Vala since they are both first class GNOME languages with excellent GTK+ 3 bindings. After doing some investigation, I decided to go with Python for this application for a couple of reasons. The first is that Python is more widely used then Vala which isn’t used anywhere outside of GNOME development as far as I can tell. This leads into the second reason which is that learning Python better actually benefits my day job as I’m often writing WebLogic scripts in Jython. The final reason is that Python has more mature tools then Vala.

Now that the language decision was made, the second order of business was to get an IDE setup. I opted for the PyCharm Community Edition from JetBrains. It appears to be a robust Python IDE with full support for code completion, re-factoring and debugging. Also, it didn’t hurt that I have heard nothing but good things about IntelliJ which is the JetBrains IDE for Java. Installing PyCharm in Arch is simple using the AUR package for it.

After installing PyCharm, I copied in my first GTK 3 program from a tutorial as follows:

[python]
from gi.repository import Gtk

win = Gtk.Window()
win.connect(“delete-event”, Gtk.main_nquit)
win.show_all()

Gtk.main()
[/python]

And this is where I ran into my first problem. The first line had a red underline for the Gtk import indicating PyCharm could not resolve it and code completion wasn’t working for any GTK classes. After doing some googling I could see that this was a common complaint. Apparently GTK 3 uses introspective bindings which are problematic for some IDEs. PyCharm was supposed to handle it by generating a skeleton (hit Alt-Enter after Gtk and select “Generate stubs for binary module”)  but it never worked for me.

Instead I ended up using a package called fakegir which generates skeleton source files for the GTK 3 API. To use fakegir, I first imported the python-lxml dependency fakegir requires and then executed the fakegir script using the following commands:
[bash]
git clone https://github.com/strycore/fakegir
cd fakegir
python3 fakegir.py
[/bash]
And this is where I hit my next issue when I got the following error:
[bash]

Parsing /usr/share/gir-1.0/Cogl-2.0.gir
Traceback (most recent call last):
File “fakegir.py”, line 234, in
generate_fakegir()
File “fakegir.py”, line 226, in generate_fakegir
fakegir_content = parse_gir(gir_path)
File “fakegir.py”, line 195, in parse_gir
namespace_content = extract_namespace(namespace)
File “fakegir.py”, line 165, in extract_namespace
namespace_content += insert_enum(element)
File “fakegir.py”, line 88, in insert_enum
if enum_name[0].isdigit():
IndexError: string index out of range
[/bash]
To work around this, I patched the fakegir.py to simply ignore this exception. Not sure if this is the best route to fixing the issue (Hey I just started learning Python!) but it worked for me:
[python]
def insert_enum(element):
“””Returns an enum (class with attributes only) as text”””
enum_name = element.attrib[‘name’]
docstring = get_docstring(element)
enum_content = “\n\nclass %s:\n \”\”\”%s\”\”\”\n” % (enum_name, docstring)
members = element.findall(“{%s}member” % XMLNS)
for member in members:
enum_name = member.attrib[‘name’]
try:
if enum_name[0].isdigit():
enum_name = ‘_’ + enum_name
except IndexError:
print(“Enumeration failed ” + enum_name)
continue
enum_value = member.attrib[‘value’]
enum_value = enum_value.replace(‘\\’, ‘\\\\’)
enum_content += ” %s = ‘%s’\n” % (enum_name.upper(), enum_value)
return enum_content
[/python]
Notice the new try…except, apparently the XML element causing this issue does not have a ‘name’ attribute hence why it fails. Like I said my fix probably isn’t the greatest but it gets it going.

Once the fakegir cache is generated, you have to add it as a content root in PyCharm as per the screenshot below:

Screenshot from 2015-01-10 15:01:48

Once this is done, code completion works successfully:

Screenshot from 2015-01-10 15:02:34

However if you try to run the application within PyCharm it now fails because the fakegir files are supplanting the real GTK 3 implementation. To workaround this, I disabled the options in Run Configurations to “Add content roots to PYTHONPATH” and was able to run the code successfully within PyCharm.

PyCharm Run Configuration

So that’s my first entry on my foray into the world of Python, GNOME and GTK+ 3 development. As I work through this application I’ll update the blog with my progress, hope you’ll find it interesting.