From b73a163ce169382b858826d45bcb541867d53423 Mon Sep 17 00:00:00 2001 From: Simone Cattaneo Date: Tue, 20 Nov 2018 12:10:38 +0100 Subject: [PATCH] fix: make 'setParentWindow' compatible under Windows --- atom/browser/api/atom_api_top_level_window.cc | 3 +- atom/browser/native_window_views.cc | 35 +++++++++++-------- docs/api/browser-window.md | 3 +- spec/api-browser-window-spec.js | 6 ---- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/atom/browser/api/atom_api_top_level_window.cc b/atom/browser/api/atom_api_top_level_window.cc index 7c9a9959ce3ca..cb34b2d5d3e47 100644 --- a/atom/browser/api/atom_api_top_level_window.cc +++ b/atom/browser/api/atom_api_top_level_window.cc @@ -671,6 +671,7 @@ void TopLevelWindow::SetParentWindow(v8::Local value, parent_window_.Reset(); window_->SetParentWindow(nullptr); } else if (mate::ConvertFromV8(isolate(), value, &parent)) { + RemoveFromParentChildWindows(); parent_window_.Reset(isolate(), value); window_->SetParentWindow(parent->window_.get()); parent->child_windows_.Set(isolate(), weak_map_id(), GetWrapper()); @@ -1061,9 +1062,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate, .SetMethod("setContentProtection", &TopLevelWindow::SetContentProtection) .SetMethod("setFocusable", &TopLevelWindow::SetFocusable) .SetMethod("setMenu", &TopLevelWindow::SetMenu) -#if !defined(OS_WIN) .SetMethod("setParentWindow", &TopLevelWindow::SetParentWindow) -#endif .SetMethod("setBrowserView", &TopLevelWindow::SetBrowserView) .SetMethod("getNativeWindowHandle", &TopLevelWindow::GetNativeWindowHandle) diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index a6db82b5d4ba6..900933cdec078 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -989,20 +989,27 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) { XSetTransientForHint( xdisplay, GetAcceleratedWidget(), parent ? parent->GetAcceleratedWidget() : DefaultRootWindow(xdisplay)); -#elif defined(OS_WIN) && defined(DEBUG) - // Should work, but does not, it seems that the views toolkit doesn't support - // reparenting on desktop. - if (parent) { - ::SetParent(GetAcceleratedWidget(), parent->GetAcceleratedWidget()); - views::Widget::ReparentNativeView(GetNativeWindow(), - parent->GetNativeWindow()); - wm::AddTransientChild(parent->GetNativeWindow(), GetNativeWindow()); - } else { - if (!GetNativeWindow()->parent()) - return; - ::SetParent(GetAcceleratedWidget(), NULL); - views::Widget::ReparentNativeView(GetNativeWindow(), nullptr); - wm::RemoveTransientChild(GetNativeWindow()->parent(), GetNativeWindow()); +#elif defined(OS_WIN) + // To set parentship between windows into Windows is better to play with the + // owner instead of the parent, as Windows natively seems to do if a parent + // is specified at window creation time. + // For do this we must NOT use the ::SetParent function, instead we must use + // the ::GetWindowLongPtr or ::SetWindowLongPtr functions with "nIndex" set + // to "GWLP_HWNDPARENT" which actually means the window owner. + HWND hwndParent = parent ? parent->GetAcceleratedWidget() : NULL; + if (hwndParent == + (HWND)::GetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT)) + return; + ::SetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT, + (LONG_PTR)hwndParent); + // Ensures the visibility + if (IsVisible()) { + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + ::GetWindowPlacement(GetAcceleratedWidget(), &wp); + ::ShowWindow(GetAcceleratedWidget(), SW_HIDE); + ::ShowWindow(GetAcceleratedWidget(), wp.showCmd); + ::BringWindowToTop(GetAcceleratedWidget()); } #endif } diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 422e252432be2..6100292f9d717 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -122,7 +122,6 @@ state is `hidden` in order to minimize power consumption. * On macOS the child windows will keep the relative position to parent window when parent window moves, while on Windows and Linux child windows will not move. -* On Windows it is not supported to change parent window dynamically. * On Linux the type of modal windows will be changed to `dialog`. * On Linux many desktop environments do not support hiding a modal window. @@ -1521,7 +1520,7 @@ On Windows it calls SetWindowDisplayAffinity with `WDA_MONITOR`. Changes whether the window can be focused. -#### `win.setParentWindow(parent)` _Linux_ _macOS_ +#### `win.setParentWindow(parent)` * `parent` BrowserWindow diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index f0d129de9ec46..86c6ec4efc44b 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -2957,12 +2957,6 @@ describe('BrowserWindow module', () => { }) describe('win.setParentWindow(parent)', () => { - before(function () { - if (process.platform === 'win32') { - this.skip() - } - }) - beforeEach(() => { if (c != null) c.destroy() c = new BrowserWindow({ show: false })