Recent

Author Topic: bug with application idle event  (Read 1159 times)

robert rozee

  • New Member
  • *
  • Posts: 35
bug with application idle event
« on: September 05, 2021, 10:57:09 am »
hi,
    have just noticed an 'interesting' behaviour with TApplicationProperties.OnIdle events - see attached example project [REMOVED - SEE UPDATED ATTACHMENT IN Reply #5]

in an application i'm working on, within a Timer event i am generating quite a bit of work which is (under certain extreme conditions) 'swamping' the LCL and causing the application's GUI to become non-responsive. the solution i've found for this is to have an OnIdle event handler set a timestamp every time it is called. if my Timer event handler sees this timestamp fall more than 100ms behind, it starts skipping (ie, if idle timestamp is >100ms old, then exit). this, on the whole, works quite well and keeps the rest of the application responsive.

the problem is, if a dialog itself creates a popup question - for example, TSaveDialog pops up a box asking about overwriting a file - then the OnIdle event handler stops being called until the popup question is closed. the attached example project demonstrates this. Label1 indicates OnIdle activity. click on Button1 to bring up SaveDIalog1, select a file that already exists, and when you click 'Save' a popup question is generated asking "A file named xxxx.xxx" already exists.  Do you want to replace it?". at this point, the counter displayed in Label1 freezes (indicating OnIdle is no longer being called), and stays frozen until the popup question box closes.

is this a bug with OnIdle? with the TSaveDialog? i would have thought that OnIdle should continue being called throughout the whole time the TSaveDialog is open, even if focus is diverted to a popup question.


cheers,
rob   :-)
« Last Edit: September 06, 2021, 01:59:14 am by robert rozee »

PascalDragon

  • Hero Member
  • *****
  • Posts: 3391
  • Compiler Developer
Re: bug with application idle event
« Reply #1 on: September 05, 2021, 11:12:09 am »
I assume that you're on Windows. In that case those popup dialogs are created by the Windows side of the dialog and that runs a separate, modal message loop which will lead to the message loop of the original application no longer receiving messages until that loop is left.

robert rozee

  • New Member
  • *
  • Posts: 35
Re: bug with application idle event
« Reply #2 on: September 05, 2021, 11:35:44 am »
oops, i keep forgetting to mention - i'm running linux.

timer events in my main program do keep on running (as one would expect), so the message loop of the original application is certainly still doing something!

cheers,
rob   :-)

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 714
Re: bug with application idle event
« Reply #3 on: September 05, 2021, 06:59:46 pm »
Message loop is blocked, if you don't exit message handler. I guess, you create dialog inside some event handler. Most event handlers are actually message handlers or handlers, that are called by other message handlers. If you block them - whole message loop is blocked. Dialog is modal window, that don't exit, till it's closed. And OnIdle is called, when no massages are currently pending in message queue.
« Last Edit: September 05, 2021, 09:48:48 pm by Mr.Madguy »
07.10.2021 - Major bug is fixed in main project, that was causing random crashes in 64bit version.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 12 years old.

robert rozee

  • New Member
  • *
  • Posts: 35
Re: bug with application idle event
« Reply #4 on: September 05, 2021, 10:38:07 pm »
if you run the example project, you'll see that the OnIdle event handler is being called repeatedly while the SaveDialog is initially displayed. this implies the message loop is not blocked, yes?

the OnIdle handler only stops running when/while a further popup is active, asking you to confirm if it is ok to overwrite the selected file.

meanwhile (not shown in the example), a TTimer will continue to run throughout, even when the OnIdle stops.

i'll put together another example project to demonstrate.


cheers,
rob   :-)

robert rozee

  • New Member
  • *
  • Posts: 35
Re: bug with application idle event
« Reply #5 on: September 06, 2021, 01:46:40 am »
here is an updated example project. there is a TTimer added, and both OnTimer and OnIdle events now just increment counters displayed on Form1 - so you can see the repetition rate of each of the events. these counters are displayed with appropriate labels (see attached image).

