I'm Marnanel, and this is my blog. Well, sort of. It isn't timely like a blog, and I don't expect you to subscribe to the feed (though I won't complain if you do). Rather, treat it as a quick trot around my mind, a chat over a pint in the pub, assuming you'd be caught dead talking about software in the pub. You should start here.

Tuesday, May 29, 2007

How Metacity creates a tab list

NARGERY LEVEL: High. Not for the faint of heart.

I've been asked to explain how to add new items to the list of programs which appears when you use alt-Tab to switch between programs in Metacity. This is a bit of a simplification, but it goes like this:

When the user is switching between applications using alt-Tab, Metacity has what's called a "keyboard grab" on the X server. This means that it gets told about all the keyboard events, and no other X client hears about them. The grab is initiated by meta_display_begin_grab_op() and ended by meta_display_end_grab_op().

Everything Metacity needs to know about a screen's tab popup is kept in a MetaTabPopup called "tab_popup" which lives inside the MetaScreen representing that screen. In a newly-created MetaScreen, it's null, because there's no popup on that screen. It gets initialised by meta_display_begin_grab_op() calling meta_screen_ensure_tab_popup() (or meta_screen_ensure_workspace_popup() if we're actually needing to switch between workspaces, rather than applications), both of which call meta_ui_tab_popup_new() in order to actually allocate and initialise the memory.

Before it calls meta_ui_tab_popup_new(), however, meta_screen_ensure_tab_popup() needs to prepare a list of MetaTabEntry items to display in the popup. It does this by calling the function meta_display_get_tab_list(), which is where the magic truly lives.

meta_display_get_tab_list() returns a GList of MetaWindow objects. (meta_screen_ensure_tab_popup() converts the MetaWindows to MetaTabEntrys.) This is where the actual list of windows that you see when you press alt-Tab comes from.

Now, there are actually three kinds of list that meta_display_get_tab_list() might be asked for, and these are represented by the possible values of the MetaTabList enum parameter "type". META_TAB_LIST_NORMAL means the ordinary alt-Tab sequence you're used to, of ordinary user application windows. META_TAB_LIST_DOCKS means that what's needed is a list of system windows; you can see this in action by pressing alt-ctrl-Tab. META_TAB_LIST_GROUP means that what's needed is a list of all windows (even dialogues, etc.) in the same application group as the current window.

How do we deal with this headache-inducing complexity? meta_display_get_tab_list() does the sensible thing and delegates it (in this case, to a macro). It iterates over every window in the requested workspace and adds it to the result list if

  • it's on the same screen, and
  • the IN_TAB_CHAIN macro returns true for it. We will come back to this in a moment.
The result list is ordered firstly by whether the window's minimised (minimised windows come first, presumably because this is standard behaviour on certain other operating systems); after that, most recently used windows come first. You can verify this using alt-Tab on your own desktop.

The IN_TAB_CHAIN macro (in display.c) is written in terms of the three macros META_WINDOW_IN_*_TAB_CHAIN (in window.h). Each of these takes a single argument, a MetaWindow, and returns true or false depending on whether it's in that particular tab chain.

The original reason I was asked to explain all this was a request to add all windows (on any workspace) which have the urgency hint to any newly-created tab chain. This wouldn't be a suitable thing to add to the META_WINDOW_IN_*_TAB_CHAIN macros, because the list of windows passed to those is pre-filtered to include only windows on the current workspace. Instead, it should be added to meta_display_get_tab_list() as a separate, final step.

Sunday, May 27, 2007

Writing a Facebook application in Perl, part 2

This post has moved to marnanel.org; please click the title above to go there.

Saturday, May 26, 2007

The Marn behind the curtain

This post has moved to marnanel.org; please click the title above to go there.

Writing a Facebook application in Perl

This post has moved to marnanel.org; please click the title above to go there.

Friday, May 25, 2007

Tips: How to get function names in svn diff

There used to be a -p switch to cvs diff which would print the names of functions which had changed between your working copy and the repository. svn doesn't have the switch (why on earth not?) but you can make it spawn an external diff process and do -p that way thus:

alias svndiff="svn diff --diff-cmd diff --extensions \"-u -p\""

Put that in your .bashrc so that you can type svndiff wherever you go. Note that we use -u for unified diffs, because anything else is evil.

h/t: the KDE people.

Strings, the shameful special cases

This post has moved to marnanel.org; click the title above to go there.

Thursday, May 24, 2007

If you're going to start somewhere, this is where to start.

The year was 1999, I'd been out of college for a year and a bit, and I was working hard at my first proper programming job. I'd stayed in the same town, but everyone I knew had graduated and gone away, so there wasn't much in my life besides work, spodding and sleep. A former college housemate of mine phoned me up one day and asked how I was, and when she heard that the company secretary had been coming up to me to ask me to take time off work because I hadn't taken any in over a year and it was confusing the record-keeping, she told me that this was an insufferable situation and that steps would be taken. That weekend I found myself on a train to Lincoln.

In Lincoln I was staying at the house of my former housemate's godmother, who owned two horses: every day she would get up at the crack of dawn and go to muck them out. At first she thought I wanted to sleep in in the mornings, but I explained that clearing horseshit out of stables was so different to bug-squashing in object database servers that I would be happy to help. So every day, out I went and got very mucky.

