Xnest Buginess

Anyone that uses Xnest will have gotten annoyed when it gets confused about the modifier state and it thinks e.g. Alt is pressed when its clearly not. Given that the bug has been around forever, it was seriously gratifying to fix it last week.

And before anyone says “Xnest sucks; use Xephr“, this is actually a bug in Xephr too … 🙂

Sabayon

I’ve been been doing a lot of work changing Sabayon around so that the list of changes you make in the prototype session aren’t displayed within the prototype session itself. I think it makes a lot more sense.

Lots of work still remains to get the changes list someway usable given the limited space, though. I may have to get jrb to rescue me.

Input Focus

The details of behind input focus and X/GTK+ have always confused the
hell out of me. Its all fine and dandy when you only have to think
about GTK+ focus, but whenever I had to think about the interaction
between GTK+, the window manager and what’s actually happening at the
Xlib/Xserver level, by brain used to go to mush. I’d barely figure
out the bits neccessary to fix whatever bug I was up against and
promptly forget it all again five minutes later.

Well, this morning I have to get focus handling working with Xnest
embedded in a GTK+ window. So, I figure I’m really going to have to
understand it this time. Here’s some of the details:

  • In order for any X window to receive events of a certain type,
    you must call XSelectInput() on that window with the
    appropriate event mask.
  • When a key event is generated, the Xserver tries to find a
    client and window to deliver the event to. It starts with the
    window which contains the pointer and recurses up through its
    ancestors until it finds a window with that event selected.
  • X has the notion of “the keyboard focus window”. This is set
    using XSetInputFocus(). When a key event is generated,
    the event is propopagated as normal if the focus window contains
    the pointer, but propogation stops at the focus window. If the
    focus window doesn’t contain the pointer, the event is
    delivered directly to the focus window.
  • What’s important here is this has nothing to do with GTK+
    keyboard focus. Its more about which toplevel window is
    currently focused by the window manager, rather than which
    widget is focused within the application. The XEmbed
    spec
    more or less redefines this as the window’s “activation
    state” – i.e. if a toplevel or its descendants is the current
    keyboard focus window then the toplevel is said to be active.
  • None of this really reflects the way modern desktops and
    toolkits work. What happens in reality is that applications
    never focus themselves (i.e. XSetInputFocus()) unless
    the window manager tells it to using the WM_TAKE_FOCUS ICCCM
    ClientMessage.
  • On receipt of this message GTK+ makes a 1 pixel square window,
    located just outside the visible area of the toplevel
    window, be the keyboard focus window. That causes all
    KeyPresses to always go straight to this window (the window
    doesn’t have any descendants which can contain the pointer).
  • When this window receives an X KeyPress event, GTK+ then
    generates a GTK key press event (with the toplevel as the
    target window) and puts that on the GTK event queue.
  • At this point the event is entirely in the hands of GTK+. X
    has wiped its hands of the whole affair.
  • Each toplevel GtkWindow knows which widget within the window
    is currently focused. All the toplevel now needs to do is
    send that event onto the currently focused widget.

One last little interesting detail is how the window manager
implements click-to-focus:

  • The WM establishes a pasive grab on each unfocused toplevel
    window using XGrabButton()
  • A passive grab is where events are delivered as normal until a
    specific key or button combination is pressed and an active grab
    is established causing the event (and following events) to be
    delived to the grabbing client.
  • The WM passes GrabModeSync to XGrabButton()
    which causes all event delivery to freeze when the specific
    key/button combination is pressed.
  • So, when a user clicks on an unfocused window, all subsequent
    events are queued in the Xserver, the WM gets the ButtonPress,
    focuses the toplevel of the window which was clicked in and
    releases the event queue again using XAllowEvents()

In case its not obvious, I’m only really writing this down so there’s
less chance of me forgetting it all again 🙂

What a week …

Wow, what a week. GUADEC was excellent. Lots of interesting talks and a great buzz from everyone. I was sorry to have to leave a day early, especially since I missed Glynn’s talk which looked like a lot of fun. I’ve dumped the slides from my talk here.

