Fl_Text_Display Not updating on MacOS 10.11.6 El Capitan

27 views
Skip to first unread message

Rob McDonald

unread,
Nov 22, 2016, 3:51:40 PM11/22/16
to fltk.general
I have some code that has a Fl_Text_Display

Fl_Text_Display *display;

This is set up with an appropriate Fl_Text_Buffer.

Later on, I have a method like this:

void myClass::AddOutputText( const string &text )
{
  display->buffer()->append( text.c_str() );
  display->move_down();
  display->show_insert_position();

  Fl::flush();

  printf( "%s", text.c_str() );
}

This method gets called frequently to update a status console as the program runs.  The whole point is to produce a 'live streaming' output.  The printf code is not there in production -- just for testing.  This code (or some much like it) has worked great for years over many FLTK versions, on Windows, Mac, and Linux.

Recently, I updated to OSX 10.11.6 and this doesn't work anymore.  I updated FLTK to 1.3.4 in case there was already a fix for this -- but that did not change behavior.

On 10.11.6, nothing is output to the Fl_Text_Display until this part of the program stops running.  The printf still outputs as expected (so the problem is not with the data getting to this point in a timely manner).

It behaves as-if the OS is ignoring the call to Fl::flush().

I've tried surrounding the above calls in Fl::lock()/unlock() with no change in observed behavior.

Any ideas?

Rob

Martin McDonough

unread,
Nov 22, 2016, 3:59:56 PM11/22/16
to fltk.general
Perhaps adding a call to redraw() on the widget would help. I am not sure if that should be necessary or not in this case.

Greg Ercolano

unread,
Nov 22, 2016, 4:21:33 PM11/22/16
to fltkg...@googlegroups.com
On 11/22/16 12:51, Rob McDonald wrote:
> I have some code that has a Fl_Text_Display
>
> Fl_Text_Display *display;
>
> This is set up with an appropriate Fl_Text_Buffer.
>
> Later on, I have a method like this:
>
> void myClass::AddOutputText( const string &text )
> {
> display->buffer()->append( text.c_str() );
> display->move_down();
> display->show_insert_position();
>
> Fl::flush();
>
> printf( "%s", text.c_str() );
> }

I'd get rid of the Fl::flush() -- no need to call that unless
you're not planning on returning to the event loop.

Use display->redraw() either in your method, or at a higher level.

The reason widgets don't automatically call redraw() is so that
if you're in a tight loop appending a lot of strings,
it doesn't add the overhead of calling redraw() each time.

Rob McDonald

unread,
Nov 22, 2016, 4:44:31 PM11/22/16
to fltk.general
Thanks for the prompt reply.

I've changed the code to redraw() instead of Fl::flush() -- no observable change in behavior.  It still doesn't display to the screen as the data is pushed.

Rob


 

Albrecht Schlosser

unread,
Nov 22, 2016, 5:41:01 PM11/22/16
to fltkg...@googlegroups.com
On 22.11.2016 22:44 Rob McDonald wrote:
> On Tuesday, November 22, 2016 at 1:21:33 PM UTC-8, Greg Ercolano wrote:
>
> On 11/22/16 12:51, Rob McDonald wrote:
> > I have some code that has a Fl_Text_Display
> > ...
> > void myClass::AddOutputText( const string &text )
> > {
> > display->buffer()->append( text.c_str() );
> > display->move_down();
> > display->show_insert_position();
> >
> > Fl::flush();
> >
> > printf( "%s", text.c_str() );
> > }
>
> I'd get rid of the Fl::flush() -- no need to call that unless
> you're not planning on returning to the event loop.
>
> Use display->redraw() either in your method, or at a higher
> level.
>
> The reason widgets don't automatically call redraw() is so that
> if you're in a tight loop appending a lot of strings,
> it doesn't add the overhead of calling redraw() each time.
>
>
> Thanks for the prompt reply.
>
> I've changed the code to redraw() instead of Fl::flush() -- no
> observable change in behavior. It still doesn't display to the screen
> as the data is pushed.

I can only agree with others: Fl::flush() is the wrong method, calling
redraw() on the widget is correct.

Background: redraw() marks the widget "dirty", Fl::flush() draws
everything that was marked "dirty". Fl::flush() is called in the event
loop anyway, so there's no need to call it usually, unless you do your
own event handling or a very long callback.

