RE: [fltk.general] Avoiding app freezing on window events [General Use]

246 views
Skip to first unread message

MacArthur, Ian (Leonardo, UK)

unread,
Mar 29, 2017, 10:25:40 AM3/29/17
to fltkg...@googlegroups.com
> I was wondering if there is any way to prevent an
> FLTK app from freezing on Windows OS when (for example)
> the window titlebar is clicked.


I'm not sure, but I think you are you referring to the way that windows on Windows appear to "freeze" any time you start to resize them, or even if you simply click-and-hold on the titlebar?

If so, that's a bit of a tricky one to work around, as it is not really something fltk is doing; rather it's arises from the way the Windows window manager behaves. Basically, it doesn't redraw any window that it thinks is being "adjusted" by the user, until the user finishes.

The underlying app doesn't necessarily "freeze" in this case though, they can keep on ticking away in the background; you just can't see any changes on the screen...

You can see this with the test/offscreen demo, for example. If you click and hold on the titlebar, with a good long wait, then when you release a whole slew of updated lines are "delivered at once" when the window refreshes. These are lines that were drawn "whilst the window was frozen".

This effect isn't peculiar to fltk; many Windows apps exhibit this behaviour.

That said, I have seen applications running on Windows (video apps, and maybe some games) that did seem to be able to redraw the window whilst it was being "manipulated".

I'm not sure how that is done though; it may be using an "alternative" rendering path to the screen, I suppose (e.g. DirectShow and it successor technologies) or it may simply be an attribute that can be asserted on a stock window.

If the former; tricky.
If the latter, maybe not so much...
It's pretty easy to get a Windows handle from a fltk window and then "tweak" it to suit of absolutely necessary. Needs a few #ifdef's to retain some portability of course but otherwise no too bad.







Leonardo MW 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.
********************************************************************

MacArthur, Ian (Leonardo, UK)

unread,
Mar 29, 2017, 12:33:56 PM3/29/17
to fltkg...@googlegroups.com
> I was wondering if there is any way to prevent an
> FLTK app from freezing on Windows OS when (for example)
> the window titlebar is clicked.


So I was intrigued to see what it is that Windows does that prevents updates during a drag or hold.

Turns out: It isn’t pretty... lots of folks have issues with this.

Still, you can trick it into working, sort of.

Attached, a reworked version of offscreen.cxx (for WIN32 builds only, not for OSX or X11) that should "correctly" refresh the window even whilst it is held.

At least, it works for me on Win7 at any rate.

The solution is not elegant, but may be adequate for your needs? At least it's fairly simple...

--
Ian
offscreen.cxx

Martin McDonough

unread,
Mar 29, 2017, 1:13:10 PM3/29/17
to fltk.general, ian.ma...@leonardocompany.com
Could you possibly hack around this by marking the window as non-resizable, then adding thin boxes to the edges that, when clicked, both trap the mouse to the window, and manually resize the window based on drags? It wouldn't work exactly the same as a regular window, but if that's not your main concern...

Greg Ercolano

unread,
Mar 29, 2017, 2:02:10 PM3/29/17
to fltkg...@googlegroups.com
On 03/29/17 07:25, MacArthur, Ian (Leonardo, UK) wrote:
>> I was wondering if there is any way to prevent an
>> FLTK app from freezing on Windows OS when (for example)
>> the window titlebar is clicked.
>
>
> I'm not sure, but I think you are you referring to the way
> that windows on Windows appear to "freeze" [..] if you simply
> click-and-hold on the titlebar?
>
> If so, that's a bit of a tricky one to work around, as it is
> not really something fltk is doing; rather it's arises from
> the way the Windows window manager behaves.


Hmm, not sure about that; On windows 8, if I run the fltk
clock program and click-and-drag the titlebar, the clock freezes.

But if I open either firefox or explorer and go to a page
that updates automatically, like: http://www.time.gov/ (every second),
if I click-and-drag the titlebar, the clock keeps running in
either case.

So it might be something FLTK is doing..


Ian MacArthur

unread,
Mar 29, 2017, 5:18:57 PM3/29/17
to fltkg...@googlegroups.com

