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.