From da3475998f154c19d3102c26fec175b9dd4eecec Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 12 Jul 2023 17:42:24 +0200 Subject: [PATCH] fix: `BrowserWindow.moveAbove()` not working for child windows (#39034) fix: BrowserWindow.moveAbove() not working for child windows --- shell/browser/native_window_mac.mm | 53 ++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index 195a684c756..9ca838f29e1 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -162,6 +162,47 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { [self setFrame:[[self superview] bounds]]; } +// -[NSWindow orderWindow] does not handle reordering for children +// windows. Their order is fixed to the attachment order (the last attached +// window is on the top). Therefore, work around it by re-parenting in our +// desired order. +void ReorderChildWindowAbove(NSWindow* child_window, NSWindow* other_window) { + NSWindow* parent = [child_window parentWindow]; + DCHECK(parent); + + // `ordered_children` sorts children windows back to front. + NSArray* children = [[child_window parentWindow] childWindows]; + std::vector> ordered_children; + for (NSWindow* child in children) + ordered_children.push_back({[child orderedIndex], child}); + std::sort(ordered_children.begin(), ordered_children.end(), std::greater<>()); + + // If `other_window` is nullptr, place `child_window` in front of + // all other children windows. + if (other_window == nullptr) + other_window = ordered_children.back().second; + + if (child_window == other_window) + return; + + for (NSWindow* child in children) + [parent removeChildWindow:child]; + + const bool relative_to_parent = parent == other_window; + if (relative_to_parent) + [parent addChildWindow:child_window ordered:NSWindowAbove]; + + // Re-parent children windows in the desired order. + for (auto [ordered_index, child] : ordered_children) { + if (child != child_window && child != other_window) { + [parent addChildWindow:child ordered:NSWindowAbove]; + } else if (child == other_window && !relative_to_parent) { + [parent addChildWindow:other_window ordered:NSWindowAbove]; + [parent addChildWindow:child_window ordered:NSWindowAbove]; + } + } +} + } // namespace NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options, @@ -759,13 +800,21 @@ bool NativeWindowMac::MoveAbove(const std::string& sourceId) { if (!webrtc::GetWindowOwnerPid(window_id)) return false; - [window_ orderWindow:NSWindowAbove relativeTo:id.id]; + if (!parent()) { + [window_ orderWindow:NSWindowAbove relativeTo:window_id]; + } else { + NSWindow* other_window = [NSApp windowWithWindowNumber:window_id]; + ReorderChildWindowAbove(window_, other_window); + } return true; } void NativeWindowMac::MoveTop() { - [window_ orderWindow:NSWindowAbove relativeTo:0]; + if (!parent()) + [window_ orderWindow:NSWindowAbove relativeTo:0]; + else + ReorderChildWindowAbove(window_, nullptr); } void NativeWindowMac::SetResizable(bool resizable) {