That said, I don't know why this code doesn't work on this particular
version of MacOS. I'd check the nesting of the widgets, because it can
have strange effects if child widgets if child widgets are not entirely
inside their parents' bounding box (x,y,w,h). If this is not correct and
it worked before that my just have been lucky.

What I would check:

(1) Does the fixed code with redraw() work on the older MacOS platforms?

(2) Does it work on other OS's (Windows, Linux with X11)?

(3) Can you strip this code down to a simple but complete, compileable
example program that still shows the effect and can post it here? You
could add test data in a timer event to the Fl_Text_Display.

(4) And, last but not least, can you also test with FLTK 1.4.0? There
are weekly snapshots you can download. This is maybe the easiest test.

Rob McDonald

unread,
Nov 23, 2016, 11:59:45 AM11/23/16
to fltk.general, Albrech...@online.de
On Tuesday, November 22, 2016 at 2:41:01 PM UTC-8, Albrecht Schlosser wrote:
I can only agree with others: Fl::flush() is the wrong method, calling
redraw() on the widget is correct.

Background: redraw() marks the widget "dirty", Fl::flush() draws
everything that was marked "dirty". Fl::flush() is called in the event
loop anyway, so there's no need to call it usually, unless you do your
own event handling or a very long callback.

That said, I don't know why this code doesn't work on this particular
version of MacOS. I'd check the nesting of the widgets, because it can
have strange effects if child widgets if child widgets are not entirely
inside their parents' bounding box (x,y,w,h). If this is not correct and
it worked before that my just have been lucky.

What I would check:

(1) Does the fixed code with redraw() work on the older MacOS platforms?

No, interestingly switching to redraw() on my old Mac makes it have the 'problem' behavior.

This seems like our most informational test.  What would cause a flush() to work, but not a redraw()?


(2) Does it work on other OS's (Windows, Linux with X11)?

I haven't tried it yet (can only test those on a VM) -- suspect answer to (1) is sufficient.
 
(3) Can you strip this code down to a simple but complete, compileable
example program that still shows the effect and can post it here? You
could add test data in a timer event to the Fl_Text_Display.

I'll work on it, but seems like it will be easier to build up an example from zero -- if that example doesn't show the behavior, then I'll be in a tough spot.
 
(4) And, last but not least, can you also test with FLTK 1.4.0? There
are weekly snapshots you can download. This is maybe the easiest test.

I'll work on that also.

This GUI is built programmatically, so I can't visually check the bounding boxes of the widgets in FLUID.  From inspecting the code, I think it is correct -- and we don't generally have problems with events working up/down the hierarchy.

I modified the code to trigger each Fl_Group::redraw() up the hierarchy (starting at the deepest nested level, adding the parent each test) until I got all the way up to the containing Fl_Double_Window.  The behavior still does not work as desired.  Even with all the redraw()s _and_ a flush(), it doesn't update.


Rob 

Rob McDonald

