Is there anything which causes a dialog going from modal to not modal?

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Marilith11
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Dec 20, 2020 2:59 pm

Is there anything which causes a dialog going from modal to not modal?

Post by Marilith11 »

Hello,

without going into details: I have a dialog with a worker function executed in an Idle-Event-Handler.

If I start the dialog with ShowModal(), the worker is started with the Idle Event. Since the dialog has no button, the idea was to run it purely on Idle-Events. With every Idle-Event the worker would do something, then leave the Idle-Handler, and continue with the next Idle-Event. The entire thing is a state machine, which starts with downloading a file from the Internet (via webRequest), then reading this file and do a check of a folder (CRC check of the files in the folder), and then (depending on the results of this check) return from the Idle-Handler or continue to download update files and install them.
Every step is with a state machine, where the next step depends on the results of the previous step. Every step is a new Idle Event, which causes it, after the previous step is concluded. The sequence of Idle Events works fine. Only the Modal mode is lost, this is the problem.

This works fine, actually, the file is downloaded, and the check runs too. The state machine works. But at a certain point the entire dialog becomes non modal, despite being started with ShowModal(). For debugging I build in check with 'IsModal()' to see where it stops being modal. Starting the webrequest, receiving it (with a webRequest Handler) works fine, also the next step in the state machine runs fine, but with the third step which starts the CRC check the dialog suddenly is marked a non modal, i.e. IsModal() returns false (after reporting true twice before).

There is nothing going on in the calling window (also a dialog, and my TopWindow). It should be frozen until the dialog returns. Actually this special dialog (designed to look for and install updates to another program) is started when my program is started, also by an Idle-Event, which is only used once, and then immediately via Unbind deactivated. So when the dialog in question starts, there is only one window registered for Idle-Events, namely this dialog.

Any ideas? Is there something you cannot do because a modal dialog becomes non modal? Or maybe the correct question is: Can a modal running window receive Idle-Events and stay modal?

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Is there anything which causes a dialog going from modal to not modal?

Post by doublemax »

First of all: No, i don't know how a modal dialog can turn into a non-modal one.

However, i find your approach a little strange. I think the whole process you're describing should happen in a worker thread. And if the user should not do anything during that process, just display a wxProgressDialog.

BTW: Why is your main window also a (modal?) wxDialog. A wxFrame might be more suitable. But i don't know if this is related to your issue, it's just unusual.
Use the source, Luke!
Marilith11
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Dec 20, 2020 2:59 pm

Re: Is there anything which causes a dialog going from modal to not modal?

Post by Marilith11 »

Answering my own question, but only in part...

I had the dialog in question created on the heap, i.e MyDialog *dialog = new MyDialog(...).

Doing so had the strange problem described above. I did so to save stack space, but decided to try it on stack:
MyDialog dialog(...);
...

And - now it works fine, it stays modal if started with ShowModal()!

But - why? I am not experienced enough to understand why this happens.

Just for reference, which I forgot in my post above: I am using Visual Studio 2019, C++, and wxWidgets 3.1.5 (compiled locally with VS 2019 per nmake, worked fine). This is a 64 bit application, I am still developing in Windows 7, but it compiles and tests on my WIn10 Machine just as fine.

So - maybe anybody with more knowledge in Windows/wxWidgets has any idea?

Thank you.
Marilith11
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Dec 20, 2020 2:59 pm

Re: Is there anything which causes a dialog going from modal to not modal?

Post by Marilith11 »

doublemax wrote: Fri Dec 03, 2021 9:50 pm First of all: No, i don't know how a modal dialog can turn into a non-modal one.

However, i find your approach a little strange. I think the whole process you're describing should happen in a worker thread. And if the user should not do anything during that process, just display a wxProgressDialog.

BTW: Why is your main window also a (modal?) wxDialog. A wxFrame might be more suitable. But i don't know if this is related to your issue, it's just unusual.
Thank you for the reply:

Your question about why I used a dialog for the top window: Because I am a Newbie :) I just used the dialog because I do not need/want a menubar or a statusbar, just the window, with a close Icon in the caption. This is actually a game starter/updater, so the user either closes it with the 'X" in the Caption, or starts the game with a button, then the program stays or closes itself, which is a configurable behaviour. I could use a frame too, if it is deemed necessary. But it works fine as it is. I do not start the first (main, topframe) dialog modal, obviously. I use just Show().

Your second comment - use a worker thread: I never used threads before, I would need to study how this is done, and also I would need to communicate with the main program, and so on. So I used this method, which actually works fine. There will be a progress bar, and there are messages in a TextCtrl informing the user about the steps taken. The download and the check itself completes in around 5 seconds, then the dialog closes if there are no updates. The Idle Event method actually works fine, because the entire work is in steps, so every Idle Event causes a new step, when the step is completed the windows becomes Idle again and a new Idle Event is received, which either ends the dialog or does the next step.

