Archive for December, 2007

Nargery: How to write an Epiphany extension with both hands tied behind your back

Saturday, December 29th, 2007

Disclaimer: I am nothing to do with the Epiphany project.
Disclaimer: Do not actually tie both hands behind your back without supervision.

Epiphany is the official browser of the GNOME project. Today I want to ramble at you about how easy it is to write extensions for it, because it is crazy easy. I started writing this about two person-hours ago and now it’s working, and the hardest part was getting the GTK stuff to cooperate.

So let’s write an extension. I fancy the idea of colouring the tabs according to which domain you’re looking at. There’s a nonfree extension to do this in Firefox, so let’s build our own free one. (Disclaimer: It will be pretty crap because I’m throwing it together in a few hours.)

First off, you need to declare the extension, which you do in a file ending with .ephy-extension which you put in a directory called ~/.gnome2/epiphany/extensions (it’s not rocket science, folks). Let’s call it colour-tabs.ephy-extension (because I’m British, okay)? It looks like this:

[Epiphany Extension]
Name=Colour tabs
Description=I like colour tabs
Version=0
URL=http://www.gnome.org/projects/epiphany/extensions.html

[Loader]
Type=python
Module=colour-tabs

I would go through this line by line, but I think you are clever enough that I don’t need to. The last line, though, is the name of a Python file. Create this in the same directory, as colour-tabs.py. Now, you can add functions which get called, according to their names, when various things happen in the browser. What we want to do is to be called when tabs are created (“attach_tab”) and removed (“detach_tab”):

def attach_tab(window, tab):
   embed = tab.get_embed()
   tab._colour_tab_handler = embed.connect(“net_stop”, _colour_the_tab, tab)
   # we don’t call through like this when things are loaded
   # and we should

def detach_tab(window, tab):
   if ‘_colour_tab_handler’ in tab:
      tab.get_embed().disconnect(tab._colour_tab_handler)
      del tab._colour_tab_handler

“embed” in attach_tab is the actual web page rendering engine in that tab; we are asking it to do something when an event occurs. In this case the event is “net_stop”, i.e. when the page has loaded (because let’s assume we can’t know what colour to colour the tab before the page has loaded). When that happens, we call a function to deal with the situation, which I’ll call _colour_the_tab because that’s what it does.

All detach_tab has to do, then, is look to see whether we are already waiting on this and tell it not to bother.

I added the extra comment because it would be nice to call _colour_the_tab directly if a tab is attached when a page is already loaded (this does happen occasionally, but in situations which are too complicated to go into in such a simple example).

So what do we do when the page HAS loaded? Well, that’s _colour_the_tab’s job, as I said. (Conventionally, you add a leading underscore in case it clashes with a name that Epiphany might be calling.) _colour_the_tab has three jobs:

1) the trivial job of taking the URL and finding the domain; in real life it would be better if people could specify particular colours for particular domains, etc.
2) the job of turning the domain into a colour (we just use the last six hex digits of the md5 here, which is a bad idea because it could be black!)
3) the rather fiddly job of changing the background colour of the label (this is difficult in GTK for boring reasons)

I won’t bother you with any more details here, but here’s a place you can get the code I wrote above, and I thought you might like a screenshot:

Thanks to the folks on #pygtk who helped me figure out how to set the background colour of a GtkLabel.

Update: Oh, something I forgot to mention: If you run Ephy from a terminal, and your extension uses “print”, it will go to that terminal. This makes debugging a snap compared to Firefox. Also, you almost never have to restart Epiphany. Just drop your extension in the extensions directory, turn it on from the extensions dialogue, and off you go. If you change the extension, just turn the extension off and on again and it will be reloaded. It is deeply awesome.

Really basic project tracking

Saturday, December 22nd, 2007

Lazyweb: I currently do this with a notebook (yeah, an actual paper one; I’m not sure why I don’t just write things into a text file; I have in the past). But is there a program in existence which will let me do this?

$ whatever --list-my-current-projects
metacity
fusa
workproject1
workproject2

$ whatever --start-working-on fusa

(does some work)

$ whatever --log "working on consolekit integration"

(time passes)

(gets interrupted)

$ whatever --what-the-heck-was-i-doing
working on consolekit integration

(time passes)

$ whatever --log "fixing GetWomble()"

(time passes)

$ whatever --stop-working-on fusa

$ whatever --what-have-i-worked-on-today
2007-12-22: 18:00-18:30 - fusa (30 minutes)

I know it would be pretty trivial to write; I just wondered whether it existed already so that I didn’t have to. (If it exists many times over, do you have recommendations?)

(Beyond that, it would be good to have sub-projects/sub-goals which you could mark done and so on.)

(Commit message and twitter integration would be further fun extensions.)

(Many responses received, which are getting their own post.)