diff --git a/common/basicframe.cpp b/common/basicframe.cpp index 5af1f62a7c..645dd942bd 100644 --- a/common/basicframe.cpp +++ b/common/basicframe.cpp @@ -112,30 +112,21 @@ EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType, } +DIALOG_SHIM* findQuasiModalDialog( wxWindowList& aList ) +{ + for( wxWindowList::iterator iter = aList.begin(); iter != aList.end(); ++iter ) + { + DIALOG_SHIM* dlg = dynamic_cast( *iter ); + if( dlg && dlg->IsQuasiModal() ) + return dlg; + } + return NULL; +} + + void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event ) { - DIALOG_SHIM* dlg = NULL; - wxWindowList list = GetChildren(); - - // Quasi modal dialogs create issues (crashes) when closing Kicad. - // I am guessing they are delete too late, when deleting main frames. - // AFAIK, only these DIALOG_SHIM dialogs create such issues. - // The policy is do not allow closing Kicad if a Quasi modal dialog is open. - // (Anyway, closing without prompting the user is certainly bad, - // because an edit is in preogress) - // Therefore, iterate through the child list to find at least - // a DIALOG_SHIM opened in quasi modal mode - for( wxWindowList::iterator iter = list.begin(); iter != list.end(); ++iter ) - { - if( (dlg = dynamic_cast (*iter) ) != NULL ) - { - if( dlg->IsQuasiModal() ) - break; - else - dlg = NULL; - } - } - + DIALOG_SHIM* dlg = findQuasiModalDialog( GetChildren() ); if( dlg ) { // Happens when a quasi modal dialog is currently open. @@ -184,6 +175,13 @@ EDA_BASE_FRAME::~EDA_BASE_FRAME() bool EDA_BASE_FRAME::ProcessEvent( wxEvent& aEvent ) { + if( !IsEnabled() && IsActive() ) + { + DIALOG_SHIM* dlg = findQuasiModalDialog( GetChildren() ); + if( dlg ) + dlg->Raise(); + } + if( !wxFrame::ProcessEvent( aEvent ) ) return false; diff --git a/common/dialog_shim.cpp b/common/dialog_shim.cpp index 24d684611b..02e70db52d 100644 --- a/common/dialog_shim.cpp +++ b/common/dialog_shim.cpp @@ -565,6 +565,13 @@ int DIALOG_SHIM::ShowQuasiModal() // quasi-modal: disable only my "optimal" parent m_qmodal_parent_disabler = new WDO_ENABLE_DISABLE( parent ); +#ifdef __WXMAC__ + // Apple in its infinite wisdom will raise a disabled window before even passing + // us the event, so we have no way to stop it. Instead, we must set an order on + // the windows so that the quasi-modal will be pushed in front of the disabled + // window when it is raised. + ReparentQuasiModal(); +#endif Show( true ); m_qmodal_showing = true; diff --git a/patches/wxwidgets-3.0.2_macosx_quasimodal.patch b/patches/wxwidgets-3.0.2_macosx_quasimodal.patch new file mode 100644 index 0000000000..def460bc0a --- /dev/null +++ b/patches/wxwidgets-3.0.2_macosx_quasimodal.patch @@ -0,0 +1,66 @@ +From 0cc169ec53f5eb50e6f1e77c2f73f4631561d574 Mon Sep 17 00:00:00 2001 +From: Jeff Young +Date: Tue, 9 Jan 2018 12:04:20 +0000 +Subject: [PATCH 1/1] Backport OSX disabled-window fixes from master. + +Also adds ReparentQuasiModal() which is required for Kicad +quasi-modal dialogs. +--- + src/osx/cocoa/dialog.mm | 12 ++++++++++++ + src/osx/cocoa/window.mm | 13 ++++++++++++- + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/src/osx/cocoa/dialog.mm b/src/osx/cocoa/dialog.mm +index 8b1e48f1b4..c6b508013e 100644 +--- a/src/osx/cocoa/dialog.mm ++++ b/src/osx/cocoa/dialog.mm +@@ -44,3 +44,15 @@ + [NSApp endSheet: GetWXWindow()]; + [GetWXWindow() orderOut:GetWXWindow()]; + } ++ ++void wxDialog::ReparentQuasiModal() ++{ ++ wxTopLevelWindow* parent = static_cast(wxGetTopLevelParent(GetParent())); ++ ++ wxASSERT_MSG(parent, "QuasiModal dialogs require a parent."); ++ ++ NSWindow* parentWindow = parent->GetWXWindow(); ++ NSWindow* theWindow = GetWXWindow(); ++ ++ [parentWindow addChildWindow:theWindow ordered:NSWindowAbove]; ++} +diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm +index ede8ebf778..2366d65d6b 100644 +--- a/src/osx/cocoa/window.mm ++++ b/src/osx/cocoa/window.mm +@@ -863,6 +863,15 @@ - (BOOL) canBecomeKeyView + return NO; + } + ++- (NSView *)hitTest:(NSPoint)aPoint; ++{ ++ wxWidgetCocoaImpl* viewimpl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); ++ if ( viewimpl && viewimpl->GetWXPeer() && !viewimpl->GetWXPeer()->IsEnabled() ) ++ return nil; ++ ++ return [super hitTest:aPoint]; ++} ++ + @end // wxNSView + + // We need to adopt NSTextInputClient protocol in order to interpretKeyEvents: to work. +@@ -985,7 +994,9 @@ void wxOSX_mouseEvent(NSView* self, SEL _cmd, NSEvent *event) + if (impl == NULL) + return; + +- impl->mouseEvent(event, self, _cmd); ++ // We shouldn't let disabled windows get mouse events. ++ if (impl->GetWXPeer()->IsEnabled()) ++ impl->mouseEvent(event, self, _cmd); + } + + void wxOSX_cursorUpdate(NSView* self, SEL _cmd, NSEvent *event) +-- +2.14.3 (Apple Git-98) +