diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index b98fb46ec..514a4ca67 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -39,6 +39,62 @@ inline bool IsWindowInvalid(Window* win) return !hasWindow || !win; } +inline Window* GetEngineWindow(NSWindow* nativeWindow) +{ + WindowsManager::WindowsLocker.Lock(); + for (auto* window : WindowsManager::Windows) + { + if (window && window->GetNativePtr() == nativeWindow) + { + WindowsManager::WindowsLocker.Unlock(); + return window; + } + } + WindowsManager::WindowsLocker.Unlock(); + return nullptr; +} + +inline bool ShouldAttachToParent(const CreateWindowSettings& settings) +{ + // Cocoa child windows inherit parent z-order and minimize behavior. + // Minimizable regular windows need independent top-level window semantics. + return settings.Parent && (settings.Type != WindowType::Regular || !settings.AllowMinimize); +} + +inline bool CanMakeKeyWindow(NSWindow* window) +{ + return window && [window isVisible] && ![window isMiniaturized] && [window canBecomeKeyWindow]; +} + +inline bool IsRegularWindowWithParent(Window* window, Window* parent) +{ + return window && + !window->IsClosed() && + window->GetSettings().Type == WindowType::Regular && + window->GetSettings().Parent == parent; +} + +inline void MakeNextParentedWindowKey(NSWindow* hiddenWindow, Window* fallbackParent) +{ + if (!fallbackParent || IsWindowInvalid(fallbackParent)) + return; + + for (NSWindow* candidate in [NSApp orderedWindows]) + { + if (candidate == hiddenWindow || !CanMakeKeyWindow(candidate)) + continue; + Window* candidateWindow = GetEngineWindow(candidate); + if (!IsRegularWindowWithParent(candidateWindow, fallbackParent)) + continue; + [candidate makeKeyAndOrderFront:nil]; + return; + } + + NSWindow* parent = (NSWindow*)fallbackParent->GetNativePtr(); + if (parent != hiddenWindow && CanMakeKeyWindow(parent)) + [parent makeKeyAndOrderFront:nil]; +} + KeyboardKeys GetKey(NSEvent* event) { switch ([event keyCode]) @@ -963,7 +1019,7 @@ void MacWindow::Show() // Show NSWindow* window = (NSWindow*)_window; - if (_settings.Parent) + if (ShouldAttachToParent(_settings)) { NSWindow* parent = (NSWindow*)_settings.Parent->GetNativePtr(); [parent addChildWindow:window ordered:NSWindowAbove]; @@ -989,18 +1045,17 @@ void MacWindow::Hide() // Hide (order out doesn't work for miniaturized windows) NSWindow* window = (NSWindow*)_window; - const BOOL wasKey = [window isKeyWindow]; + const BOOL wasKey = [window isKeyWindow] || [NSApp keyWindow] == window; if ([window isMiniaturized]) [window close]; else [window orderOut:nil]; - - // Transfer focus back to the parent when hiding popup - if (_settings.Parent && wasKey && _settings.Type != WindowType::Popup && _settings.Type != WindowType::Tooltip) - { - NSWindow* parent = (NSWindow*)_settings.Parent->GetNativePtr(); - [parent makeKeyAndOrderFront:nil]; - } + const bool shouldRestoreFocus = _settings.Parent && + _settings.Type == WindowType::Regular && + [NSApp isActive] && + (wasKey || [NSApp keyWindow] == nil); + if (!IsClosed() && shouldRestoreFocus) + MakeNextParentedWindowKey(window, _settings.Parent); // Base WindowBase::Hide(); @@ -1009,23 +1064,27 @@ void MacWindow::Hide() void MacWindow::Close(ClosingReason reason) { - const BOOL wasKey = _window && [(NSWindow*)_window isKeyWindow]; + NSWindow* window = (NSWindow*)_window; + const BOOL shouldRestoreFocus = window && + _settings.Parent && + _settings.Type == WindowType::Regular && + [NSApp isActive] && + ([window isKeyWindow] || [NSApp keyWindow] == window); + WindowBase::Close(reason); // Closing can be cancelled by managed Window.Closing handlers. if (!IsClosed()) return; - if (NSWindow* window = (NSWindow*)_window) - { + if (window) [window close]; - } - - if (_settings.Parent && wasKey && _settings.Type != WindowType::Popup && _settings.Type != WindowType::Tooltip) - { - NSWindow* parent = (NSWindow*)_settings.Parent->GetNativePtr(); - [parent makeKeyAndOrderFront:nil]; - } + const bool hasNoKeyWindow = _settings.Parent && + _settings.Type == WindowType::Regular && + [NSApp isActive] && + [NSApp keyWindow] == nil; + if (shouldRestoreFocus || hasNoKeyWindow) + MakeNextParentedWindowKey(window, _settings.Parent); } void MacWindow::Minimize() diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 3a1cf0dd3..902950133 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -362,6 +362,13 @@ void WindowsWindow::BringToFront(bool force) { ASSERT(HasHWND()); + HWND hWndInsertAfter = HWND_TOP; + uint32 flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER; + if (_settings.IsTopmost) + { + hWndInsertAfter = HWND_TOPMOST; + } + if (_settings.Type == WindowType::Regular) { if (IsIconic(_handle)) @@ -372,22 +379,15 @@ void WindowsWindow::BringToFront(bool force) { SetActiveWindow(_handle); } + SetWindowPos(_handle, hWndInsertAfter, 0, 0, 0, 0, flags); } else { - HWND hWndInsertAfter = HWND_TOP; - uint32 flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER; - if (!force) { flags |= SWP_NOACTIVATE; } - if (_settings.IsTopmost) - { - hWndInsertAfter = HWND_TOPMOST; - } - SetWindowPos(_handle, hWndInsertAfter, 0, 0, 0, 0, flags); } } @@ -614,6 +614,7 @@ void WindowsWindow::SetOpacity(const float opacity) void WindowsWindow::Focus() { ASSERT(HasHWND()); + BringToFront(); if (GetFocus() != _handle) { SetFocus(_handle); @@ -1130,6 +1131,10 @@ LRESULT WindowsWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) } } break; + case WM_MOUSEACTIVATE: + if (_settings.Type == WindowType::Regular) + BringToFront(); + break; case WM_CREATE: return 0; case WM_SIZE: