issue with focus in main window after a dialog closes

472 views
Skip to first unread message

Vojtěch Bubník

unread,
Dec 3, 2021, 11:11:04 AM12/3/21
to wx-u...@googlegroups.com
Hello.

We use wxWidgets 3.1.4. For some time already we have an issue with keyboard focus. Namely, when we open a dialog from our main window, the main window gets deactivated and it loses focus. Then a modal dialog opens and once it closes, an "Activate" event is sent to the main window first. During the "Activate" event, the window is still in deactivated state (deactivated by the modal dialog event handler) while the "Activate" default handler tries to restore focus on the main window. Because the main window is deactivated, SetFocus fails (I verified on Windows only, however the behavior seems to be similar on Linux).

We seem to have such an issue on Windows and Linux, not on OSX. We used to work around the issue by issuing a CallAfter wrapped SetFocus() to our preferred widget from the OnActivate handler, however the CallAfter causes havoc with some Linux window managers with a "keyboard focus follows mouse" feature enabled. So we have overridden the Enable() function on two windows in the window hierarchy: The top most window seems to be activated / deactivated by the dialog modal loop handler, the other (non-top most window) seems to get activated by wxProgressDialog, I suppose we make this non top most window a parent of this wxProgressDialog.


I suppose another option (untested) would be to Enable() the main window from OnActivate callback handler.

I wonder whether this issue has been fixed on master, but I did a quick check of MSW specific code that I suppose is responsible for the current behavior and I did not see any new commits.

Is it a known issue?

Thanks,
Vojtech

Vadim Zeitlin

unread,
Dec 3, 2021, 1:56:37 PM12/3/21
to wx-u...@googlegroups.com
On Fri, 3 Dec 2021 17:10:50 +0100 Vojtěch Bubník wrote:

VB> We use wxWidgets 3.1.4. For some time already we have an issue with
VB> keyboard focus. Namely, when we open a dialog from our main window, the
VB> main window gets deactivated and it loses focus. Then a modal dialog opens
VB> and once it closes, an "Activate" event is sent to the main window first.
VB> During the "Activate" event, the window is still in deactivated state
VB> (deactivated by the modal dialog event handler) while the "Activate"
VB> default handler tries to restore focus on the main window. Because the main
VB> window is deactivated, SetFocus fails (I verified on Windows only, however
VB> the behavior seems to be similar on Linux).

Sorry but what exactly are you doing and why? Focus is supposed to be
restored to the control which had had it before after showing a modal
dialog in any case, so why do you have a wxEVT_ACTIVATE handler in the
first place? What happens if you simply remove it?

VB> Is it a known issue?

Unfortunately I can't really answer this before understanding what the
issue is. All I can is that it's trivially easy to confuse (especially but
not only) wxMSW by defining your own custom wxEVT_ACTIVATE and/or
wxEVT_SET_FOCUS handlers and doing anything focus-related on them, so my
advice is always to avoid doing this.

Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/

Vojtěch Bubník

unread,
Dec 4, 2021, 12:47:14 AM12/4/21
to wx-u...@googlegroups.com
Thanks Vadim for your response.

I am starting to think that the issue we are having has something to do with wxProgressDialog not playing well with the modal loop of a modal dialog. We see focus issues when we open a file open dialog, then on closing the file open dialog we start loading while showing the progress with wxProgressDialog. I will have to dig deeper.

I don't think we break the default Activate event handler. I see that the default Activate handler calls SetFocus() on the widget that had the focus before the file open dialog opened, but the window and the widget is disabled, thus SetFocus() fails.
    Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) {
        // something non-focus modifying
        event.Skip();
    });



Vadim Zeitlin

unread,
Dec 4, 2021, 9:58:49 AM12/4/21
to wx-u...@googlegroups.com
On Sat, 4 Dec 2021 06:47:00 +0100 Vojtěch Bubník wrote:

VB> I am starting to think that the issue we are having has something to do
VB> with wxProgressDialog not playing well with the modal loop of a modal
VB> dialog.

wxProgressDialog uses wxYield() internally, so it can often result in
weird problems. My recommendation would be to avoid using it at all if
possible, especially because it doesn't have a great UI neither and it's
usually better to show the progress in some wxGauge inside the main window
rather than in a separate dialog.

VB> We see focus issues when we open a file open dialog, then on
VB> closing the file open dialog we start loading while showing the progress
VB> with wxProgressDialog. I will have to dig deeper.

