diff --git a/atom/browser/mac/atom_application.mm b/atom/browser/mac/atom_application.mm index f934bfeacddc..96c99f5d22f1 100644 --- a/atom/browser/mac/atom_application.mm +++ b/atom/browser/mac/atom_application.mm @@ -4,6 +4,7 @@ #import "atom/browser/mac/atom_application.h" +#import "atom/browser/mac/atom_application_delegate.h" #include "atom/browser/mac/dict_util.h" #include "atom/browser/browser.h" #include "base/auto_reset.h" @@ -27,6 +28,11 @@ inline void dispatch_sync_main(dispatch_block_t block) { return (AtomApplication*)[super sharedApplication]; } +- (void)terminate:(id)sender { + AtomApplicationDelegate* atomDelegate = (AtomApplicationDelegate*) [NSApp delegate]; + [atomDelegate tryToTerminateApp:self]; +} + - (BOOL)isHandlingSendEvent { return handlingSendEvent_; } diff --git a/atom/browser/mac/atom_application_delegate.h b/atom/browser/mac/atom_application_delegate.h index 777475213ecf..cbc5c71d0a73 100644 --- a/atom/browser/mac/atom_application_delegate.h +++ b/atom/browser/mac/atom_application_delegate.h @@ -11,6 +11,8 @@ base::scoped_nsobject menu_controller_; } +- (void)tryToTerminateApp:(NSApplication*)app; + // Sets the menu that will be returned in "applicationDockMenu:". - (void)setApplicationDockMenu:(atom::AtomMenuModel*)model; diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 9a5133368ef8..5664501d1aa3 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -87,15 +87,11 @@ static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session; return atom::Browser::Get()->OpenFile(filename_str) ? YES : NO; } -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender { - atom::Browser* browser = atom::Browser::Get(); - if (browser->is_quiting()) { - return NSTerminateNow; - } else { - // System started termination. - atom::Browser::Get()->Quit(); - return NSTerminateCancel; - } +// We simply try to close the browser, which in turn will try to close the windows. +// Termination can proceed if all windows are closed or window close can be cancelled +// which will abort termination. +- (void)tryToTerminateApp:(NSApplication*)app { + atom::Browser::Get()->Quit(); } - (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 8d471f351281..857857842a96 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -157,6 +157,24 @@ describe('app module', () => { done() }) }) + + it('exits gracefully on macos', (done) => { + if (process.platform !== 'darwin') { + this.skip() + } + const appPath = path.join(__dirname, 'fixtures', 'api', 'singleton') + const electronPath = remote.getGlobal('process').execPath + appProcess = ChildProcess.spawn(electronPath, [appPath]) + appProcess.stdout.once('data', () => { + // The apple script will try to terminate the app + // If there's an error terminating the app, then it will print to stderr + ChildProcess.exec('osascript -e \'quit app "Electron"\'', (err, stdout, stderr) => { + assert(!err) + assert(!stderr.trim()) + done() + }) + }) + }) }) describe('app.makeSingleInstance', () => {