Add 'quit' and 'window-all-closed' events for app module.
authorCheng Zhao <zcbenz@gmail.com>
Fri, 3 May 2013 02:53:54 +0000 (10:53 +0800)
committerCheng Zhao <zcbenz@gmail.com>
Fri, 3 May 2013 02:53:54 +0000 (10:53 +0800)
atom.gyp
browser/api/atom_api_app.cc
browser/api/atom_api_app.h
browser/api/lib/app.coffee
browser/browser.cc
browser/browser.h
browser/browser_observer.h [new file with mode: 0644]
browser/default_app/main.js
browser/window_list_observer.h
script/cpplint

index 091aaa8..3627a3d 100644 (file)
--- a/atom.gyp
+++ b/atom.gyp
@@ -52,6 +52,7 @@
       'browser/browser.cc',
       'browser/browser.h',
       'browser/browser_mac.mm',
+      'browser/browser_observer.h',
       'browser/native_window.cc',
       'browser/native_window.h',
       'browser/native_window_mac.h',
index 797e03f..eece7af 100644 (file)
@@ -11,6 +11,35 @@ namespace atom {
 
 namespace api {
 
+App::App(v8::Handle<v8::Object> wrapper)
+    : EventEmitter(wrapper) {
+  Browser::Get()->AddObserver(this);
+}
+
+App::~App() {
+  Browser::Get()->RemoveObserver(this);
+}
+
+void App::OnWillQuit(bool* prevent_default) {
+  *prevent_default = Emit("will-quit");
+}
+
+void App::OnWindowAllClosed() {
+  Emit("window-all-closed");
+}
+
+// static
+v8::Handle<v8::Value> App::New(const v8::Arguments &args) {
+  v8::HandleScope scope;
+
+  if (!args.IsConstructCall())
+    return node::ThrowError("Require constructor call");
+
+  new App(args.This());
+
+  return args.This();
+}
+
 // static
 v8::Handle<v8::Value> App::Quit(const v8::Arguments &args) {
   v8::HandleScope scope;
@@ -31,8 +60,16 @@ v8::Handle<v8::Value> App::Terminate(const v8::Arguments &args) {
 
 // static
 void App::Initialize(v8::Handle<v8::Object> target) {
-  node::SetMethod(target, "quit", Quit);
-  node::SetMethod(target, "terminate", Terminate);
+  v8::HandleScope scope;
+
+  v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(App::New);
+  t->InstanceTemplate()->SetInternalFieldCount(1);
+  t->SetClassName(v8::String::NewSymbol("Application"));
+
+  NODE_SET_PROTOTYPE_METHOD(t, "quit", Quit);
+  NODE_SET_PROTOTYPE_METHOD(t, "terminate", Terminate);
+
+  target->Set(v8::String::NewSymbol("Application"), t->GetFunction());
 }
 
 }  // namespace api
index 0c8fdc7..f2b45ee 100644 (file)
@@ -5,22 +5,35 @@
 #ifndef ATOM_BROWSER_API_ATOM_API_APP_H_
 #define ATOM_BROWSER_API_ATOM_API_APP_H_
 
-#include "base/basictypes.h"
-#include "v8/include/v8.h"
+#include "base/compiler_specific.h"
+#include "browser/api/atom_api_event_emitter.h"
+#include "browser/browser_observer.h"
 
 namespace atom {
 
 namespace api {
 
-class App {
+class App : public EventEmitter,
+            public BrowserObserver{
  public:
+  virtual ~App();
+
   static void Initialize(v8::Handle<v8::Object> target);
 
+ protected:
+  explicit App(v8::Handle<v8::Object> wrapper);
+
+  // BrowserObserver implementations:
+  virtual void OnWillQuit(bool* prevent_default) OVERRIDE;
+  virtual void OnWindowAllClosed() OVERRIDE;
+
  private:
+  static v8::Handle<v8::Value> New(const v8::Arguments &args);
+
   static v8::Handle<v8::Value> Quit(const v8::Arguments &args);
   static v8::Handle<v8::Value> Terminate(const v8::Arguments &args);
 
-  DISALLOW_IMPLICIT_CONSTRUCTORS(App);
+  DISALLOW_COPY_AND_ASSIGN(App);
 };
 
 }  // namespace api
index 3ee09d2..3b699c4 100644 (file)
@@ -1,8 +1,7 @@
-binding = process.atomBinding 'app'
 EventEmitter = require('events').EventEmitter
 
-class App extends EventEmitter
-  quit: binding.quit
-  terminate: binding.terminate
+Application = process.atomBinding('app').Application
+Application.prototype.__proto__ = EventEmitter.prototype
 
-module.exports = new App
+# Only one App object pemitted.
+module.exports = new Application
index b85901f..fafe86e 100644 (file)
@@ -26,12 +26,22 @@ Browser* Browser::Get() {
 void Browser::Quit() {
   atom::WindowList* window_list = atom::WindowList::GetInstance();
   if (window_list->size() == 0)
-    Terminate();
+    NotifyAndTerminate();
 
   is_quiting_ = true;
   window_list->CloseAllWindows();
 }
 
+void Browser::NotifyAndTerminate() {
+  bool prevent_default = false;
+  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));
+
+  if (prevent_default)
+    return;
+
+  Terminate();
+}
+
 void Browser::OnWindowCloseCancelled(NativeWindow* window) {
   // Once a beforeunload handler has prevented the closing, we think the quit
   // is cancelled too.
@@ -40,7 +50,9 @@ void Browser::OnWindowCloseCancelled(NativeWindow* window) {
 
 void Browser::OnWindowAllClosed() {
   if (is_quiting_)
-    Terminate();
+    NotifyAndTerminate();
+  else
+    FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWindowAllClosed());
 }
 
 }  // namespace atom
index ef07e36..118ce00 100644 (file)
@@ -7,6 +7,8 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "browser/browser_observer.h"
 #include "browser/window_list_observer.h"
 
 namespace atom {
@@ -25,9 +27,17 @@ class Browser : public WindowListObserver {
   // Quit the application immediately without cleanup work.
   void Terminate();
 
-  bool is_quiting() const { return is_quiting_; }
+  void AddObserver(BrowserObserver* obs) {
+    observers_.AddObserver(obs);
+  }
+
+  void RemoveObserver(BrowserObserver* obs) {
+    observers_.RemoveObserver(obs);
+  }
 
  protected:
+  void NotifyAndTerminate();
+
   bool is_quiting_;
 
  private:
@@ -35,6 +45,9 @@ class Browser : public WindowListObserver {
   virtual void OnWindowCloseCancelled(NativeWindow* window) OVERRIDE;
   virtual void OnWindowAllClosed() OVERRIDE;
 
+  // Observers of the browser.
+  ObserverList<BrowserObserver> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(Browser);
 };
 
diff --git a/browser/browser_observer.h b/browser/browser_observer.h
new file mode 100644 (file)
index 0000000..e79884b
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (c) 2013 GitHub, Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ATOM_BROSER_BROWSER_OBSERVER_H_
+#define ATOM_BROSER_BROWSER_OBSERVER_H_
+
+namespace atom {
+
+class BrowserObserver {
+ public:
+  // The browser has closed all windows and will quit.
+  virtual void OnWillQuit(bool* prevent_default) {}
+
+  // The browser has closed all windows. If the browser is quiting, then this
+  // method will not be called, instead it will call OnWillQuit.
+  virtual void OnWindowAllClosed() {}
+
+ protected:
+  virtual ~BrowserObserver() {}
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROSER_BROWSER_OBSERVER_H_
index 5238372..721caeb 100644 (file)
@@ -1,9 +1,15 @@
+var app = require('app');
 var atom = require('atom');
 var ipc = require('ipc');
 var Window = require('window');
 
 var mainWindow = null;
 
+// Quit when all windows are closed.
+app.on('window-all-closed', function() {
+  app.terminate();
+});
+
 // Echo every message back.
 ipc.on('message', function(process_id, routing_id) {
   ipc.send.apply(ipc, arguments);
index 76778cd..e68e492 100644 (file)
@@ -10,7 +10,7 @@ namespace atom {
 class NativeWindow;
 
 class WindowListObserver {
 public:
+ public:
   // Called immediately after a window is added to the list.
   virtual void OnWindowAdded(NativeWindow* window) {}
 
index ff72393..48a5a4a 100755 (executable)
@@ -5,6 +5,8 @@ cd "`dirname $0`/.."
 # List all Objective-C headers here, should not cpplint them.
 OBJC_HEADERS='
 browser/atom_event_processing_window.h
+browser/atom_application_mac.h
+browser/atom_application_delegate_mac.h
 browser/native_window_mac.h
 common/api/api_messages.cc
 common/api/api_messages.h'