Merge pull request #9133 from electron/app-exit-failure

Fix app.exit() not closing all windows
This commit is contained in:
Kevin Sawicki 2017-04-11 09:49:54 -07:00 committed by GitHub
commit 964b210ce0
10 changed files with 69 additions and 37 deletions

View file

@ -87,16 +87,14 @@ void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) {
void AutoUpdater::QuitAndInstall() { void AutoUpdater::QuitAndInstall() {
// If we don't have any window then quitAndInstall immediately. // If we don't have any window then quitAndInstall immediately.
WindowList* window_list = WindowList::GetInstance(); if (WindowList::IsEmpty()) {
if (window_list->empty()) {
auto_updater::AutoUpdater::QuitAndInstall(); auto_updater::AutoUpdater::QuitAndInstall();
return; return;
} }
// Otherwise do the restart after all windows have been closed. // Otherwise do the restart after all windows have been closed.
window_list->AddObserver(this); WindowList::AddObserver(this);
for (NativeWindow* window : *window_list) WindowList::CloseAllWindows();
window->Close();
} }
// static // static

View file

@ -43,11 +43,10 @@ void Browser::Quit() {
if (!is_quiting_) if (!is_quiting_)
return; return;
atom::WindowList* window_list = atom::WindowList::GetInstance(); if (atom::WindowList::IsEmpty())
if (window_list->empty())
NotifyAndShutdown(); NotifyAndShutdown();
else
window_list->CloseAllWindows(); atom::WindowList::CloseAllWindows();
} }
void Browser::Exit(mate::Arguments* args) { void Browser::Exit(mate::Arguments* args) {
@ -65,14 +64,12 @@ void Browser::Exit(mate::Arguments* args) {
is_exiting_ = true; is_exiting_ = true;
// Must destroy windows before quitting, otherwise bad things can happen. // Must destroy windows before quitting, otherwise bad things can happen.
atom::WindowList* window_list = atom::WindowList::GetInstance(); if (atom::WindowList::IsEmpty()) {
if (window_list->empty()) {
Shutdown(); Shutdown();
} else { } else {
// Unlike Quit(), we do not ask to close window, but destroy the window // Unlike Quit(), we do not ask to close window, but destroy the window
// without asking. // without asking.
for (NativeWindow* window : *window_list) atom::WindowList::DestroyAllWindows();
window->CloseContents(nullptr); // e.g. Destroy()
} }
} }
} }

View file

@ -16,9 +16,7 @@ namespace atom {
void Browser::Focus() { void Browser::Focus() {
// Focus on the first visible window. // Focus on the first visible window.
WindowList* list = WindowList::GetInstance(); for (const auto& window : WindowList::GetWindows()) {
for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) {
NativeWindow* window = *iter;
if (window->IsVisible()) { if (window->IsVisible()) {
window->Focus(true); window->Focus(true);
break; break;

View file

@ -204,9 +204,8 @@ std::string Browser::DockGetBadgeText() {
} }
void Browser::DockHide() { void Browser::DockHide() {
WindowList* list = WindowList::GetInstance(); for (const auto& window : WindowList::GetWindows())
for (WindowList::iterator it = list->begin(); it != list->end(); ++it) [window->GetNativeWindow() setCanHide:NO];
[(*it)->GetNativeWindow() setCanHide:NO];
ProcessSerialNumber psn = { 0, kCurrentProcess }; ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToUIElementApplication); TransformProcessType(&psn, kProcessTransformToUIElementApplication);

View file

@ -104,8 +104,7 @@ NativeWindow::~NativeWindow() {
// static // static
NativeWindow* NativeWindow::FromWebContents( NativeWindow* NativeWindow::FromWebContents(
content::WebContents* web_contents) { content::WebContents* web_contents) {
WindowList& window_list = *WindowList::GetInstance(); for (const auto& window : WindowList::GetWindows()) {
for (NativeWindow* window : window_list) {
if (window->web_contents() == web_contents) if (window->web_contents() == web_contents)
return window; return window;
} }

View file

@ -26,6 +26,16 @@ WindowList* WindowList::GetInstance() {
return instance_; return instance_;
} }
// static
WindowList::WindowVector WindowList::GetWindows() {
return GetInstance()->windows_;
}
// static
bool WindowList::IsEmpty() {
return GetInstance()->windows_.empty();
}
// static // static
void WindowList::AddWindow(NativeWindow* window) { void WindowList::AddWindow(NativeWindow* window) {
DCHECK(window); DCHECK(window);
@ -76,6 +86,13 @@ void WindowList::CloseAllWindows() {
window->Close(); window->Close();
} }
// static
void WindowList::DestroyAllWindows() {
WindowVector windows = GetInstance()->windows_;
for (const auto& window : windows)
window->CloseContents(nullptr); // e.g. Destroy()
}
WindowList::WindowList() { WindowList::WindowList() {
} }

View file

@ -19,23 +19,9 @@ class WindowListObserver;
class WindowList { class WindowList {
public: public:
typedef std::vector<NativeWindow*> WindowVector; typedef std::vector<NativeWindow*> WindowVector;
typedef WindowVector::iterator iterator;
typedef WindowVector::const_iterator const_iterator;
// Windows are added to the list before they have constructed windows, static WindowVector GetWindows();
// so the |window()| member function may return NULL. static bool IsEmpty();
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();
// Adds or removes |window| from the list it is associated with. // Adds or removes |window| from the list it is associated with.
static void AddWindow(NativeWindow* window); static void AddWindow(NativeWindow* window);
@ -51,7 +37,12 @@ class WindowList {
// Closes all windows. // Closes all windows.
static void CloseAllWindows(); static void CloseAllWindows();
// Destroy all windows.
static void DestroyAllWindows();
private: private:
static WindowList* GetInstance();
WindowList(); WindowList();
~WindowList(); ~WindowList();

View file

@ -137,6 +137,16 @@ describe('app module', function () {
done() 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 () { describe('app.relaunch', function () {

View file

@ -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)
})
})

View file

@ -0,0 +1,4 @@
{
"name": "electron-exit-closes-all-windows",
"main": "main.js"
}