unread,
Nov 23, 2016, 2:29:24 PM11/23/16
to fltk.general, Albrech...@online.de
Forcing a Fl::wait() seems to 'correct' the problem.  This seems like a terrible hack (so I'm hesitant to put it into production) but perhaps it will help the gurus help figure this out.

The code is now like this:

display->buffer()->append( text.c_str() );

display->move_down();

display->show_insert_position();

display->redraw();

Fl::wait();



Rob

Ian MacArthur

unread,
Nov 23, 2016, 4:08:13 PM11/23/16
to fltkg...@googlegroups.com
On Wed Nov 23 2016 19:29:24, Rob McDonald wrote:

Forcing a Fl::wait() seems to 'correct' the problem.  This seems like a terrible hack (so I'm hesitant to put it into production) but perhaps it will help the gurus help figure this out.

The code is now like this:

display->buffer()->append( text.c_str() );

display->move_down();

display->show_insert_position();

display->redraw();

Fl::wait();


Fl::wait() basically just calls Fl::flush() though, in large part, so it’s not clear that’s really all that different... Curious.

Rob, do you have a minimal compileable example that exhibits this behaviour?

I’m wondering of there’s some strange interaction in the widget hierarchy or something that is triggering this.




Albrecht Schlosser

unread,
Nov 23, 2016, 4:51:14 PM11/23/16
to fltkg...@googlegroups.com
It looks as if you're not returning from a timer callback or an idle
callback for a longer time. If that is the case then the Fl::flush()
call that is done after processing all events in the normal event loop
is obviously not called, hence no drawing at all.

You can test if this theory is true:

(1) events would not be serviced while your text display is missing
updates (draws) although your printf() or other output statements
indicate that the text display is (was) modified

(2) the text display would refresh once the action that is blocking the
event loop (long running timer or idle callback) finishes.

> (2) Does it work on other OS's (Windows, Linux with X11)?
>
>
> I haven't tried it yet (can only test those on a VM) -- suspect
> answer to (1) is sufficient.
>
>
> (3) Can you strip this code down to a simple but complete,
> compileable
> example program that still shows the effect and can post it
> here? You
> could add test data in a timer event to the Fl_Text_Display.
>
> I'll work on it, but seems like it will be easier to build up an
> example from zero -- if that example doesn't show the behavior, then
> I'll be in a tough spot.

You'd likely do it differently and it wouldn't expose the same bad
behavior. Or maybe it would, depending on how similar you can rebuild
your existing code.

> (4) And, last but not least, can you also test with FLTK 1.4.0?
> There
> are weekly snapshots you can download. This is maybe the easiest
> test.
>
> I'll work on that also.
>
> This GUI is built programmatically, so I can't visually check the
> bounding boxes of the widgets in FLUID. From inspecting the code, I
> think it is correct -- and we don't generally have problems with
> events working up/down the hierarchy.
>
> I modified the code to trigger each Fl_Group::redraw() up the
> hierarchy (starting at the deepest nested level, adding the parent
> each test) until I got all the way up to the containing
> Fl_Double_Window. The behavior still does not work as desired.
> Even with all the redraw()s _and_ a flush(), it doesn't update.
>
>
> Forcing a Fl::wait() seems to 'correct' the problem. This seems like a
> terrible hack (so I'm hesitant to put it into production) but perhaps it
> will help the gurus help figure this out.

Yep, this supports my theory that you don't leave your
(whatever-type-of) callback so the normal FLTK event loop is blocked. I
hope there are no threads involved. That would open even more options to
do it wrong and to exhibit strange effects.

> The code is now like this:
>
> display->buffer()->append( text.c_str() );
>
> display->move_down();
>
> display->show_insert_position();
>
> display->redraw();
>
> Fl::wait();

Fl::wait() processes pending events and calls Fl::flush() after all
events have been processed. This should not be necessary here. If it
makes the code work then because it "heals" another bug.

We need more information about how your code above is called (timeout
event, idle callback?) and how long it runs. If it runs in a loop with
multiple display updates w/o _leaving_ this loop to return to the FLTK
event loop then _this_ is the culprit. All callbacks (even idle
callbacks[1]) must return as soon as possible to let the FLTK event loop
handle events and eventually call Fl::flush() to draw everything that
was changed.

Please check if this is the case. If it is, then this code will behave
similar (bad) on all platforms, and the fact that it seemed to work was
only good luck. Note: this is only an educated guess without knowing
your complete code, but I hope we're coming closer to the root cause...

-------------------
[1] idle callbacks should run only a few milliseconds, never more than
about 50-100ms before they return to the FLTK event loop to let FLTK
service pending events. Otherwise event handling would stall. When all
pending events are done FLTK will call the idle callback again. Your
code looks very similar to something that might be done in an idle callback.

Rob McDonald

unread,
Nov 25, 2016, 10:49:55 AM11/25/16
to fltk.general, Albrech...@online.de
I am certainly guilty of doing too much in the main thread.  In this case, the user presses a button that sets off a calculation (seconds to minutes) that runs right in the main thread.

I know this is naive, but we've been OK with naive for a while.  It causes the program to block (won't accept button presses, spinny wheel / hourglass, etc.) but -- this console kept updating to give the user some idea of progress.

The 'right' fix is to spawn off a thread and run this task in the background.  However, that is more invasive a change than I want to take on right now.

I didn't realize that the updating I was seeing was unexpected - interesting that an OS update would change that behavior (that we've observed on Mac, Linux, and Windows for at least ~10 years).

Thanks for all the help,

Rob


 
Reply all
Reply to author
Forward
0 new messages