One of the central objects in the GLib main loop is GSource. What is GSource the source of? Events. But where are the events? There is no event object, and the docs very seldom mention events (though they do frequently talk about “event sources”.) What I realized last night is that there really are events in the GLib main loop, they are just virtual: a concept without an object behind it.
A lot of the GLib main loop becomes clearer when viewed in this light: the return value of the ‘check’ and ‘prepare’ members of GSourceFuncs isn’t “TRUE if it is ready to be dispatched”, but rather “TRUE if there are any pending events for this source”. g_source_set_can_recurse() actually sets whether the source can have multiple outstanding events. Recursion becomes a whole lot more conceptually simple: we’re simply pulling more events off the event queue and processing them before we finish processing the last one.
Of course, because I didn’t realize this when I created the main loop interface in 1998, or when I revised it for GLib-2.0 in 2000, there are some places where the match isn’t exactly perfect. For example, g_main_context_dispatch() should dispatch only the single event at the front of the (virtual) event queue: instead it dispatches one event from each GSource that has pending events and who’s priority matches the priority of the highest priority GSource that has pending events. (whew!)