> On 29 Mar 2017, at 19:02, Greg Ercolano wrote:
>
>>
>>
>> I'm not sure, but I think you are you referring to the way
>> that windows on Windows appear to "freeze" [..] if you simply
>> click-and-hold on the titlebar?
>>
>> If so, that's a bit of a tricky one to work around, as it is
>> not really something fltk is doing; rather it's arises from
>> the way the Windows window manager behaves.
>
>
> Hmm, not sure about that; On windows 8, if I run the fltk
> clock program and click-and-drag the titlebar, the clock freezes.
>
> But if I open either firefox or explorer and go to a page
> that updates automatically, like: http://www.time.gov/ (every second),
> if I click-and-drag the titlebar, the clock keeps running in
> either case.
>
> So it might be something FLTK is doing..


No, it’s definitely something Windows is doing, and perhaps an interaction with something that web browsers frequently do not do...

Specifically, when you click on the top level window, under Windows, to initiate a drag or resize operation, the WIN32 WM starts to intercept a variety of the “Window Messages" that are normally delivered to your app (whilst it manages the drag / resize functions.)

Many of the messages do still get through unmolested, e.g. WM_TIMER is not affected AFAIK. But for the duration of the drag/resize operation, no WM_PAINT messages are delivered at all.

As a result, any Windows application that depends on passing WM_PAINT messages around to control redrawing (which is the *normal* way to do things in Windows) doesn’t do any redraws.
Which is what you see with the fltk clock program for example.

The test/offscreen example illustrates this somewhat; if you click and hold the titlebar the drawing stops, but when you release the click a whole series of lines appear at once. This is because the lines are drawn in the background by the timer, and the timer still fires (WM_TIMER is not blocked) but the screen is not refreshed (WM_PAINT is blocked.)

Now, an app that contrives to manage its drawing directly, and not to depend on WM_PAINT, can continue to refresh its display during a drag/resize episode, and it seems that many browsers (because they need to manage asynchronous updates? Work cross-platform? Handle animations? Don’t know...) fall into that category, as do some games and video players.
But it’s not that common for general applications.


However, as the modified offscreen example I posted earlier shows, it’s feasible to tweak your way around this with some WIN32 specific code.

Basically, you add a message handler to spot the events that are specific to the click/hold/drag situation, and use these to add a timer event (the timer will still work because WM_TIMER etc. is not blocked) and then use this timer to trigger a refresh of the top-level window *directly* (which is the dodgy hack here) rather than by calling redraw (which doesn’t work due to WM_PAINT being blocked.)

So; it works better than I expected it would, actually, and might even be useful. I do not propose that we make it the default behaviour at this point!

Cheers,
--
Ian


MacArthur, Ian (Leonardo, UK)

unread,
Mar 30, 2017, 5:59:13 AM3/30/17
to fltkg...@googlegroups.com
> No, it’s definitely something Windows is doing...
>
> Specifically, when you click on the top level window, under Windows, to
> initiate a drag or resize operation, the WIN32 WM starts to intercept a
> variety of the “Window Messages" that are normally delivered to your
> app (whilst it manages the drag / resize functions.)


I've cleaned up the example code I did, that illustrates the workaround, and added some comments that (I hope!) clarify what it is doing and why.

As attached...

--
Ian
offscreen.cxx

Stephan Effelsberg

unread,
Apr 4, 2017, 9:29:15 AM4/4/17
to fltk.general, ian.ma...@leonardocompany.com
First an improvement to Ian's latest example code, use flush() if you know that the window is Fl_Double_Window. This removed the flickering for me.

main_window->flush();

Second there may be a much simpler approach without Windows specific code. If it is known that the window's contents are updated (we do in this example), then set a timeout to issue a redraw.
Again starting with Ian's code, remove all WIN32 stuff, make main_window a simple Fl_Double_Window* without derivation, then expand the drawing callback like this:

static void redraw_if_damaged_cb(void* arg)
{
    Fl_Double_Window* win = (Fl_Double_Window*)arg;
    if (win && win->damage()) {
        win->flush();
    }
}

static void oscr_anim(void *)
{
    os_box->oscr_drawing();
    Fl::repeat_timeout(delta_time, oscr_anim);
    if (!Fl::has_timeout(redraw_if_damaged_cb, main_window)) {
        Fl::add_timeout(0.2, redraw_if_damaged_cb, main_window);
    }
}

This means that if the window gets new contents and it is still damaged after 200 ms, then a flush() will do the trick. Everything seems to be pivoted around smartly using flush(). Tested on Win7.

