diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc index 276d889006d1..ea3024191e97 100644 --- a/atom/browser/api/atom_api_auto_updater.cc +++ b/atom/browser/api/atom_api_auto_updater.cc @@ -87,16 +87,14 @@ void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) { void AutoUpdater::QuitAndInstall() { // If we don't have any window then quitAndInstall immediately. - WindowList* window_list = WindowList::GetInstance(); - if (window_list->empty()) { + if (WindowList::IsEmpty()) { auto_updater::AutoUpdater::QuitAndInstall(); return; } // Otherwise do the restart after all windows have been closed. - window_list->AddObserver(this); - for (NativeWindow* window : *window_list) - window->Close(); + WindowList::AddObserver(this); + WindowList::CloseAllWindows(); } // static diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index b18ab7b70fd7..b2900a326ff3 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -43,11 +43,10 @@ void Browser::Quit() { if (!is_quiting_) return; - atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->empty()) + if (atom::WindowList::IsEmpty()) NotifyAndShutdown(); - - window_list->CloseAllWindows(); + else + atom::WindowList::CloseAllWindows(); } void Browser::Exit(mate::Arguments* args) { @@ -65,14 +64,12 @@ void Browser::Exit(mate::Arguments* args) { is_exiting_ = true; // Must destroy windows before quitting, otherwise bad things can happen. - atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->empty()) { + if (atom::WindowList::IsEmpty()) { Shutdown(); } else { // Unlike Quit(), we do not ask to close window, but destroy the window // without asking. - for (NativeWindow* window : *window_list) - window->CloseContents(nullptr); // e.g. Destroy() + atom::WindowList::DestroyAllWindows(); } } } diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index 4dd799dfaf02..f569040a2189 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -16,9 +16,7 @@ namespace atom { void Browser::Focus() { // Focus on the first visible window. - WindowList* list = WindowList::GetInstance(); - for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) { - NativeWindow* window = *iter; + for (const auto& window : WindowList::GetWindows()) { if (window->IsVisible()) { window->Focus(true); break; diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 51604e377cd6..38a0a003d968 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -204,9 +204,8 @@ std::string Browser::DockGetBadgeText() { } void Browser::DockHide() { - WindowList* list = WindowList::GetInstance(); - for (WindowList::iterator it = list->begin(); it != list->end(); ++it) - [(*it)->GetNativeWindow() setCanHide:NO]; + for (const auto& window : WindowList::GetWindows()) + [window->GetNativeWindow() setCanHide:NO]; ProcessSerialNumber psn = { 0, kCurrentProcess }; TransformProcessType(&psn, kProcessTransformToUIElementApplication); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index af32a2e8a85a..316cc8dc2e3d 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -104,8 +104,7 @@ NativeWindow::~NativeWindow() { // static NativeWindow* NativeWindow::FromWebContents( content::WebContents* web_contents) { - WindowList& window_list = *WindowList::GetInstance(); - for (NativeWindow* window : window_list) { + for (const auto& window : WindowList::GetWindows()) { if (window->web_contents() == web_contents) return window; } diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index d627f6d1206b..374389e0a786 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -26,6 +26,16 @@ WindowList* WindowList::GetInstance() { return instance_; } +// static +WindowList::WindowVector WindowList::GetWindows() { + return GetInstance()->windows_; +} + +// static +bool WindowList::IsEmpty() { + return GetInstance()->windows_.empty(); +} + // static void WindowList::AddWindow(NativeWindow* window) { DCHECK(window); @@ -76,6 +86,13 @@ void WindowList::CloseAllWindows() { window->Close(); } +// static +void WindowList::DestroyAllWindows() { + WindowVector windows = GetInstance()->windows_; + for (const auto& window : windows) + window->CloseContents(nullptr); // e.g. Destroy() +} + WindowList::WindowList() { } diff --git a/atom/browser/window_list.h b/atom/browser/window_list.h index d9b307352e90..e336c8073dc8 100644 --- a/atom/browser/window_list.h +++ b/atom/browser/window_list.h @@ -19,23 +19,9 @@ class WindowListObserver; class WindowList { public: typedef std::vector WindowVector; - typedef WindowVector::iterator iterator; - typedef WindowVector::const_iterator const_iterator; - // Windows are added to the list before they have constructed windows, - // so the |window()| member function may return NULL. - const_iterator begin() const { return windows_.begin(); } - const_iterator end() const { return windows_.end(); } - - iterator begin() { return windows_.begin(); } - iterator end() { return windows_.end(); } - - bool empty() const { return windows_.empty(); } - size_t size() const { return windows_.size(); } - - NativeWindow* get(size_t index) const { return windows_[index]; } - - static WindowList* GetInstance(); + static WindowVector GetWindows(); + static bool IsEmpty(); // Adds or removes |window| from the list it is associated with. static void AddWindow(NativeWindow* window); @@ -51,7 +37,12 @@ class WindowList { // Closes all windows. static void CloseAllWindows(); + // Destroy all windows. + static void DestroyAllWindows(); + private: + static WindowList* GetInstance(); + WindowList(); ~WindowList(); diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 301d6ae4bf47..9a9b4334bceb 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -137,6 +137,16 @@ describe('app module', function () { done() }) }) + + it('closes all windows', function (done) { + var appPath = path.join(__dirname, 'fixtures', 'api', 'exit-closes-all-windows-app') + var electronPath = remote.getGlobal('process').execPath + appProcess = ChildProcess.spawn(electronPath, [appPath]) + appProcess.on('close', function (code) { + assert.equal(code, 123) + done() + }) + }) }) describe('app.relaunch', function () { diff --git a/spec/fixtures/api/exit-closes-all-windows-app/main.js b/spec/fixtures/api/exit-closes-all-windows-app/main.js new file mode 100644 index 000000000000..c97d8d1f195b --- /dev/null +++ b/spec/fixtures/api/exit-closes-all-windows-app/main.js @@ -0,0 +1,19 @@ +const {app, BrowserWindow} = require('electron') + +const windows = [] + +function createWindow (id) { + const window = new BrowserWindow({show: false}) + window.loadURL(`data:,window${id}`) + windows.push(window) +} + +app.once('ready', () => { + for (let i = 1; i <= 5; i++) { + createWindow(i) + } + + setImmediate(function () { + app.exit(123) + }) +}) diff --git a/spec/fixtures/api/exit-closes-all-windows-app/package.json b/spec/fixtures/api/exit-closes-all-windows-app/package.json new file mode 100644 index 000000000000..ae52532315a3 --- /dev/null +++ b/spec/fixtures/api/exit-closes-all-windows-app/package.json @@ -0,0 +1,4 @@ +{ + "name": "electron-exit-closes-all-windows", + "main": "main.js" +}