I have a window that presents a popover with a bunch of text fields. I want these text fields to be tabbable but not focused when the popover appears. To achieve this I set the first responder to nil
when the popover appears:
// Inside popover's view controller.
override func viewDidAppear() {
self.view.window!.makeFirstResponder(nil)
}
This works fine up until the point when the popover gets dismissed causing the owning window first responder being set to the window itself, not the view that was the first responder prior the popover appeared. However, if I do self.view.window!.makeFirstResponder(self.view)
or don't touch the first responder at all in the above block, everything works as expected and the owning window's first responder gets restored correctly when the popover gets dismissed.
To my knowledge changes inside the popover shouldn't affect the owning window, since popovers have own windows with own responder chains.
I'm very curious what's happening behind the scenes. Pretty sure this gets down to how the responder chain works and gets updated, but I can't connect the dots.
–––
Can anyone explain why changing the first responder inside the popover to nil
messes up the owning window's (above which it gets displayed) first responder when the popover gets dismissed? And doesn't affect it when using the aforementioned workaround?
The popover window is a child window of the owning window and shares the first responder with its parent. When the popover closes _NSPopoverCloseAndAnimate:
is called. If the first responder of the popover is a subclass of NSView
then _updateFirstResponderForIgnoredChildWindow:
is called on the owning window and it will set a first responder. If the first responder of the popover is a window then the first responder of the owning window isn't restored.
If the popover doesn't contain any views which can be first responder then the text field of the owning window stays first responder and accepts keydowns.