GNOME Break Timer: Week 4

My work is coming along nicely with the new break timer application for GNOME. I started off week three working on some extra pieces for the break monitor component. I disabled its big “take a break” overlay, and I added some new functionality: the screen locks automatically during a long break, there’s a new “break interrupted” notification that appears at just the right moment (like when you unlock the screen), and there are some helpful sounds when breaks start and stop.

With that bit behaving mostly as intended, for now, I switched over to the other half to the application: its settings screen. The new settings screen is very different from the old one. Actually, the way it’s presented is that the settings application is the break timer application, and it just continues running in the background when you close it. That makes a ton of sense, of course, but it’s different from how this is implemented so I’ll probably sound nonsensical for a bit as I get used to describing it that way.

The new settings screen (or whatever we call it now) is already feeling quite nice.
The new settings screen (or whatever we call it now) is already feeling quite nice.

It took a surprising amount of fiddling to get the break status to show up correctly in the new Break Timer application, but I learned some interesting things about Vala along the way. These two bits of the application talk to each other over dbus, so to make that easier I define my interface in a source file that is common between the two components, and then I implement it in the code that actually provides the dbus service. Here’s how that looks (in a very simplified, contrived form, of course):

// common/IMyService.vala:

public const string MY_BUS_NAME = "org.my.application";
public const string MY_OBJECT_PATH = "/org/my/service";

[DBus (name = "org.my.service")]
public interface IMyService : Object {
	public abstract string[] get_messages() throws IOError;
}

// service/main.vala:

[DBus (name = "org.my.service")]
private class MyService : Object, IMyService {
	public string[] get_messages() {
		return {"Hello", "world"};
	}
}

public int main(string[] args) {
	try {
		DBusConnection connection = Bus.get_sync(BusType.SESSION, null);
		connection.register_object(
			MY_OBJECT_PATH,
			new MyService()
		);
	} catch (IOError error) {
		GLib.error("Error registering service on the session bus: %s", error.message);
	}
	return 0;
}

// client/main.vala:

IMyService my_service = Bus.get_proxy_sync(
	BusType.SESSION,
	MY_BUS_NAME,
	MY_OBJECT_PATH
);

Vala does a great job making all of that just work, though I did run into some trouble when I tried to define a signal in my interface. Normally we just have the signal in the interface definition and it’s automatically available for any implementing class (think mixins), but something was getting muddled up somewhere and, while the signal was available to the application, it was never registered on dbus. So, my client application couldn’t use it. The obvious workaround is to just not implement the Vala interface with MyService (so it’s just private class MyService : Object {), but I hate to do that because the nice thing about using the same Vala interface on either end is you can’t change them independently. So, I’m less likely to do something dumb like change the DBus interface in a way that breaks part of the settings application. In the end I wasn’t using signals in my dbus interface anyway, so I didn’t have to deal with it.

Another curious puzzle I ran into was an annoying race condition, where the Break Timer application would detect the break monitor daemon on dbus, and try to talk to it, and then fail because the interface it was expecting was not available (unexpected error: GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such interface `org.brainbreak.Breaks.TimerBreak' on object at path /org/brainbreak/Breaks/microbreak). This turned out to be a lot simpler than I originally assumed: I’m using GtkApplication, which registers the application ID on dbus in order to handle uniqueness. What happened is GtkApplication would acquire the well-known name of my break monitor daemon on dbus, then the settings application would get some CPU time and see the daemon’s name on dbus and try to talk to it, but at that stage the daemon had not actually initialized, so its break-tracking-related services weren’t registered, yet – just the name. The fix is really simple: the value for my GtkApplication’s application_id needs to be different from the well-known dbus name I use to access the break timer’s special dbus interface. I just changed application_id to that dbus name + “.Application”. Then, after all of the initialization is complete, I get the dbus connection object for the application and own a different name on the bus for the service that the application itself provides:

var connection = this.get_dbus_connection();
if (connection != null) {
	Bus.own_name_on_connection(connection, HELPER_BUS_NAME, BusNameOwnerFlags.REPLACE, null, null);
}
We have a lot of room to play with for cute little status messages.
We have a lot of room to play with for cute little status messages.

That all gave me a nice opportunity to explore some changes to the break schedule dialog, which is what’s left of the original break settings application. I got rid of the On / Off switch beside each break type, and instead I added a combo box to select a particular type of schedule: either micro breaks and full breaks, just micro breaks, or just full breaks. This helps to establish what full breaks and micro breaks are, and it allows us to present the different break schedules up front, instead of hiding that more meaningful choice behind a rather arcane assortment of switches.

The Schedule dialog has two fewer buttons, and some much more direct choices.
The Schedule dialog has two fewer buttons, and some much more direct choices.

I’m working on this with Ubuntu 13.04 and the GNOME 3 repository, so I’m trying to keep everything compatible with GTK 3.8. To use the wonderful new HeaderBar widget, I’m using libgd. It’s meant to be used as a git submodule, but I’m still using bzr for this project (pending an even more compelling reason to switch). So, I added an extra git clone command in my automake.sh, which does essentially the same thing as git submodules. This is all a little strange, and the moment I switch this project to a git repository is getting very close, but for the time being I just feel a little happier pushing to Launchpad and getting that quick feedback when I break the build. With that said, there was an extra stumbling block with my fake libgd submodule and Launchpad: the build server wasn’t letting my build script access the internet to do its git clone libgd thing, but there is no way I am adding the libgd codebase to my project without a very good reason. So, I set up a git import for libgd in Launchpad, and I added one more line to my bzr-builder recipe: nest submodules lp:~dylanmccall/brainbreak/libgd libgd.

So, that means there’s still a working repository to play with the latest code! This version only works in an environment with GNOME 3.8 or above, like Fedora 19 or Ubuntu Saucy (or, if you’re feeling adventurous, Ubuntu 13.04 with the GNOME 3 PPA), but it does work! For Ubuntu, it’s a different repository than before: ppa:brainbreak/experimental. It should also build and run from source relatively smoothly.

That’s all for now. This is rough around the edges, but I think it’s starting to make sense. If you try it, please consider leaving a comment to share how it goes.

5 Replies to “GNOME Break Timer: Week 4”

  1. Hey there! Would you mind if I share your blog with my
    myspace group? There’s a lot of people that I think would really appreciate your content.
    Please let me know. Cheers

Comments are closed.