RE: [fltk.general] Window Not Completely Drawn After wait_for_expose

45 views
Skip to first unread message

MacArthur, Ian (Selex ES, UK)

unread,
Mar 17, 2015, 5:30:30 AM3/17/15
to fltkg...@googlegroups.com
> In my program I have a window that launches just prior to a
> computationally expensive operation. Calling show by itself has the
> window appear completely blank at first. Calling wait_for_expose after
> calling show ensures that the window is at least partially drawn before
> the operation begins, but the bottom 20 pixels or so of the window
> remain blank and a button is cut off at half its height. If I throw in
> another 5 calls to wait I can get the window to draw completely, but I
> worry about the resilience of the solution (will it require 10 calls to
> wait if I'm running another computationally expensive operation, or 20
> calls to wait on another machine). Is there a proper way to ensure that
> all children of a window are drawn?

To be honest, if it were me, I’d put the long computation in its own child thread and let the main thread get on with servicing the GUI.

However, that may be a poor fit for your needs.

Is there a periodic loop in your long operation?
Or in any case, can you contrive to have it call Fl::check() every now and then to get the fltk core ticking over?

If you can arrange to pump the fltk core now and then by calling Fl::check(), then it all should Just Work.






Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************

Albrecht Schlosser

unread,
Mar 17, 2015, 7:19:14 AM3/17/15
to fltkg...@googlegroups.com
On 16.03.2015 23:33 Andrew Baldwin wrote:
> In my program I have a window that launches just prior to a
> computationally expensive operation. Calling show by itself has the
> window appear completely blank at first. Calling wait_for_expose after
> calling show ensures that the window is at least partially drawn before
> the operation begins, but the bottom 20 pixels or so of the window
> remain blank and a button is cut off at half its height. If I throw in
> another 5 calls to wait I can get the window to draw completely, but I
> worry about the resilience of the solution (will it require 10 calls to
> wait if I'm running another computationally expensive operation, or 20
> calls to wait on another machine). Is there a proper way to ensure that
> all children of a window are drawn?

As Ian wrote: the proper (and documented) way is to use Fl::check()
regularly. That's what it is intended for.

<http://www.fltk.org/doc-1.3/classFl.html#a1dbb83f1d52001c152ccf8415e3ee6f0>

An alternative would be to use a thread, as Ian said.

I'd like to add: wait_for_expose() makes sure that the window is
'mapped' by the WM, but maybe not (yet) fully drawn. The documentation
is not exact and can be misleading. However, the 'splash screen' example
shows that you should also use

Fl::flush(); // make sure everything gets drawn

Please report if this alone (adding Fl::flush() w/o calling Fl::check())
solves your problem. I'd like to update (clarify) the docs if you can
confirm this. TIA.

> I'm running under Ubuntu 14.04 LTS using FLTK 1.3.3 (built from the
> subversion repository).

Which desktop/WM are you using? Standard (Unity), Metacity, or anything
else? This might make a difference.

Albrecht Schlosser

unread,
Mar 17, 2015, 7:47:59 AM3/17/15
to fltkg...@googlegroups.com
On 17.03.2015 12:19 Albrecht Schlosser wrote:
> On 16.03.2015 23:33 Andrew Baldwin wrote:
>> In my program I have a window that launches just prior to a
>> computationally expensive operation. Calling show by itself has the
>> window appear completely blank at first. Calling wait_for_expose after
>> calling show ensures that the window is at least partially drawn before
>> the operation begins, but the bottom 20 pixels or so of the window
>> remain blank and a button is cut off at half its height. If I throw in
>> another 5 calls to wait I can get the window to draw completely, but I
>> worry about the resilience of the solution (will it require 10 calls to
>> wait if I'm running another computationally expensive operation, or 20
>> calls to wait on another machine). Is there a proper way to ensure that
>> all children of a window are drawn?

...

> I'd like to add: wait_for_expose() makes sure that the window is
> 'mapped' by the WM, but maybe not (yet) fully drawn. The documentation
> is not exact and can be misleading. However, the 'splash screen' example
> shows that you should also use
>
> Fl::flush(); // make sure everything gets drawn
>
> Please report if this alone (adding Fl::flush() w/o calling Fl::check())
> solves your problem. I'd like to update (clarify) the docs if you can
> confirm this. TIA.

My own tests on Ubuntu 14.04 LTS, currently with Metacity desktop/WM,
seem to indicate that only this combination:

win->wait_for_expose();
Fl::flush();

guarantees that the window gets drawn, as shown in the splash screen
example in the docs.

Calling Fl::check() regularly is recommended though to keep the
interface responsive.

Andrew Baldwin

unread,
Mar 18, 2015, 3:59:34 AM3/18/15
to fltkg...@googlegroups.com

Thanks to everyone for their suggestions.  I was hoping I could avoid the inevitable trip to threading a while longer, but it's clear that it can't be put off any longer.

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).

MacArthur, Ian (Selex ES, UK)

unread,
Mar 18, 2015, 4:56:54 AM3/18/15
to fltkg...@googlegroups.com
> Thanks to everyone for their suggestions.  I was
> hoping I could avoid the inevitable trip to threading
> a while longer, but it's clear that it can't be put
> off any longer.

Threading can be tricky to get right, so you are possibly right to try to put it off... (though I'm a big fan of threading myself, I often see problems...)

Is there really no prospect of having your long process call Fl::check() every few hundred ms, just to keep things ticking over?

Richard Sanders

unread,
Mar 18, 2015, 12:42:05 PM3/18/15
to fltkg...@googlegroups.com

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).

Albrecht Schlosser

unread,
Mar 18, 2015, 7:04:51 PM3/18/15
to fltkg...@googlegroups.com
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).

Richard Sanders

unread,
Mar 19, 2015, 2:22:16 PM3/19/15
to fltkg...@googlegroups.com
Thanks Albrecht, that certainly explains what is happening.



--
You received this message because you are subscribed to a topic in the Google Groups "fltk.general" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/fltkgeneral/hT9_6_NDUF4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to fltkgeneral+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Cheers Richard
Reply all
Reply to author
Forward
0 new messages