The Red Hat Summit blew me away too. The whole thing was incredibly well organised and exciting to be a part of. I especially enjoyed just talking to random Red Hat customers and users etc.

The summit ended at lunchtime today, but even in that short time we had yet another cool video, inspirational talks from Bruce Mau (about the Massive Change project … what an interesting way to look at the modern world), Dr. Deepak Phatak (who has been
bringing Open Source to education in India
) and Sanjiva Weerawarana (who is heavily involved in the Sahana project which was created to solve some of the logistical problems with the Tsunami relief effort). And most importantly, the creation of the Fedora Foundation was announced.

I’m truly shattered now, though.

Debugging With Strace

I just check in a short doc explaining some tricks to use when debugging Vino.

I got a bit side tracked explaining how you can figure out what messages are being sent back and forth to the X server, just by looking at the read()s and write()s in the strace. A snippet:

[markmc@blaa ~]$ grep -rn X_QueryExtension /usr/include/X11/Xproto.h
2091:#define X_QueryExtension               98

  That's 0x62 in hex. So, we're looking for a write to the X
connection (file descriptor 3) with 0x62 as the first byte. What do ya
know:

1117012824.950683 writev(3, [{"\x62\x01\x04\x00\x06\x00\x01\x00", 8}, {"DAMAGE", 6}, {"\x00\x00", 2}], 3) = 16
1117012824.950939 read(3, "\x01\x00\x52\x00\x00\x00\x00\x00\x01\x9d\x75\xba\x00\x00"..., 32) = 32

  It's pretty clear that its QueryExtension for DAMAGE. Now, lets
figure out the event base from the reply. The format for the reply is:

typedef struct {
    BYTE type;  /* X_Reply */
    BYTE pad1;
    CARD16 sequenceNumber B16;
    CARD32 length B32; /* 0 */
    BOOL  present;
    CARD8 major_opcode;
    CARD8 first_event;
    ...
} xQueryExtensionReply;

   first_event is 11 bytes in. Looking at the read, that's 0x75. The
value of XDamageNotify is zero, so we can be 100% sure that all those
events after our NoExpose events are XDamageNotify events.

Some people might find it interesting. Others will think I’m weird and tell me to use something like xscope.

Design By Scribble

Yesterday, I finally got around to hacking up a dialog in Sabayon where you can assign profiles to users. Code-wise, I knew it was pretty trivial, but for once I decided to spend some time thinking about the UI design rather than hoping a real designer would come along and rescue me later.

So, I scribbled down a rough design, humed and hawed for a while and got hacking. I’m not totally depressed with the end result, so that’s something …

Stack Guard Page

The most interesting little tidbit I learnt from the memory usage
debugging yesterday was
about the “stack guard page”. Look at this bit in the strace:

mmap2(NULL, 10489856, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7219000
mprotect(0xb7219000, 4096, PROT_NONE)   = 0
clone(child_stack=0xb7c194c4, flags=CLONE_VM|...) = 2282

What’s going on here is that libc is mapping an area for the thread’s
stack, just before spawning thread. The interesting bit is that, using
mprotect(), it also changes the permissions on the first page
(the page at the top of the stack) such that any instruction which
attempts to write to the page will cause a segmentation fault.

That’s your stack guard page; it means that your infinitely recursing
function won’t go off an scribble over its neighbouring thread’s stack,
it’ll just segfault like a good little thread.

(In true pthreads tradition, you can even configure the size of
this guard area – see the pthread_attr_setguardsize() manpage)

Memory Usage Debugging

There’s been a lot of talk about reducing memory usage in GNOME, so
some people may be interested in the little
adventure
I had this morning tracking down a mysterious 10M that
appeared in gnome-panel’s memory map in FC4.

Update: I better clarify that to avoid misunderstandings … this is
10M of unused virtual memory, not physical memory. The kernel would
only have ever allocated a handful of physical pages in this space.
This does not mean that GNOME now uses 10M less of your RAM.