And while we're at problems that occur in this special situation, let me expand the list of things that don't work then:
- Callbacks added with add_idle() and add_check() are not called.
- If a thread is running and this thread calls Fl::lock(), this call will block until the situation is "back to normal".
- If you run the program with a console attached and pin its scrollbar with the mouse, then any print to the console will block.

-- Stephan

Ian MacArthur

unread,
Apr 4, 2017, 6:02:51 PM4/4/17
to fltkg...@googlegroups.com
On Tue Apr 04 2017 13:29:07, 'Stephan Effelsberg' via fltk.general wrote:
> First an improvement to Ian's latest example code, use flush() if you know that the window is Fl_Double_Window. This removed the flickering for me.


Hmm, what platform were you testing on? I didn’t see any flickering for the updates in my test; this was on Win7 Pro on a machine thats a few years old now, with a decent (but not great) Intel GPU, so not the fastest or most capable GPU...

>
> main_window->flush();
>
> Second there may be a much simpler approach without Windows specific code.

Sure, this can work, but I think I’m generally in favour of a solution that #ifdef’s this on only for WIN32, as it is likely that other platforms do not need this code (at least, it seems OK on OSX and my X11 test box at any rate!) so having this code “always on” seems like overhead.

(Note: this isn’t entirely true either - the OSX test does sometimes “pause” whilst the window is being resized, but otherwise interacting with the WM frame does not stop the main window from refreshing. So “less bad” than the WIN32 case, not as good as X11 on my laptop...)


> If it is known that the window's contents are updated (we do in this example), then set a timeout to issue a redraw.


Again... yes, but...
In the specific example I posted, we do know that a redraw is posted, but that’s mainly because I just started with my old offscreen demo, as a simple basis for a window that animates constantly.

However, what I was trying to show was that it is possible to detect the WM_ENTERSIZEMOVE state and go into a “special mode” to deal with that circumstance specifically, which I *imagine* might allow us to keep the window refreshing even in response to events from “elsewhere” - whatever that might be...


> Again starting with Ian's code, remove all WIN32 stuff, make main_window a simple Fl_Double_Window* without derivation, then expand the drawing callback like this:
>
> static void redraw_if_damaged_cb(void* arg)
> {
> Fl_Double_Window* win = (Fl_Double_Window*)arg;
> if (win && win->damage()) {
> win->flush();
> }
> }


I think that’s a neater option than my make_current(); draw(); hack - does it work robustly? I think it should, in which case it seems safer than my way.


>
> static void oscr_anim(void *)
> {
> os_box->oscr_drawing();
> Fl::repeat_timeout(delta_time, oscr_anim);
> if (!Fl::has_timeout(redraw_if_damaged_cb, main_window)) {
> Fl::add_timeout(0.2, redraw_if_damaged_cb, main_window);
> }
> }