This is a complete shot in the dark, but you might want to use CallAfter()
to postpone showing wxProgressDialog itself, perhaps the problem --
whatever it is, as I still don't really know what is is exactly -- is due
to creating wxProgressDialog while the previous dialog still exists.

VB> I don't think we break the default Activate event handler. I see that the
VB> default Activate handler calls SetFocus() on the widget that had the focus
VB> before the file open dialog opened, but the window and the widget is
VB> disabled, thus SetFocus() fails.
VB> Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) {
VB> // something non-focus modifying
VB> event.Skip();
VB> });

Yes, this indeed shouldn't break anything.

Good luck,

Vojtěch Bubník

unread,
Dec 4, 2021, 5:44:34 PM12/4/21
to wx-u...@googlegroups.com
>  wxProgressDialog uses wxYield() internally, so it can often result in
weird problems. My recommendation would be to avoid using it at all if
possible, especially because it doesn't have a great UI neither and it's
usually better to show the progress in some wxGauge inside the main window
rather than in a separate dialog.

We need to release, thus we don't have time to do a lot of code change. We are benefitting from the wxProgressDialog blocking the rest of the application.

CallAfter() over the block of code that works with wxProgressDialog did not help. However what helped is to change the parent window of the wxProgressDialog from some child window to a top most window. From my sketchy debugging experience it seems that a modal dialog disables windows at a top most window level, while wxProgressDialog seems to disable windows at the level of the parent. Maybe it would be a good idea for wxProgressDialog to disable in the same fashion as the modal dialog?

Thanks for your time,
Vojtech

Vadim Zeitlin

unread,
Dec 5, 2021, 9:51:44 AM12/5/21
to wx-u...@googlegroups.com
On Sat, 4 Dec 2021 23:44:20 +0100 Vojtěch Bubník wrote:

VB> CallAfter() over the block of code that works with wxProgressDialog did not
VB> help. However what helped is to change the parent window of the
VB> wxProgressDialog from some child window to a top most window. From my
VB> sketchy debugging experience it seems that a modal dialog disables windows
VB> at a top most window level, while wxProgressDialog seems to disable windows
VB> at the level of the parent. Maybe it would be a good idea for
VB> wxProgressDialog to disable in the same fashion as the modal dialog?

It should already do this when wxPD_APP_MODAL flag is used. If you do use
this flag and it still doesn't work, it's probably a bug but, as usual,
we'd need some simple way of reproducing it to have a fighting chance of
actually doing anything about it.

Regards,

Vojtěch Bubník

unread,
Dec 5, 2021, 10:07:20 AM12/5/21
to wx-u...@googlegroups.com
>  It should already do this when wxPD_APP_MODAL flag is used. 

We don't set this flag, likely because the first one used wxProgressDialog without it and the others just copied it.

We will try to set this flag whether it helps. However I have to say this is quite a trap and maybe it needs to be documented that without wxPD_APP_MODAL the focus may not be restored correctly if preceded with another modal dialog.

Thanks, 
Vojtech


Vadim Zeitlin

unread,
Dec 5, 2021, 10:20:15 AM12/5/21
to wx-u...@googlegroups.com
On Sun, 5 Dec 2021 16:07:06 +0100 Vojtěch Bubník wrote:

VB> > It should already do this when wxPD_APP_MODAL flag is used.
VB>
VB> We don't set this flag, likely because the first one used wxProgressDialog
VB> without it and the others just copied it.

Without this flag the progress dialog explicitly avoids disabling the
other windows, i.e. it doesn't make itself modal.

VB> We will try to set this flag whether it helps. However I have to say this
VB> is quite a trap and maybe it needs to be documented that without
VB> wxPD_APP_MODAL the focus may not be restored correctly if preceded with
VB> another modal dialog.

To be clear, I think it's still probably a bug that it doesn't work
without wxPD_APP_MODAL because I don't see any fundamental reason for this
to happen in the case of modeless dialog neither. It's just that fixing it
(especially without breaking anything else!) could be difficult, while in
wxPD_APP_MODAL case things are slightly more straightforward.

Tony Kennedy

unread,
Dec 6, 2021, 8:54:18 AM12/6/21
to wx-users
I've had the same problem with certain modal dialogs in my application. I've been unable to figure out why some are fine but others force the parent window (a top window) to completely lose focus.

To get around the problem, I call "Raise" after the dialog is finished.

int nResult = myDialog.ShowModal();
m_pParentWindow->Raise();

Hope this helps. If I do figure out why some dialogs cause this and not others, I'll post a reply here.

Tony.





Reply all
Reply to author
Forward
0 new messages