1. upon running, both counters can be observed on Form1 as counting up.

2. upon clicking the 'dialog' button a Save Dialog is shown, and both counters still continue to count up. this tells us Form1's message loop is running.

3. upon selecting an existing file in the Save DIalog and then clicking 'Save' the following happens:
        a. a popup question dialog is generated asking "A file named xxxx.xxx" already exists.  Do you want to replace it?",
        b. the OnIdle counter displayed on Form1 STOPS,
        c. the OnTimer counter continues counting up, suggesting that Form1's message loop is still running. however, OnIdle is no longer being called.

4. if you then click 'Cancel' on the popup question dialog:
        a. the popup question dialog closes,
        b. the OnIdle counter displayed on Form1 RESUMES COUNTING UP,
        c. focus is returned to the Save Dialog.


i can see no good reason why OnIdle events should be suspended, especially when the OnTimer events continue without interruption.


cheers,
rob   :-)

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 714
Re: bug with application idle event
« Reply #6 on: September 06, 2021, 08:35:20 am »
You can also notice, that counting stops, when you drag any window (at least on Windows). It happens exactly because some events block event loop, i.e. don't return till some moment. It most likely happens with confirmation dialog, because it's simple message box modal window. OnTimer isn't blocked, because timer may have separate event mechanism, that doesn't involve message loop. For example SetTimer has option to use callback instead of WM_TIMER message. It's usually good thing to avoid using threads, because they complicate things, but if you need to implement 100% uninterruptible background process - then it's better to learn how to use them.
« Last Edit: September 06, 2021, 08:39:49 am by Mr.Madguy »
07.10.2021 - Major bug is fixed in main project, that was causing random crashes in 64bit version.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 12 years old.

robert rozee

  • New Member
  • *
  • Posts: 35
Re: bug with application idle event
« Reply #7 on: September 06, 2021, 03:02:03 pm »
you have prompted me to try with:

ShowMessage('Show Message')
this blocks the OnIdle events.


InputQuery('Input Query', ' prompt',S) 

this DOES NOT block OnIdle events.


cheers,
rob   :-)

Mr.Madguy

  • Hero Member
  • *****
  • Posts: 714
Re: bug with application idle event
« Reply #8 on: September 10, 2021, 12:02:35 pm »
That may happen, because ShowMessage can use native dialogue (at least on Windows it's true, not sure about Linux), while InputQuery is implemented via FPC itself.
07.10.2021 - Major bug is fixed in main project, that was causing random crashes in 64bit version.
My project still requires full Delphi 2009 support to be ported to Lazarus.
It's time to finally do it, because Delphi 2009 is 12 years old.

MarkMLl

  • Hero Member
  • *****
  • Posts: 3234
Re: bug with application idle event
« Reply #9 on: September 10, 2021, 01:11:05 pm »
I've seen the same sort of behaviour Robert (OP) reports, Debian x86_64 Linux with KDE and gtk2.

The program was already fairly complex, with commands being entered interactively through something that looked like a terminal pane plus a thread for serial comms, another for network activity and so on. I ended up moving an increasing amount of stuff into another background thread with almost all GUI activity via Synchronize(), eventually everything was able to run asynchronously but I suspect that it's a bit of a nightmare from the POV of maintenance.

Part of the problem was originally caused by a change in behaviour between (some versions of) Delphi and (current versions of) Lazarus. I'd need to check other code that I've converted, but if my recollection is correct under Delphi it was possible to start code running by using a PostMessage() in the main form's OnCreate handler and it didn't block the GUI, while under Lazarus if you do the same using an async message the GUI blocks when- e.g.- a dialogue is displayed.

When I was last working on this I was wondering whether treating the OnIdle event as a collection of coroutines would help. After @Warfley's good work in this area perhaps I ought to try to revisit it.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018