Make process.exit() quit gracefully
Instead of abrupting the whole program immediately, we should close all windows and release all native resources gracefully on exit. This avoids possible crashes. Fix #3350.
This commit is contained in:
parent
c10c74b23a
commit
863199348f
8 changed files with 59 additions and 1 deletions
|
@ -339,6 +339,7 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
|||
auto browser = base::Unretained(Browser::Get());
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("quit", base::Bind(&Browser::Quit, browser))
|
||||
.SetMethod("exit", base::Bind(&Browser::Exit, browser))
|
||||
.SetMethod("focus", base::Bind(&Browser::Focus, browser))
|
||||
.SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
|
||||
.SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))
|
||||
|
|
|
@ -50,7 +50,6 @@ app.getAppPath = ->
|
|||
# Be compatible with old API.
|
||||
app.once 'ready', -> @emit 'finish-launching'
|
||||
app.terminate = app.quit
|
||||
app.exit = process.exit
|
||||
app.getHomeDir = -> @getPath 'home'
|
||||
app.getDataPath = -> @getPath 'userData'
|
||||
app.setDataPath = (path) -> @setPath 'userData', path
|
||||
|
|
|
@ -30,6 +30,7 @@ AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
|||
|
||||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: fake_browser_process_(new BrowserProcess),
|
||||
exit_code_(nullptr),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
atom_bindings_(new AtomBindings),
|
||||
|
@ -47,6 +48,14 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
|
|||
return self_;
|
||||
}
|
||||
|
||||
bool AtomBrowserMainParts::SetExitCode(int code) {
|
||||
if (!exit_code_)
|
||||
return false;
|
||||
|
||||
*exit_code_ = code;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::RegisterDestructionCallback(
|
||||
const base::Closure& callback) {
|
||||
destruction_callbacks_.push_back(callback);
|
||||
|
@ -118,6 +127,11 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
|
||||
exit_code_ = result_code;
|
||||
return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostMainMessageLoopStart() {
|
||||
brightray::BrowserMainParts::PostMainMessageLoopStart();
|
||||
#if defined(OS_POSIX)
|
||||
|
|
|
@ -31,6 +31,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
|
||||
static AtomBrowserMainParts* Get();
|
||||
|
||||
// Sets the exit code, will fail if the the message loop is not ready.
|
||||
bool SetExitCode(int code);
|
||||
|
||||
// Register a callback that should be destroyed before JavaScript environment
|
||||
// gets destroyed.
|
||||
void RegisterDestructionCallback(const base::Closure& callback);
|
||||
|
@ -42,6 +45,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
void PreEarlyInitialization() override;
|
||||
void PostEarlyInitialization() override;
|
||||
void PreMainMessageLoopRun() override;
|
||||
bool MainMessageLoopRun(int* result_code) override;
|
||||
void PostMainMessageLoopStart() override;
|
||||
void PostMainMessageLoopRun() override;
|
||||
#if defined(OS_MACOSX)
|
||||
|
@ -66,6 +70,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
// with a task runner that will post all work to main loop.
|
||||
scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
|
||||
|
||||
// Pointer to exit code.
|
||||
int* exit_code_;
|
||||
|
||||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<JavascriptEnvironment> js_env_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
|
@ -45,6 +46,27 @@ void Browser::Quit() {
|
|||
window_list->CloseAllWindows();
|
||||
}
|
||||
|
||||
void Browser::Exit(int code) {
|
||||
if (!AtomBrowserMainParts::Get()->SetExitCode(code)) {
|
||||
// Message loop is not ready, quit directly.
|
||||
exit(code);
|
||||
} else {
|
||||
// Prepare to quit when all windows have been closed..
|
||||
is_quiting_ = true;
|
||||
|
||||
// Must destroy windows before quitting, otherwise bad things can happen.
|
||||
atom::WindowList* window_list = atom::WindowList::GetInstance();
|
||||
if (window_list->size() == 0) {
|
||||
NotifyAndShutdown();
|
||||
} 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Browser::Shutdown() {
|
||||
if (is_shutdown_)
|
||||
return;
|
||||
|
|
|
@ -42,6 +42,9 @@ class Browser : public WindowListObserver {
|
|||
// Try to close all windows and quit the application.
|
||||
void Quit();
|
||||
|
||||
// Exit the application immediately and set exit code.
|
||||
void Exit(int code);
|
||||
|
||||
// Cleanup everything and shutdown the application gracefully.
|
||||
void Shutdown();
|
||||
|
||||
|
|
|
@ -53,6 +53,9 @@ app = require 'app'
|
|||
app.on 'quit', ->
|
||||
process.emit 'exit'
|
||||
|
||||
# Map process.exit to app.exit, which quits gracefully.
|
||||
process.exit = app.exit
|
||||
|
||||
# Load the RPC server.
|
||||
require './rpc-server'
|
||||
|
||||
|
|
|
@ -208,6 +208,15 @@ This method guarantees that all `beforeunload` and `unload` event handlers are
|
|||
correctly executed. It is possible that a window cancels the quitting by
|
||||
returning `false` in the `beforeunload` event handler.
|
||||
|
||||
### `app.exit(exitCode)`
|
||||
|
||||
* `exitCode` Integer
|
||||
|
||||
Exits immediately with `exitCode`.
|
||||
|
||||
All windows will be closed immediately without asking user and the `before-quit`
|
||||
and `will-quit` events will not be emitted.
|
||||
|
||||
### `app.getAppPath()`
|
||||
|
||||
Returns the current application directory.
|
||||
|
|
Loading…
Reference in a new issue