I also learned to ride a horse for the first time. (I don't know whether I still could; perhaps it's like riding a bike and you never forget.) One of the horses was old and docile, but he wasn't not strong enough to bear me any more; the other was a proud Arab mare who induced some amount of fear to mount, especially since none of the helmets I could find around the stables fitted me, and that I had only brought sandals as footwear. But I learned to walk and trot, though I didn't stay long enough to learn cantering, and I discovered what people mean when they say dressage, and I went to a small local show in a small local field where all the horses had ribbons tied in their manes. It's a whole different world, I found, but then I suppose so is software.

I borrowed one of the ponies, whose name was Glorious George, and practiced riding him around the fields. One of the horsey people told me that George was a good choice because he knew where he was going better than I did, and wouldn't lead me into any danger. Then she said something that surprised me: The only way to learn is by hacking.

I asked her what she meant, and she told me that hacking is just fooling around. It's wandering around for no reason other than that you love riding the horse. It's trying all the things you can do riding a horse so you know what the horse and you and the pair of you together are capable of. And apparently it's the only real way to learn to ride a horse.

I was amused, because it's also the only way to learn how to use a computer, or at least how to program one. Do, please, note that I'm not talking about some kind of attempt to break into other people's computers when I talk about hacking: it's plainly immoral to damage other people's possessions without their consent. Rather, the hacking I mean is the older sense, finding out what your language and your equipment can do and pushing it to its limits because it's fun, because you're just fooling around, and it's the only way to learn. If you want to be a mediocre programmer, you can afford to hate programming. If you want to be a really good programmer, you have to push it to its limits and beyond.

The only way to learn is by hacking.

Regular expressions, part 1: why you should care

A magic circle.
It looked an extremely thorough job. Whoever had chalked it was clearly very aware that its purpose was to divide the universe into two bits, the inside and the outside.
, Terry Pratchett
This post is about regular expressions, what they do, and how they can help you.

Everyone loves strings. Most programs spend much of their time shunting them around. They're something that humans love and computers, generally, hate. I mean, they might not tell you to their face, but after hours, when you've all logged out and gone home, let me tell you, your computer is propping up a bar somewhere complaining about you and your human need for string handling.

Humans like strings because they're good for holding human language-- a field which computers, by and large, find opaque and puzzling. I'm not just talking about
Those are language, but human natural language is a vast and difficult and complicated domain which computers hate even more than strings, if that's possible. People have spent their entire lives researching ways to get computers and natural language to play along. So let's set our sights a little lower, at some simpler kinds of communication:
Wouldn't it be nice if there was a simple way of looking at a string and saying what is or isn't an ISBN, or a social security number? If there was a way of dividing the universe into two bits, the SSNs and everything else? Well, that's what regular expressions are for. A regular expression (regex, regexp, or RE to its friends) is a way of dividing all strings into strings which match and strings which don't.

Next part: how to write a regular expression.

It's the shell playing tricks behind your back

I am so old... gather round, children... I am so old that when I first started using PCs, Windows 3.0 hadn't come out yet. I played with Windows 2 at school, but let's face it, it was pretty dreadful. Every time when I logged out, it told me "This will end your Windows session": I actually cheered. So, though the Mac and Amiga users looked down their noses at us, we ended up using the DOS prompt a lot (and we was happy!)

If you don't know much about using the prompt, the idea is that you type the name of the program you want to run. So to run the program PRINT.EXE I could type:

> print

But if you want to tell the program to do something-- especially, if you want to tell it to work on a particular file, you can give it more information, or "parameters". So to tell PRINT.EXE to print a bunch of my files, I could say:

> print shopping.txt homework.txt laundry.txt

If those were the only three files ending in .txt I had, I had a shortcut. I could say:

> print *.txt

Now, I used to hack around writing my own programs in those days too, and I knew that when PRINT.EXE was run and it asked what it had been told to do, it was passed "*.txt". It had to go off and search for all the .txt files itself.

Then I went to college and everything in my world became different: not least, in that I got myself hooked on Unix and spent most of the day typing things into a DEC VT220. In Unix, you can print out all your .txt files using the lpr command (Unix commands are often as obscure as that: it stands for line printer). But if I typed

$ lpr *.txt

then when lpr started up, it would be given the names of all the text files by the shell (the program that you type commands into). It wouldn't have to search for them. It would be exactly as though I'd typed

$ lpr shopping.txt homework.txt laundry.txt

So there wasn't every need for every single program to include the searching code to turn *.txt into a list of .txt files in the current directory.

But it got cleverer, because now that the code only lived in one place we could do all sorts of fun things, not having to rely on every program out there to get it right. We could perform regular expression-like antics: say we wanted only to print all the files whose name began with S, T, or U:

$ lpr [stu]*.txt

That's one of the things the shell does behind your back, but there are others. On Unix systems there's a concept of a "home directory" where a user keeps zir own stuff. The directory is conventionally written with a tilde: ~firinel for firinel's home, ~ for your own, and so on. Well, pay no attention to the man behind the curtain: that's the shell, too. If I write

$ cat ~/dragon.txt

and my name is marnanel, it will turn into

$ cat /home/marnanel/dragon.txt

before cat even sees it. This is a cause of grief for a lot of people first getting into programming, because they attempt to open files called "~/myfile.txt"[1] and find it's not there: it's the shell which is playing tricks behind your back.

[1] But there are ways of getting the effect. In Perl you can use the glob builtin function:
open(STUFF, glob('~/myfile.txt'));