From 5e61689dbffdd0ad1c7909df81acc9249234681d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 28 Feb 2016 01:24:20 +0100 Subject: [PATCH] Fix regression with MDI children accelerators Since the changes of 8034e35391db1f77842a053d2889331d35d3e17f (see #16870) accelerators, including the standard ones such as Ctrl-F4 under MSW, didn't work any longer inside the MDI children. Fix this by extending IsTopNavigationDomain() to allow for checking whether the given window should stop propagation of all keyboard events, as wxTLW does, or only TAB navigation ones as wxMDIChildFrame and wxAuiFloatingFrame do. --- include/wx/aui/floatpane.h | 2 +- include/wx/mdi.h | 16 +++++++++++++++- include/wx/toplevel.h | 2 +- include/wx/window.h | 16 +++++++++++++--- src/aui/floatpane.cpp | 16 ++++++++++++++++ src/common/containr.cpp | 2 +- src/common/toplvcmn.cpp | 16 ++++++++++++++++ src/gtk/window.cpp | 2 +- src/msw/evtloop.cpp | 8 +++----- src/osx/window_osx.cpp | 2 +- 10 files changed, 68 insertions(+), 14 deletions(-) diff --git a/include/wx/aui/floatpane.h b/include/wx/aui/floatpane.h index ea4ee3d9a1..889d2deb73 100644 --- a/include/wx/aui/floatpane.h +++ b/include/wx/aui/floatpane.h @@ -44,7 +44,7 @@ public: wxAuiManager* GetOwnerManager() const; // Allow processing accelerators to the parent frame - virtual bool IsTopNavigationDomain() const wxOVERRIDE { return false; } + virtual bool IsTopNavigationDomain(NavigationKind kind) const wxOVERRIDE; protected: virtual void OnMoveStart(); diff --git a/include/wx/mdi.h b/include/wx/mdi.h index 3ef3864730..4be67abda9 100644 --- a/include/wx/mdi.h +++ b/include/wx/mdi.h @@ -182,7 +182,21 @@ public: // In all ports keyboard navigation must stop at MDI child frame level and // can't cross its boundary. Indicate this by overriding this function to // return true. - virtual bool IsTopNavigationDomain() const wxOVERRIDE { return true; } + virtual bool IsTopNavigationDomain(NavigationKind kind) const wxOVERRIDE + { + switch ( kind ) + { + case Navigation_Tab: + return true; + + case Navigation_Accel: + // Parent frame accelerators should work inside MDI child, so + // don't block their processing by returning true for them. + break; + } + + return false; + } // Raising any frame is supposed to show it but wxFrame Raise() // implementation doesn't work for MDI child frames in most forms so diff --git a/include/wx/toplevel.h b/include/wx/toplevel.h index 1f9cb01b0b..47c5798ebc 100644 --- a/include/wx/toplevel.h +++ b/include/wx/toplevel.h @@ -246,7 +246,7 @@ public: // override some base class virtuals virtual bool Destroy() wxOVERRIDE; virtual bool IsTopLevel() const wxOVERRIDE { return true; } - virtual bool IsTopNavigationDomain() const wxOVERRIDE { return true; } + virtual bool IsTopNavigationDomain(NavigationKind kind) const wxOVERRIDE; virtual bool IsVisible() const { return IsShown(); } // event handlers diff --git a/include/wx/window.h b/include/wx/window.h index 2bd4a8a779..80938e9fb1 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -1537,13 +1537,23 @@ public: virtual wxWindow *GetMainWindowOfCompositeControl() { return (wxWindow*)this; } - // If this function returns true, keyboard navigation events shouldn't + enum NavigationKind + { + Navigation_Tab, + Navigation_Accel + }; + + // If this function returns true, keyboard events of the given kind can't // escape from it. A typical example of such "navigation domain" is a top // level window because pressing TAB in one of them must not transfer focus // to a different top level window. But it's not limited to them, e.g. MDI // children frames are not top level windows (and their IsTopLevel() - // returns false) but still are self-contained navigation domains as well. - virtual bool IsTopNavigationDomain() const { return false; } + // returns false) but still are self-contained navigation domains for the + // purposes of TAB navigation -- but not for the accelerators. + virtual bool IsTopNavigationDomain(NavigationKind WXUNUSED(kind)) const + { + return false; + } protected: diff --git a/src/aui/floatpane.cpp b/src/aui/floatpane.cpp index fbbbc05560..adebf5f7c7 100644 --- a/src/aui/floatpane.cpp +++ b/src/aui/floatpane.cpp @@ -165,6 +165,22 @@ wxAuiManager* wxAuiFloatingFrame::GetOwnerManager() const return m_ownerMgr; } +bool wxAuiFloatingFrame::IsTopNavigationDomain(NavigationKind kind) const +{ + switch ( kind ) + { + case Navigation_Tab: + break; + + case Navigation_Accel: + // Floating frames are often used as tool palettes and it's + // convenient for the accelerators defined in the parent frame to + // work in them, so don't block their propagation. + return false; + } + + return wxAuiFloatingFrameBaseClass::IsTopNavigationDomain(kind); +} void wxAuiFloatingFrame::OnSize(wxSizeEvent& WXUNUSED(event)) { diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 50bbd6aefa..c663417043 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -505,7 +505,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // even an MDI child frame, so test for this explicitly // (and in particular don't just use IsTopLevel() which // would return false in the latter case). - if ( focusedParent->IsTopNavigationDomain() ) + if ( focusedParent->IsTopNavigationDomain(wxWindow::Navigation_Tab) ) break; event.SetCurrentFocus( focusedParent ); diff --git a/src/common/toplvcmn.cpp b/src/common/toplvcmn.cpp index dd90760697..58581f6d8a 100644 --- a/src/common/toplvcmn.cpp +++ b/src/common/toplvcmn.cpp @@ -370,6 +370,22 @@ void wxTopLevelWindowBase::SetIcon(const wxIcon& icon) // event handlers // ---------------------------------------------------------------------------- +bool wxTopLevelWindowBase::IsTopNavigationDomain(NavigationKind kind) const +{ + // This switch only exists to generate a compiler warning and force us to + // revisit this code if any new kinds of navigation are added in the + // future, but for now we block of them by default (some derived classes + // relax this however). + switch ( kind ) + { + case Navigation_Tab: + case Navigation_Accel: + break; + } + + return true; +} + // default resizing behaviour - if only ONE subwindow, resize to fill the // whole client area void wxTopLevelWindowBase::DoLayout() diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index f5c91d545d..f86dbe21d3 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -1109,7 +1109,7 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), break; } - if (ancestor->IsTopNavigationDomain()) + if (ancestor->IsTopNavigationDomain(wxWindow::Navigation_Accel)) break; ancestor = ancestor->GetParent(); } diff --git a/src/msw/evtloop.cpp b/src/msw/evtloop.cpp index cb2bae0d5f..eb053cd33d 100644 --- a/src/msw/evtloop.cpp +++ b/src/msw/evtloop.cpp @@ -134,10 +134,8 @@ bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg) if ( wnd->MSWTranslateMessage((WXMSG *)msg)) return true; - // stop at first top level window, i.e. don't try to process the key - // strokes originating in a dialog using the accelerators of the parent - // frame - this doesn't make much sense - if ( wnd->IsTopNavigationDomain() ) + // stop at top navigation domain, i.e. typically a top level window + if ( wnd->IsTopNavigationDomain(wxWindow::Navigation_Accel) ) break; } @@ -151,7 +149,7 @@ bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg) // if we don't do this, pressing ESC on a modal dialog shown as child // of a modal dialog with wxID_CANCEL will cause the parent dialog to // be closed, for example - if ( wnd->IsTopNavigationDomain() ) + if ( wnd->IsTopNavigationDomain(wxWindow::Navigation_Accel) ) break; } diff --git a/src/osx/window_osx.cpp b/src/osx/window_osx.cpp index d067b0c27f..f12c025753 100644 --- a/src/osx/window_osx.cpp +++ b/src/osx/window_osx.cpp @@ -2662,7 +2662,7 @@ bool wxWindowMac::OSXHandleKeyEvent( wxKeyEvent& event ) break; } - if (ancestor->IsTopNavigationDomain()) + if (ancestor->IsTopNavigationDomain(wxWindow::Navigation_Accel)) break; ancestor = ancestor->GetParent();