On 18.03.2015 17:42 Richard Sanders wrote:
>
> Running under Ubuntu 14.04 LTS with Unity the combination
>
> win->wait_for_expose();
> Fl::flush();
>
> did not result in the window being drawn completely. The bottom ~20
> pixel rows of the window remain undrawn (the same as without the
> Fl::flush).
>
>
> I recently had a similar problem with Debian 7.x. This problem seems to
> be a Linux (or perhaps x-windows) specific. I found no bullet proof
> solution but the most reliable in my case was:
>
> win->wait_for_expose();
> Fl::wait(5);
>
> Adjust the wait period downward until it stops working then increase by
> one. My concern about this method is that it may be machine specific
> (how will it work on an older and slower machine).
Yes, AFAICT there is no _reliable_ way to make sure a window is really
drawn other than running the event loop continuously. The problem lies
in the asynchronous event sending and handling of the X11 client and
server protocol. We're only talking about X11 (xlib) here. Other systems
work differently. What happens is something like this:
win->show(); tells the X server to create and show a window if it is the
first time show() is called on the window (it may be different if the
window is iconified). FLTK marks the window internally as "shown", but
sets a flag named "wait_for_expose" to wait until the window can be
drawn. This is also a necessary condition to give the focus to the
window or any child widget of this window, and the latter was one of the
reasons why wait_for_expose() was implemented in FLTK 1.3.3.
When the X server has created and "mapped" the window (i.e. made it
visible on the display) it sends one or more "expose events" to the
client (application). The expose events include the area of the window
that has been exposed. There can be more than one expose event though,
and this is probably what happens when the window is not fully drawn in
an app that tries to utilize win->wait_for_expose().
Usually an application program would run the FLTK event loop by calling
Fl::run() or calling Fl::wait() or Fl::check() continuously. This would
read one or more expose events and draw the areas that have been
"exposed". Hence the window will be drawn completely within a few client
server roundtrips.
If you don't run the event loop continuously, it can happen that the
first expose event is "incomplete" (the area is not the entire window).
In this case win->wait_for_expose() returns because the _first_ expose
event was received. The internal window structures are complete, and the
next call to Fl::flush() will draw everything that needs to be drawn (so
far, according to the exposed area). If the first expose event was
incomplete and there are no other expose events currently pending, then
the window will be drawn incomplete.
Calling Fl::wait(5) once may or may not help. Note that the argument (5)
is the maximum time in seconds Fl::wait() will wait for the next event
to be received. If one event arrives, this event (maybe another partial
expose event or anything unrelated like a timer or keypress) will be
serviced. If more events are queued concurrently in the event queue they
will be serviced as well before FLTK calls flush() internally and draws
everything.
Now it is easy to see what _can_ happen: if there is any event, but the
"sum" of all expose events so far does not cover the entire window, then
the window will still be drawn incomplete. You will have to call
Fl::wait() at least once more. And so on...
The bad thing is that you don't know how often you must call Fl::wait()
until all necessary expose events have been received so the window is
fully drawn.
I suggest this: if you _really_ want to make sure that your window is
drawn after show() and then do some long computations w/o calling the
FLTK event loop (Fl::wait(), Fl::check(), Fl::run()), then your best bet
would be:
int n = 10; // maximum number of Fl::wait() calls
double delta = 0.05; // maximum time to wait for events
for (int i=0; i<n; i++) {
Fl::wait(delta);
}
Tune the parameters n and delta as you need. The example given would
wait no longer than 0.5 seconds _or_ 10 different events (or groups of
events that arrive concurrently), whatever happens first.
I assume that n = 3 and delta = 0.01 might be enough on a local system
(X server on the local desktop system), but on a remote system (X server
not on the system where the application program runs so you can have
significant network delays) you might need n > 3 and delta > 0.1 or so.
I don't know, it's just an educated guess.
That said: it's always better and the only way to get a well defined
behavior to run the FLTK event loop continuously.
Anyway, I hope that this may help to understand what happens and why
windows may be drawn incomplete sometimes (if you don't run the event loop).