From a5d719dc19cbc38566e1846bd806246704e568e9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 27 Oct 2019 01:20:39 +0200 Subject: [PATCH] Fix setting initial focus in wxOSX Previously calls to SetFocus() during construction/initialization of the parent window simply didn't do anything for windows other than wxTextCtrl because CanFocus() always returned false for them because they were not shown yet (while wxTextCtrl implementation overrides CanFocus() to always return true, probably to work around the same problem). Now use [NSView setInitialFirstResponder:] if the window is currently hidden to try to focus it when it's shown. This might still fail if the window is really not focusable (e.g. for non-text windows when full keyboard access is off), but it's not worse than what happens now, and it also may work -- unlike now. Closes #17340. --- src/osx/cocoa/window.mm | 42 +++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 748c14140b..f46386286b 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -3109,19 +3109,45 @@ bool wxWidgetCocoaImpl::HasFocus() const bool wxWidgetCocoaImpl::SetFocus() { - if ( !CanFocus() ) - { - wxLogTrace(TRACE_FOCUS, "Not setting focus to %s", wxDumpNSView(m_osxView)); - return false; - } - NSView* targetView = m_osxView; if ( [m_osxView isKindOfClass:[NSScrollView class] ] ) targetView = [(NSScrollView*) m_osxView documentView]; - wxLogTrace(TRACE_FOCUS, "Setting focus to %s", wxDumpNSView(m_osxView)); + if ( [targetView canBecomeKeyView] ) + { + wxLogTrace(TRACE_FOCUS, "Setting focus to %s", wxDumpNSView(m_osxView)); + + [[m_osxView window] makeFirstResponder: targetView] ; + } + else // can't become key view + { + // This most commonly happens because the window is still hidden, as + // canBecomeKeyView: always returns NO in this case, so schedule this + // window to become focused when it's shown later in this case. + // + // Note that this may still fail to work: if full keyboard access is + // off and this window is not a text control or similar, setting + // initial first responder won't do anything. But this is not really a + // problem and at least it will do the right thing if the window turns + // out to be focusable (i.e. it's a text control or full keyboard + // access is on). + if ( !IsVisible() ) + { + wxLogTrace(TRACE_FOCUS, "Setting initial focus to %s", + wxDumpNSView(m_osxView)); + + [[m_osxView window] setInitialFirstResponder: targetView] ; + } + else // window is shown but doesn't accept focus + { + // Not sure when exactly can this happen, for now just don't do + // anything in this case. + wxLogTrace(TRACE_FOCUS, "Not setting focus to %s", + wxDumpNSView(m_osxView)); + return false; + } + } - [[m_osxView window] makeFirstResponder: targetView] ; return true; }