What baffled me is that the dialog showed IsModal() == true for several steps and with the third Idle Event it suddenly became non modal (IsModal() == false). Since the rest of the windows/program is frozen, I cannot explain why this happens. And as I posted above, as soon as I create the dialog on the stack, and not on the heap, as I did before, the problem goes away.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Is there anything which causes a dialog going from modal to not modal?

Post by doublemax »

I still can't offer an explanation how the modal state can change. Are you sure you call IsModal() on the same window each time, and not accidentally on the main dialog in one case? In any case, whatever the reason is, i think it's in your code somewhere.

Besides, if the whole process runs in the main thread, the state machine and the idle event handlers don't make much sense anyway. You could just use a wxProgressDialog, execute all steps in a row and call wxProgressDialog::Pulse()/Update() with the status messages.

Using threads may sound difficult if you've never used them, but it's not that hard.
Use the source, Luke!
Marilith11
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Dec 20, 2020 2:59 pm

Re: Is there anything which causes a dialog going from modal to not modal?

Post by Marilith11 »

doublemax wrote: Fri Dec 03, 2021 10:32 pm I still can't offer an explanation how the modal state can change. Are you sure you call IsModal() on the same window each time, and not accidentally on the main dialog in one case? In any case, whatever the reason is, i think it's in your code somewhere.

Besides, if the whole process runs in the main thread, the state machine and the idle event handlers don't make much sense anyway. You could just use a wxProgressDialog, execute all steps in a row and call wxProgressDialog::Pulse()/Update() with the status messages.

Using threads may sound difficult if you've never used them, but it's not that hard.
Yes - I definitely use IsModal() only inside the dialog - I did put these in not because I need them functionally, I just wanted to see where the problem happened. I found out about the problem because in debug mode there was an assertion when using EndModal(..), which told me the dialog was not modal. Then I put in these 'checkpoints', with a breakpoint inside, if IsModal() == false. So I saw where it happened - with the third Idle-Event.

I will think about your remark about using a wxPrgogressDialog. I do not see how it could help at this time:
wxWebRequest is asynchonous. If I start a WebRequest, I either have to wait, or the dialog becomes idle until the webrequest Event happens. So I have a webrequest event handler connected, the first idle event starts the webrequest, and the state goes to 'Wait'. The next Idle event sees the 'Wait' state and does nothing. After some time the webrequest completes, either successful or not. If successful, I move the file to its correct place and name (stolen from the webrequest sample, btw.) and set the state to 'Check'. After this it becomes idle again, and with the resulting idle event the machine now executes the check. If the download was not okay, another state is set which tries to deal with the problem, report it, or whatever.

So the entire idea is:
Idle-Event -> do something, note what was done in a state variable, and become idle again. Next Idle Event reads the state variable and does something else, depending on the state variable, or even returns with EndModal(..).

While a webRequest is running, I do what is necessary inside the webrequest-Event-Handler, and the state is wait, so every Idle Event just returns. I do not request more Idle Events, since they are not needed.

If the webrequest is ready (good or bad) I set the state variable accordingly and the system becomes idle again, and the next Idle Event does something depending on the state variable.

I hope I could explain the idea behind it. I also thought of doing these things with a timer, but the actions (download, check, unpack) have vastly different run times, a download can take several minutes, in this time I would just need to wait for results and advance a progress gauge (like it is done in the webrequest sample). Other things like check and unpack are quite fast and more computing intensive.

In a thread I could do check and unpack actions sequentially, but while a webrequest is running I would need to communicate with the window code where the request handler is running and wait until it is ready. I am sure more experienced people will have solutions for this too, but the Idle-Mechanism was the best idea I could come up with - and it seems to work fine. Except the modal-Problem, which seems to be solved by creating the dialog on the stack...
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Is there anything which causes a dialog going from modal to not modal?

Post by doublemax »

Yes, i forgot about the asynchronous nature of webrequest, this would make my approach less straight-forward.
Except the modal-Problem, which seems to be solved by creating the dialog on the stack...
I'm very curious about this, but without some code that shows the issue, i don't know how to find an answer for this.

But as it works now for you, just be happy and continue with your project :)
Use the source, Luke!
Marilith11
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Dec 20, 2020 2:59 pm

Re: Is there anything which causes a dialog going from modal to not modal?

Post by Marilith11 »

Just a fast addition: I did replace my top level dialog with a top level frame. Rest of the program is unchanged. This was a bit of pain, btw. which is why I postponed it, but in the end it worked fine. I am using wxFormBuilder (latest version), and it turned out that you can do this without building everything again. As a side note: I used wxSmith (long time before today), and always was a bit sceptical about Formbuilder because of the need to use derived classes - but as soon one does understand it, it works very fine and it is also updated and worked on at GitHub - can recommend it.

But - with the frame as toplevel window the problem persists: Dialog becomes non modal mid execution, if it is created on the heap. If it is created at the stack it works normal as excepted.

If I find the time I will make a framework for testing this.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Is there anything which causes a dialog going from modal to not modal?

Post by ONEEYEMAN »

Hi,
Dialogs are not supposed to be created on the heap. Is there a reason you do that?

Thank you.
Post Reply