Browse Source

Add "parent" option for BrowserWindow

Cheng Zhao 8 years ago
parent
commit
85ba382027

+ 20 - 2
atom/browser/api/atom_api_window.cc

@@ -97,9 +97,16 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options)
   mate::Dictionary(isolate, web_contents->GetWrapper()).Set(
       "browserWindowOptions", options);
 
+  // The parent window.
+  mate::Handle<Window> parent;
+  if (options.Get("parent", &parent))
+    parent_window_.Reset(isolate, parent.ToV8());
+
   // Creates BrowserWindow.
-  window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
-                                     options));
+  window_.reset(NativeWindow::Create(
+      web_contents->managed_web_contents(),
+      options,
+      parent.IsEmpty() ? nullptr : parent->window_.get()));
   web_contents->SetOwnerWindow(window_.get());
   window_->InitFromOptions(options);
   window_->AddObserver(this);
@@ -122,6 +129,17 @@ Window::~Window() {
   base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
 }
 
+void Window::AfterInit(v8::Isolate* isolate) {
+  mate::TrackableObject<Window>::AfterInit(isolate);
+
+  // We can only append this window to parent window's child windows after this
+  // window's JS wrapper gets initialized.
+  mate::Handle<Window> parent;
+  if (!parent_window_.IsEmpty() &&
+      mate::ConvertFromV8(isolate, GetParentWindow(), &parent))
+    parent->child_windows_.Set(isolate, ID(), GetWrapper());
+}
+
 void Window::WillCloseWindow(bool* prevent_default) {
   *prevent_default = Emit("close");
 }

+ 3 - 0
atom/browser/api/atom_api_window.h

@@ -55,6 +55,9 @@ class Window : public mate::TrackableObject<Window>,
   Window(v8::Isolate* isolate, const mate::Dictionary& options);
   ~Window() override;
 
+  // TrackableObject:
+  void AfterInit(v8::Isolate* isolate) override;
+
   // NativeWindowObserver:
   void WillCloseWindow(bool* prevent_default) override;
   void OnWindowClosed() override;

+ 2 - 1
atom/browser/native_window.h

@@ -81,7 +81,8 @@ class NativeWindow : public base::SupportsUserData,
   // managing the window's live.
   static NativeWindow* Create(
       brightray::InspectableWebContents* inspectable_web_contents,
-      const mate::Dictionary& options);
+      const mate::Dictionary& options,
+      NativeWindow* parent = nullptr);
 
   // Find a window from its WebContents
   static NativeWindow* FromWebContents(content::WebContents* web_contents);

+ 2 - 1
atom/browser/native_window_mac.h

@@ -22,7 +22,8 @@ namespace atom {
 class NativeWindowMac : public NativeWindow {
  public:
   NativeWindowMac(brightray::InspectableWebContents* inspectable_web_contents,
-                  const mate::Dictionary& options);
+                  const mate::Dictionary& options,
+                  NativeWindow* parent);
   ~NativeWindowMac() override;
 
   // NativeWindow:

+ 9 - 3
atom/browser/native_window_mac.mm

@@ -453,7 +453,8 @@ namespace atom {
 
 NativeWindowMac::NativeWindowMac(
     brightray::InspectableWebContents* web_contents,
-    const mate::Dictionary& options)
+    const mate::Dictionary& options,
+    NativeWindow* parent)
     : NativeWindow(web_contents, options),
       is_kiosk_(false),
       attention_request_id_(0),
@@ -526,6 +527,10 @@ NativeWindowMac::NativeWindowMac(
   window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
   [window_ setDelegate:window_delegate_];
 
+  if (parent) {
+    SetParentWindow(parent);
+  }
+
   if (transparent()) {
     // Setting the background color to clear will also hide the shadow.
     [window_ setBackgroundColor:[NSColor clearColor]];
@@ -1197,8 +1202,9 @@ void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
 // static
 NativeWindow* NativeWindow::Create(
     brightray::InspectableWebContents* inspectable_web_contents,
-    const mate::Dictionary& options) {
-  return new NativeWindowMac(inspectable_web_contents, options);
+    const mate::Dictionary& options,
+    NativeWindow* parent) {
+  return new NativeWindowMac(inspectable_web_contents, options, parent);
 }
 
 }  // namespace atom

+ 5 - 3
atom/browser/native_window_views.cc

@@ -126,7 +126,8 @@ class NativeWindowClientView : public views::ClientView {
 
 NativeWindowViews::NativeWindowViews(
     brightray::InspectableWebContents* web_contents,
-    const mate::Dictionary& options)
+    const mate::Dictionary& options,
+    NativeWindow* parent)
     : NativeWindow(web_contents, options),
       window_(new views::Widget),
       web_view_(inspectable_web_contents()->GetView()->GetView()),
@@ -1139,8 +1140,9 @@ ui::WindowShowState NativeWindowViews::GetRestoredState() {
 // static
 NativeWindow* NativeWindow::Create(
     brightray::InspectableWebContents* inspectable_web_contents,
-    const mate::Dictionary& options) {
-  return new NativeWindowViews(inspectable_web_contents, options);
+    const mate::Dictionary& options,
+    NativeWindow* parent) {
+  return new NativeWindowViews(inspectable_web_contents, options, parent);
 }
 
 }  // namespace atom

+ 2 - 1
atom/browser/native_window_views.h

@@ -42,7 +42,8 @@ class NativeWindowViews : public NativeWindow,
                           public views::WidgetObserver {
  public:
   NativeWindowViews(brightray::InspectableWebContents* inspectable_web_contents,
-                    const mate::Dictionary& options);
+                    const mate::Dictionary& options,
+                    NativeWindow* parent);
   ~NativeWindowViews() override;
 
   // NativeWindow:

+ 25 - 0
spec/api-browser-window-spec.js

@@ -849,7 +849,32 @@ describe('browser-window module', function () {
       c = null
     })
 
+    describe('parent option', function () {
+      beforeEach(function () {
+        if (c != null) c.destroy()
+        c = new BrowserWindow({show: false, parent: w})
+      })
+
+      it('sets parent window', function () {
+        assert.equal(c.getParentWindow(), w)
+      })
+
+      it('adds window to child windows of parent', function () {
+        assert.deepEqual(w.getChildWindows(), [c])
+      })
+
+      it('removes from child windows of parent when window is closed', function (done) {
+        c.once('closed', () => {
+          assert.deepEqual(w.getChildWindows(), [])
+          done()
+        })
+        c.close()
+      })
+    })
+
     describe('win.setParentWindow(parent)', function () {
+      if (process.platform !== 'darwin') return
+
       it('sets parent window', function () {
         assert.equal(w.getParentWindow(), null)
         assert.equal(c.getParentWindow(), null)