Don't reset firstResponder when a window is deactivated

Don't call makeFirstResponder:nil from windowDidResignKey: because it's
not a native behavior and subtly breaks some things (e.g. paste managers
or keyboard switched under some settings).

This was done to provide the illusion of Windows-like focus behavior
when a TLW is deactivated. macOS separates the concept of active ("key")
window and focus ("first responder") within it and it's possible and
normal to have the latter assigned even in inactive (non-key) windows.
wxOSX reset the responder to trigger wxEVT_KILL_FOCUS.

Instead, keep the first responder untouched and only run wx-side code to
handle focus lost as well as focus set in windowDidBecomeKey: This would
preserve behavior compatibility with other ports, while also playing
nice with macOS.
This commit is contained in:
Václav Slavík
2017-01-06 16:51:11 +01:00
committed by Václav Slavík
parent 5d87c70eba
commit 1a1a2ffdf8
2 changed files with 38 additions and 5 deletions

View File

@@ -492,6 +492,15 @@ extern int wxOSXGetIdFromSelector(SEL action );
wxNonOwnedWindowCocoaImpl* windowimpl = [window WX_implementation];
if ( windowimpl )
{
// See windowDidResignKey: -- we emulate corresponding focus set
// event for the first responder here as well:
NSView *firstResponder = [window firstResponder];
wxWidgetCocoaImpl *focused = firstResponder
? (wxWidgetCocoaImpl*)wxWidgetImpl::FindFromWXWidget(wxOSXGetViewFromResponder(firstResponder))
: NULL;
if ( focused )
focused->DoNotifyFocusSet();
wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
if ( wxpeer )
wxpeer->HandleActivated(0, true);
@@ -508,9 +517,16 @@ extern int wxOSXGetIdFromSelector(SEL action );
if ( wxpeer )
{
wxpeer->HandleActivated(0, false);
// as for wx the deactivation also means losing focus we
// must trigger this manually
[window makeFirstResponder:nil];
// As for wx the deactivation also means losing focus, we
// must emulate focus events _without_ resetting first responder
// (because that would subtly break other things in Cocoa/macOS):
NSView *firstResponder = [window firstResponder];
wxWidgetCocoaImpl *focused = firstResponder
? (wxWidgetCocoaImpl*)wxWidgetImpl::FindFromWXWidget(wxOSXGetViewFromResponder(firstResponder))
: NULL;
if ( focused )
focused->DoNotifyFocusLost();
// TODO Remove if no problems arise with Popup Windows
#if 0

View File

@@ -71,7 +71,24 @@ NSView* GetFocusedViewInWindow( NSWindow* keyWindow )
WXWidget wxWidgetImpl::FindFocus()
{
return GetFocusedViewInWindow( [NSApp keyWindow] );;
NSWindow *key = [NSApp keyWindow];
if ( key == nil )
{
// Application's keyWindow property may still not be updated and be
// nil when windowDidBecomeKey: is called and even if the
// just-activated's window isKeyWindow already returns YES. To get
// accurate information about where the focus is at all times, we have
// to explicitly check all application windos as well:
for ( NSWindow *w in [NSApp windows] )
{
if ( [w isKeyWindow] )
{
key = w;
break;
}
}
}
return key ? GetFocusedViewInWindow(key) : nil;
}
wxWidgetImpl* wxWidgetImpl::FindBestFromWXWidget(WXWidget control)