Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix app.exit() not closing all windows #9133

Merged
merged 5 commits into from Apr 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 3 additions & 5 deletions atom/browser/api/atom_api_auto_updater.cc
Expand Up @@ -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
Expand Down
13 changes: 5 additions & 8 deletions atom/browser/browser.cc
Expand Up @@ -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) {
Expand All @@ -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();
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions atom/browser/browser_linux.cc
Expand Up @@ -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;
Expand Down
5 changes: 2 additions & 3 deletions atom/browser/browser_mac.mm
Expand Up @@ -204,9 +204,8 @@
}

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);
Expand Down
3 changes: 1 addition & 2 deletions atom/browser/native_window.cc
Expand Up @@ -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;
}
Expand Down
17 changes: 17 additions & 0 deletions atom/browser/window_list.cc
Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
}

Expand Down
23 changes: 7 additions & 16 deletions atom/browser/window_list.h
Expand Up @@ -19,23 +19,9 @@ class WindowListObserver;
class WindowList {
public:
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,
// 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);
Expand All @@ -51,7 +37,12 @@ class WindowList {
// Closes all windows.
static void CloseAllWindows();

// Destroy all windows.
static void DestroyAllWindows();

private:
static WindowList* GetInstance();

WindowList();
~WindowList();

Expand Down
10 changes: 10 additions & 0 deletions spec/api-app-spec.js
Expand Up @@ -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 () {
Expand Down
19 changes: 19 additions & 0 deletions 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)
})
})
4 changes: 4 additions & 0 deletions spec/fixtures/api/exit-closes-all-windows-app/package.json
@@ -0,0 +1,4 @@
{
"name": "electron-exit-closes-all-windows",
"main": "main.js"
}