Slaving the GTK+ main loop to an external main loop



One distinct problem for ports of GTK+ to other windowing systems has
been dealing with modal operations in the windowing systems API; this
comes up for:

 - Window resizing
 - Drag and drop
 - Modal print dialogs

And so forth. While the modal operation is going on, the GTK+ main loop
is not running, so no idles or timeouts are dispatched, relayout and
repaints don't happen and so forth. There are some workarounds in the
Win32 backend code - in particular, contrary to the way other events are
handled, it handles WM_PAINT events directly out of the window
procedure. But a more general approach would be desirable.

As a strawman, we could imagine for the duration of the modal operation
running the GTK+ main loop in another thread. The problem with this is
obvious: callbacks would be dispatched in that other thread. To see how
we can refine that, let's look at how g_main_context_iteration() works.
(Aside from a few efficiency considerations, g_main_context_iteration()
uses only public API and can be reimplemented.)

In skeleton, g_main_context_iteration() looks like:

 g_main_context_acquire(context);
 g_main_context_prepare (context, ...);
 g_main_context_query (context, ...);
 g_main_context_poll (context, ...);
 g_main_context_dispatch (context); 
 g_main_context_release(context);

So all we have to do is do everything before the dispatch() step in the
thread, signal the main thread do the dispatch() call, wait for that to
complete, then continue.

Signaling the main thread is platform dependent. On Windows, we can
PostMessage() to a window created by the main thread and do the
dispatch() in the window procedure of that window. On OS X we can add a 
CFRunLoopSource to the main thread's run loop and then call 
CFRunLoopSourceSignal() on it when we are ready to dispatch.

Potential issues:

 * The prepare() and query() functions of custom main loop sources may
   not be thread safe. I think this would just have to be documented
   as a portability issue.

 * You have to know when you are entering and leaving a modal
   operation in order to start and stop the iteration in the helper
   thread. This is possible for most or all of the examples listed above
   but may not always be possible.

- Owen




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]