Stuck in XNextEvent


#1

Here is a strange issue that so far I have not been able to understand. On some setups, my application receive timer events only when those events follow a “regular” X event. For example I get timer events only when I move my mouse over the gui, if I stop moving the mouse, timer events just don’t come anymore.

On other setups, the gui seems fine except that on some occasions, when the mouse is idle for some time, the application also stops receiving timer events, and the “hourglass” cursor shows up. When I move the mouse, everything goes back to normal.

After looking a bit more into juce code, I can say that the problem happens inside the “XNextEvent” call of juce_dispatchNextMessageOnSystemQueue . It looks like it is just not taking care of the XClientMessageEvents sent by the juce_postMessageToSystemQueue function. It is not losing any message, just at some time the “pipe” seems to be stuck, and then a mouse event happens (or any other x11 event) , and the events flow again.

Could this be a threading issue ? I could not find any definitive information about what is thread-safe and what is not thread-safe with xlib … what exactly does the XInitThreads call ? when should the XLockDisplay and XUnlockDisplay be done ? I have been reading and re-reading those awful manpages of xlib and outdated web pages and they just don’t say anything useful.

Could this be just a bug in xlib or xserver ?

Putting XFlush and XSync calls everywhere does not seem to help.

Here is a short program that exhibits the problem (with latest juce svn r717 or any older version):

[code]//g++ -o ~/plop -I juce -DLINUX juceurl.cc juce/bin/libjuce_debug.a -lX11 -lXinerama -lfreetype -lGL -lasound
#include <juce.h>
#include

class App : public JUCEApplication, Timer
{
int old_t;
public:
void initialise (const String& commandLine) {
old_t = Time::getMillisecondCounter();
startTimer(50);
}
void shutdown() {}
const String getApplicationName() { return T(“plop”); }
void timerCallback() {
int now = Time::getMillisecondCounter();
std::cerr << “timer !, dt=” << now - old_t << “\n”;
old_t = now;
}
};

START_JUCE_APPLICATION (App)
[/code]

On some computers where everything is fine , the program calls its timer every ~50 ms.
On others, the program gets stuck at the startup (for 2 seconds, somethings for 18 seconds…). It is also affected when I launch a second instance.

Very strange.

So far, my only workaround is to replace the XNextEvent by a version that has a timeout:

/* an XNextEvent that does not block forever when no event seems to come */ bool juce_XNextEventOrTimeout(Display *display, XEvent *evt, int timeout_ms) { bool pending = XPending(display); if (!pending) { struct timeval tv; tv.tv_sec=0; tv.tv_usec=timeout_ms * 1000; int fd = XConnectionNumber(display); fd_set readset; FD_ZERO(&readset); FD_SET(fd, &readset); select( fd+1, &readset, 0, 0, &tv ); pending = XPending(display); } if (pending) { XNextEvent(display, evt); return true; } return false; }

and in juce_dispatchNextMessageOnSystemQueue:

XEvent evt; //XNextEvent (display, &evt); while (!juce_XNextEventOrTimeout (display, &evt, 400)) { if (errorCondition || breakIn) return false; }

It helps a lot, as in the worst situation the select() call will block for 400ms, and then XPending() will be called, will notice that there are some XClientMessageEvent and the next call to XNextEvent will retrieve them… However I think this fixes 98% of the issues, not 100%, on some very rare occasions the bug still happens on my application. And understanding what is going on would be far better of course…

So if anybody here has a clue, let me know !