diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 30427d536be0..d1263c7e5832 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -76,7 +76,9 @@ v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { } // namespace -Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { +Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) + : disable_count_(0), + is_modal_(false) { // Use options.webPreferences to create WebContents. mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); options.Get(options::kWebPreferences, &web_preferences); @@ -294,11 +296,15 @@ bool Window::IsVisible() { } void Window::Disable() { - window_->Disable(); + ++disable_count_; + if (disable_count_ == 1) + window_->Disable(); } void Window::Enable() { - window_->Enable(); + --disable_count_; + if (disable_count_ == 0) + window_->Enable(); } bool Window::IsEnabled() { @@ -680,17 +686,43 @@ void Window::SetParentWindow(v8::Local value, } } -v8::Local Window::GetParentWindow() { +v8::Local Window::GetParentWindow() const { if (parent_window_.IsEmpty()) return v8::Null(isolate()); else return v8::Local::New(isolate(), parent_window_); } -std::vector> Window::GetChildWindows() { +std::vector> Window::GetChildWindows() const { return child_windows_.Values(isolate()); } +void Window::SetModal(bool modal, mate::Arguments* args) { + if (parent_window_.IsEmpty()) { + args->ThrowError("setModal can only be called for child window"); + return; + } + + mate::Handle parent; + if (!mate::ConvertFromV8(isolate(), GetParentWindow(), &parent)) { + args->ThrowError("Invalid parent window"); // should never happen + return; + } + + if (modal == is_modal_) + return; + + if (modal) + parent->Disable(); + else + parent->Enable(); + is_modal_ = modal; +} + +bool Window::IsModal() const { + return is_modal_; +} + v8::Local Window::GetNativeWindowHandle() { gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget(); return ToBuffer( @@ -721,8 +753,14 @@ void Window::RemoveFromParentChildWindows() { return; mate::Handle parent; - if (mate::ConvertFromV8(isolate(), GetParentWindow(), &parent)) - parent->child_windows_.Remove(ID()); + if (!mate::ConvertFromV8(isolate(), GetParentWindow(), &parent)) + return; + + parent->child_windows_.Remove(ID()); + if (IsModal()) { + parent->Enable(); + is_modal_ = false; + } } // static @@ -753,6 +791,8 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("setParentWindow", &Window::SetParentWindow) .SetMethod("getParentWindow", &Window::GetParentWindow) .SetMethod("getChildWindows", &Window::GetChildWindows) + .SetMethod("setModal", &Window::SetModal) + .SetMethod("isModal", &Window::IsModal) .SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle) .SetMethod("getBounds", &Window::GetBounds) .SetMethod("setBounds", &Window::SetBounds) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 3e53cbf65ce5..003fa5230e96 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -164,8 +164,10 @@ class Window : public mate::TrackableObject, bool IsMenuBarVisible(); void SetAspectRatio(double aspect_ratio, mate::Arguments* args); void SetParentWindow(v8::Local value, mate::Arguments* args); - v8::Local GetParentWindow(); - std::vector> GetChildWindows(); + v8::Local GetParentWindow() const; + std::vector> GetChildWindows() const; + void SetModal(bool modal, mate::Arguments* args); + bool IsModal() const; v8::Local GetNativeWindowHandle(); #if defined(OS_WIN) @@ -188,7 +190,7 @@ class Window : public mate::TrackableObject, int32_t ID() const; v8::Local WebContents(v8::Isolate* isolate); - // Helpers. + // Remove this window from parent window's |child_windows_|. void RemoveFromParentChildWindows(); #if defined(OS_WIN) @@ -201,6 +203,12 @@ class Window : public mate::TrackableObject, v8::Global parent_window_; KeyWeakMap child_windows_; + // How many times the Disable has been called. + int disable_count_; + + // Is current window modal. + bool is_modal_; + api::WebContents* api_web_contents_; std::unique_ptr window_; diff --git a/atom/common/key_weak_map.h b/atom/common/key_weak_map.h index 9c66785c41d4..009ba099c99f 100644 --- a/atom/common/key_weak_map.h +++ b/atom/common/key_weak_map.h @@ -53,7 +53,7 @@ class KeyWeakMap { } // Returns all objects. - std::vector> Values(v8::Isolate* isolate) { + std::vector> Values(v8::Isolate* isolate) const { std::vector> keys; keys.reserve(map_.size()); for (const auto& iter : map_) { diff --git a/lib/browser/api/browser-window.js b/lib/browser/api/browser-window.js index 2a85a7cb0c75..388e396844df 100644 --- a/lib/browser/api/browser-window.js +++ b/lib/browser/api/browser-window.js @@ -97,23 +97,6 @@ BrowserWindow.prototype._init = function () { }) } -BrowserWindow.prototype.setModal = function (modal) { - const parent = this.getParentWindow() - if (!parent) { - throw new Error('setModal can only be called for child window') - } - - let closeListener = () => parent.enable() - if (modal) { - parent.disable() - this.once('closed', closeListener) - this.show() - } else { - parent.enable() - this.removeListener('closed', closeListener) - } -} - BrowserWindow.getFocusedWindow = () => { for (let window of BrowserWindow.getAllWindows()) { if (window.isFocused()) return window