I’ve always been a little fuzzy on the relationship between these important Gtk.Widget signals: “map”, “map-event”, “realize”, “show”, and “expose-event”. I was working on a problem with Shotwell today and realized (no pun) that I needed to intercept at least one of these to solve a UI initialization problem. Okay — which one?
They’re all related, of course. Over time I’ve gathered some notion of their order (“realize” before “map” followed at some point by “expose-event”), but what is “map-event” versus “map”? And why a “show” signal when all these other signals seem to be saying, in their own way, the same thing?
For the nth time I dug through DevHelp (no help) and the Xlib Programming Manual (which is written in some variant of Middle English — I recognize the language, fuzzily) looking for help. I finally discovered this clue by none other than Havoc Pennington:
Realize means to create the GDK resources for a widget. i.e. to instantiate the widget on the display. This is more useful once we have multiple display support in GTK.
Map means to actually pop the widget’s window onscreen. It requires the widget to be realized, since the window is created in realize.
Show means the widget should be mapped when its toplevel is mapped, or in the case of a toplevel, should be mapped immediately.
Mapping is asynchronous though; that is, gtk_widget_map() and the map signal are emitted when the map is requested. When the map actually occurs you get a map_event (distinct from plain map). But you are not allowed to draw on widgets until you get the first expose, map_event is insufficient.
I’m not saying that clears everything up, but it gave me a starting point:
realize is what takes a data structure in memory (the Widget) and allocates GDK resources (i.e. a window) for it. I’ve done a lot of network programming in my past, so I imagine this step as analogous to initializing a Session object. The Session object itself is (usually) cheap to instantiate, but can’t do much until a network connection (i.e. a socket) is created — sockets being a system resource much scarcer than heap memory.
map, as Havoc says, “pops” the window onto the display. But actually, it only requests the window be displayed. I compare this to an asynchronous connect() call. The request is initiated, but when the call returns, the circuit is not complete.
map-event is a GDK event. This is called when the window is now on-screen, i.e. the connection is complete. It’s like a callback.
expose-event is called when the window may be drawn upon, and is called thereafter whenever a portion of the window has gone dirty and must be redrawn. In network parlance, this is like a signal some stacks offer to indicate when a connection is able to send(). (This is the roughest analogy of them all.)
This leaves unrealize, unmap, and unmap-event, which look like obvious complements — signals fired during tear-down to indicate the stages of destroying the underlying window object.
I built a test application in Vala to verify some of this as well as determine the ordering of these signals for a Gtk.Window. (They might be in a different order for windowed widgets; I didn’t investigate.) This is the ordering of the events after I called show_all() on the Gtk.Window and then closed the window by clicking on the dismiss button in the chrome:
Notice that “unmap-event” was never called; this may have to do with connecting the “destroy” signal to Gtk.main_quit(). The fact that the application can exit without it being properly called is enough for me to know not to rely on it during tear-down.
Also notice that “expose-event” is called in between the “map” call and the “map-event” callback. This too is not what I expected.
And what about “show”? I understand what the virtual method is doing, but why make it a signal? Havoc explains in a follow-up:
It’s one of those weird historical things from pre-1.0.
Okay. I can accept that.
(Postscript: I know that the “expose-event” signal is deprecated in GNOME 3.0 in favor of “draw”, but I still think the above information is useful.)