Browse Source

Merge pull request #8487 from leethomas/feature/osx-relative-window-levels

Feature/macOS relative window levels
Kevin Sawicki 8 years ago
parent
commit
dc1c11a841

+ 10 - 1
atom/browser/api/atom_api_window.cc

@@ -512,8 +512,17 @@ bool Window::IsClosable() {
 
 void Window::SetAlwaysOnTop(bool top, mate::Arguments* args) {
   std::string level = "floating";
+  int relativeLevel = 0;
+  std::string error;
+
   args->GetNext(&level);
-  window_->SetAlwaysOnTop(top, level);
+  args->GetNext(&relativeLevel);
+
+  window_->SetAlwaysOnTop(top, level, relativeLevel, &error);
+
+  if (!error.empty()) {
+    args->ThrowError(error);
+  }
 }
 
 bool Window::IsAlwaysOnTop() {

+ 3 - 1
atom/browser/native_window.h

@@ -119,7 +119,9 @@ class NativeWindow : public base::SupportsUserData,
   virtual void SetClosable(bool closable) = 0;
   virtual bool IsClosable() = 0;
   virtual void SetAlwaysOnTop(bool top,
-                              const std::string& level = "floating") = 0;
+                              const std::string& level = "floating",
+                              int relativeLevel = 0,
+                              std::string* error = nullptr) = 0;
   virtual bool IsAlwaysOnTop() = 0;
   virtual void Center() = 0;
   virtual void SetTitle(const std::string& title) = 0;

+ 2 - 1
atom/browser/native_window_mac.h

@@ -67,7 +67,8 @@ class NativeWindowMac : public NativeWindow,
   bool IsFullScreenable() override;
   void SetClosable(bool closable) override;
   bool IsClosable() override;
-  void SetAlwaysOnTop(bool top, const std::string& level) override;
+  void SetAlwaysOnTop(bool top, const std::string& level,
+                      int relativeLevel, std::string* error) override;
   bool IsAlwaysOnTop() override;
   void Center() override;
   void SetTitle(const std::string& title) override;

+ 14 - 2
atom/browser/native_window_mac.mm

@@ -1056,8 +1056,12 @@ bool NativeWindowMac::IsClosable() {
   return [window_ styleMask] & NSClosableWindowMask;
 }
 
-void NativeWindowMac::SetAlwaysOnTop(bool top, const std::string& level) {
+void NativeWindowMac::SetAlwaysOnTop(bool top, const std::string& level,
+                                     int relativeLevel, std::string* error) {
   int windowLevel = NSNormalWindowLevel;
+  CGWindowLevel maxWindowLevel = CGWindowLevelForKey(kCGMaximumWindowLevelKey);
+  CGWindowLevel minWindowLevel = CGWindowLevelForKey(kCGMinimumWindowLevelKey);
+  
   if (top) {
     if (level == "floating") {
       windowLevel = NSFloatingWindowLevel;
@@ -1078,7 +1082,15 @@ void NativeWindowMac::SetAlwaysOnTop(bool top, const std::string& level) {
       windowLevel = NSDockWindowLevel;
     }
   }
-  [window_ setLevel:windowLevel];
+
+  NSInteger newLevel = windowLevel + relativeLevel;
+  if (newLevel >= minWindowLevel && newLevel <= maxWindowLevel) {
+    [window_ setLevel:newLevel];
+  } else {
+    *error = std::string([[NSString stringWithFormat:
+      @"relativeLevel must be between %d and %d", minWindowLevel,
+      maxWindowLevel] UTF8String]);
+  }
 }
 
 bool NativeWindowMac::IsAlwaysOnTop() {

+ 2 - 1
atom/browser/native_window_views.cc

@@ -682,7 +682,8 @@ bool NativeWindowViews::IsClosable() {
 #endif
 }
 
-void NativeWindowViews::SetAlwaysOnTop(bool top, const std::string& level) {
+void NativeWindowViews::SetAlwaysOnTop(bool top, const std::string& level,
+                                       int relativeLevel, std::string* error) {
   window_->SetAlwaysOnTop(top);
 }
 

+ 2 - 1
atom/browser/native_window_views.h

@@ -86,7 +86,8 @@ class NativeWindowViews : public NativeWindow,
   bool IsFullScreenable() override;
   void SetClosable(bool closable) override;
   bool IsClosable() override;
-  void SetAlwaysOnTop(bool top, const std::string& level) override;
+  void SetAlwaysOnTop(bool top, const std::string& level,
+                      int relativeLevel, std::string* error) override;
   bool IsAlwaysOnTop() override;
   void Center() override;
   void SetTitle(const std::string& title) override;

+ 4 - 1
docs/api/browser-window.md

@@ -846,13 +846,16 @@ Returns `Boolean` - Whether the window can be manually closed by user.
 
 On Linux always returns `true`.
 
-#### `win.setAlwaysOnTop(flag[, level])`
+#### `win.setAlwaysOnTop(flag[, level][, relativeLevel])`
 
 * `flag` Boolean
 * `level` String (optional) _macOS_ - Values include `normal`, `floating`,
   `torn-off-menu`, `modal-panel`, `main-menu`, `status`, `pop-up-menu`,
   `screen-saver`, and ~~`dock`~~ (Deprecated). The default is `floating`. See the
   [macOS docs][window-levels] for more details.
+* `relativeLevel` Integer (optional) _macOS_ - The number of layers higher to set
+  this window relative to the given `level`. The default is `0`. Note that Apple
+  discourages setting levels higher than 1 above `screen-saver`. 
 
 Sets whether the window should show always on top of other windows. After
 setting this, the window is still a normal window, not a toolbox window which

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

@@ -524,6 +524,18 @@ describe('BrowserWindow module', function () {
       w.setAlwaysOnTop(true)
       assert.equal(w.isAlwaysOnTop(), true)
     })
+
+    it('raises an error when relativeLevel is out of bounds', function () {
+      if (process.platform !== 'darwin') return
+
+      assert.throws(function () {
+        w.setAlwaysOnTop(true, '', -2147483644)
+      })
+
+      assert.throws(function () {
+        w.setAlwaysOnTop(true, '', 2147483632)
+      })
+    })
   })
 
   describe('BrowserWindow.setAutoHideCursor(autoHide)', () => {