(Though, as noted above, I think I’d still #ifdef around the redraw_if_damaged_cb timer to make it WIN32 only...)

>
> This means that if the window gets new contents and it is still damaged after 200 ms, then a flush() will do the trick. Everything seems to be pivoted around smartly using flush(). Tested on Win7.
>
> And while we're at problems that occur in this special situation, let me expand the list of things that don't work then:
> - Callbacks added with add_idle() and add_check() are not called.

I had imagined that, once we detect the WM_ENTERSIZEMOVE state, we can probably contrive to trigger these, if we need to.

It’s possible that calling wait(...); might be enough? It should service all the timers and any pending idle callbacks, then call flush(). Assuming that wait() itself does not block, of course... Don’t have a WinXX box to hand to test this on now.


> - If a thread is running and this thread calls Fl::lock(), this call will block until the situation is "back to normal”.

I have to guess that’s happening because the main thread is holding the lock while it is itself "blocked”, but I don’t think that’s what I expect to happen.
Again, polling on wait() might get that moving again? Not sure.


> - If you run the program with a console attached and pin its scrollbar with the mouse, then any print to the console will block.

Which console were you using?
In my test, I was using the Msys console (I was building with both mingw32 and with the TDM mingw-64) and had some printf’s in there to see what was happening, and they seemed to keep on ticking even when the window was “held” (that’s basically how I figured out what the relevant events were...)
I wonder why it’s different?



Stephan Effelsberg

unread,
Apr 5, 2017, 6:02:49 AM4/5/17
to fltk.general
About the flickering ...
The window's contents flicker if I grab it (but not when using flush). I don't know which spec is important ... Win7 Pro 32 Bit, Core i3-2105, GeForce 9600 GT, FLTK1.3.4-1, both MinGW 5.1 and VStudio 2012.

About blocking printf ...
That's not specific to FLTK, but I observed this behavior when sprinkling some printfs in the code and then scrolling back while the program is running; I'm still learning after all these years. The blocking happens when I use Windows' own command shells (cmd.exe and PowerShell). MSys is not affected. As i found out, there's a key difference in the shell types. MSys only prints something if I fflush(stdout) the stream, the standard Windows shells even print without explicit flushing.

About Fl::wait() ...
Yes, that call is blocking when grabbing the window, as does Fl::check(). Passing a timeout value > 0 to Fl::wait(...) works as advertised and it times out even with a grabbed window.

About Fl::flush() ...
I missed this call, that's even more universal than Fl_Double_Window::flush(). This may come in handy for me since I can display more than one window that needs a continuous refresh (in a simulator that I use at work).

About Linux and OS X ...
I missed to run the code myself on these boxes yesterday.
You're right if you say that Windows specific code should be guarded by #ifdef _WIN32. What I meant is that no truly Windows specific code (that only compiles on Windows) might be necessary. The simple FLTK-only solution could be of general interest.

-- Stephan

Albrecht Schlosser

unread,
Apr 5, 2017, 10:26:42 AM4/5/17
to fltkg...@googlegroups.com
Hi Stephan,

[nice to see you back here]

On 05.04.2017 12:02 'Stephan Effelsberg' via fltk.general wrote:

> About blocking printf ...
> ... As i found out, there's a key
> difference in the shell types. MSys only prints something if I
> fflush(stdout) the stream, the standard Windows shells even print
> without explicit flushing.

FWIW: That's a known issue with Cygwin and MinGW/MSys (which is based on
an ancient version of Cygwin). It's not the shell itself but the runtime
system (i.e. the program) that doesn't recognize it's running in a
terminal (IIRC isatty() always returns false). You can work around this
either by explicitly flushing the output with fflush() as you wrote or
(for instance if you need it for testing) by calling

setvbuf (stdout, NULL, _IOLBF, 0);

once in main() to set stdout line buffered (_IOLBF) or unbuffered (_IONBF).

The default for a terminal (console) _should_ be line buffered, but the
MinGW/MSYS and Cygwin runtimes set the console fully buffered (_IOFBF)
for the reason above. This makes output appear only after a full buffer
(usually 4 KB or even more) has accumulated or at program exit.

HTH

PS: setvbuf() works well under MinGW, but I believe also with Visual
Studio, and of course under Linux and macOS, so you can use it on all
supported FLTK platforms.

Greg Ercolano

unread,
Apr 5, 2017, 1:49:17 PM4/5/17
to fltkg...@googlegroups.com
On 04/05/17 03:02, 'Stephan Effelsberg' via fltk.general wrote:
> About blocking printf ...
> That's not specific to FLTK, but I observed this behavior
> when sprinkling some printfs in the code and then scrolling
> back while the program is running; I'm still learning after
> all these years. The blocking happens when I use Windows'
> own command shells (cmd.exe and PowerShell). MSys is not
> affected. As i found out, there's a key difference in
> the shell types. MSys only prints something if I
> fflush(stdout) the stream, the standard Windows shells
> even print without explicit flushing.

If you use fprintf(stderr, ".."); instead of printf(),
you won't have to worry about using fflush().

Yeah, the fflush() with printf is probably C library
buffering which should be off if stdout is a tty,
but windows doesn't have a tty concept, so there's
probably some silly thing the C library is using that
isn't detecting the DOS shell correctly and buffering.

I'm guessing setvbuf() for stdout would work too
as Albrecht suggested.


MacArthur, Ian (Leonardo, UK)

unread,
May 10, 2017, 8:48:35 AM5/10/17
to fltkg...@googlegroups.com
This is *very* delayed, I forgot to post it at the time. Sorry.

I adjusted my test code to embrace the changes and observations suggested by Stephan to simplify it, remove the derived window class, with its nasty forced-redraw hack, and so forth.

This "simplified" version seems to work fine for me, and should be "portable". I'm posting it here just for completeness, in case someone finds it useful.

Cheers,
--
Ian
no-hack-offscreen.cxx
Reply all
Reply to author
Forward
0 new messages