The manual page for XtAppMainLoop says that it's just a simple loop that calls XEvent event; XtAppNextEvent(app, &event); XtDispatchEvent(&event); ... until XtAppGetExitFlag() returns true. And looking at the code in libXt-1.0.9/src/Event.c seems to show that to be the case. But: XtAppNextEvent() doesn't return until there's an actual XEvent to be handled; it handles Xt-internal events (inputs, timers, signals) itself, but doesn't return (because of course, those aren't XEvents). Which means that the exit flag doesn't get a chance to break the loop until/unless there's an actual XEvent. If you're not using a Display at all in your app, you lose: timers or input sources can't signal the main loop to exit using this mechanism. A workaround -- and what I would suggest XtAppMainLoop be fixed to do instead -- is code that looks more like this: for (;;) { XtAppProcessEvent(app, XtIMAll); if (XtAppGetExitFlag(app)) break; } XtAppProcessEvent() returns when *any* event has been dispatched, not just ones that involve a Display. For the source tree, it would look something like this: void XtAppMainLoop(XtAppContext app) { LOCK_APP(app); do { XtAppProcessEvent(app, XtIMAll); } while (! app->exit_flag); UNLOCK_APP(app); } Here's some code that shows the problem: #include <X11/Intrinsic.h> static void _Tick(XtPointer baton, XtIntervalId* id) { static int count = 0; printf("%d beep!\n", ++count); XtAppContext app = (XtAppContext)baton; if (3 == count) XtAppSetExitFlag(app); else XtAppAddTimeOut(app, 3000, _Tick, app); } int main(int argc, char** argv) { XtToolkitInitialize(); XtAppContext app = XtCreateApplicationContext(); XtAppAddTimeOut(app, 3000, _Tick, app); #ifdef SHOWBUG XtAppMainLoop(app); #else for (;;) { XtAppProcessEvent(app, XtIMAll); if (XtAppGetExitFlag(app)) break; } #endif return 0; } The patch is simple: $ rcsdiff -c Event.c =================================================================== RCS file: Event.c,v retrieving revision 1.1 diff -c -r1.1 Event.c *** Event.c 2011/02/25 12:58:32 1.1 --- Event.c 2011/02/25 12:59:51 *************** *** 1553,1563 **** LOCK_APP(app); do { ! XtAppNextEvent(app, &event); ! #ifdef XTHREADS ! /* assert(app == XtDisplayToApplicationContext(event.xany.display)); */ ! #endif ! XtDispatchEvent(&event); } while(app->exit_flag == FALSE); UNLOCK_APP(app); } --- 1553,1559 ---- LOCK_APP(app); do { ! XtAppProcessEvent(app, XtIMAll); } while(app->exit_flag == FALSE); UNLOCK_APP(app); }
I don't believe libXt was ever designed, intended, or tested for use in non-GUI applications with no open display. This sounds like a request to add support for that, not a bug in failing to meet the design.
(In reply to comment #1) > I don't believe libXt was ever designed, intended, or tested > for use in non-GUI applications with no open display. It was certainly discussed (and encouraged by Consortium engineering staff) in the late 80's (X11R2 timeframe), many years before the new ExitFlag mechanism was added. If you don't want to call it a bug, it's at least inconsistent with the documentation. For what it's worth, I do believe that the addition of the XtAppContext was specifically intended to more generally support event-driven programming. Later, Tk was inspired by XtAppMainLoop() and John Ousterhaut similarly migrated Tcl_MainLoop out of the graphical Tk and into the core Tcl base. I wrote a Usenix paper in 1994 about this kind of thing: http://bitway.com/jordan/papers/USENIX/AppDev.html
I stand corrected - unfortunately, we have little information available to most developers today about what the Consortium did 20 years ago, and Xt itself is barely maintained for binary compatibility, with no one who knows much about it willing to spend time working on maintaining it.
NTL the request is reasonable. I did some tests and found no problems so we should give it a go. LibXT did not have many changes inrecent times so it is ok to start fixing more exotic problems.
This issue came up with the addition of the XtAppSetExitFlag() call; I can't tell from the history when that was added or by who. At the time, XtAppMainLoop() was changed from what it was originally to include the test for the exit flag; that's the genesis of this bug.
Looks like XtAppSetExitFlag() was added by the X Consortium for the initial X11R6.0 release in 1994 - it's in there but not in X11R5.
Ok ... so ... can we fix it? :-)
Patch submitted to xorg-devel for review: http://lists.x.org/archives/xorg-devel/2011-March/019981.html I've not seen any noticable issues with the various Xt-based apps I ran from the X.Org app/* set, but not really fully-exercised them either, or more complex apps / toolkits like Motif.
commit 42c611d9f8c80528f6e36ceb0ce245b06e8b1e8e Author: Jordan Hayes <jordan@bitway.com> Date: Sun Mar 6 11:35:47 2011 -0800 Bug 34715: XtAppMainLoop doesn't work without a Display https://bugs.freedesktop.org/show_bug.cgi?id=34715 XtAppNextEvent() doesn't return until there's an actual XEvent to be handled; it handles Xt-internal events (inputs, timers, signals) itself, but doesn't return (because of course, those aren't XEvents). Which means that the exit flag doesn't get a chance to break the loop until/unless there's an actual XEvent. Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.