Skip to content

Commit

Permalink
fix: make 'setParentWindow' compatible under Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
neo291 committed Nov 20, 2018
1 parent 40619ef commit 16a7b13
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 21 deletions.
3 changes: 1 addition & 2 deletions atom/browser/api/atom_api_top_level_window.cc
Expand Up @@ -669,6 +669,7 @@ void TopLevelWindow::SetParentWindow(v8::Local<v8::Value> 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());
Expand Down Expand Up @@ -1059,9 +1060,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)
Expand Down
47 changes: 35 additions & 12 deletions atom/browser/native_window_views.cc
Expand Up @@ -71,6 +71,12 @@ namespace atom {
namespace {

#if defined(OS_WIN)
// WS_VISIBLE must not be used here, if used will systematically hide
// the window, causing bad behaviours.
static const DWORD kWindowDefaultChildStyle =
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;

void FlipWindowStyle(HWND handle, bool on, DWORD flag) {
DWORD style = ::GetWindowLong(handle, GWL_STYLE);
if (on)
Expand Down Expand Up @@ -975,20 +981,37 @@ 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.
#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.
// Is it also important to set the style according to whether it is child or
// non-child window, if not correctly set can lead to bad behaviours.
HWND hwndParent = parent ? parent->GetAcceleratedWidget() : NULL;
if (hwndParent ==
(HWND)::GetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT))
return;
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
if (parent) {
::SetParent(GetAcceleratedWidget(), parent->GetAcceleratedWidget());
views::Widget::ReparentNativeView(GetNativeWindow(),
parent->GetNativeWindow());
wm::AddTransientChild(parent->GetNativeWindow(), GetNativeWindow());
style &= ~kWindowDefaultStyle;
style |= kWindowDefaultChildStyle;
} else {
if (!GetNativeWindow()->parent())
return;
::SetParent(GetAcceleratedWidget(), NULL);
views::Widget::ReparentNativeView(GetNativeWindow(), nullptr);
wm::RemoveTransientChild(GetNativeWindow()->parent(), GetNativeWindow());
style &= ~kWindowDefaultChildStyle;
style |= kWindowDefaultStyle;
}
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
::SetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT, (LONG)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
}
Expand Down
2 changes: 1 addition & 1 deletion docs/api/browser-window.md
Expand Up @@ -1504,7 +1504,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

Expand Down
6 changes: 0 additions & 6 deletions spec/api-browser-window-spec.js
Expand Up @@ -2953,12 +2953,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 })
Expand Down

0 comments on commit 16a7b13

Please sign in to comment.