From 07e557621ed43f92abfe5bcb67a71948adfb0d6b Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Wed, 26 Nov 2014 16:15:53 +0100 Subject: [PATCH] Add Window.setVisibleOnAllWorkspaces API For platforms that support multiple workspaces (currently Mac and Linux), this allows node-webkit windows to be visible on all workspaces simultaneously. - Add `SetVisibleOnAllWorkspaces` method to `Window` API objects. - Add implementation for Mac OS X. - Add implementation for Aura (Linux). - Add configuration support via boolean `'window'` subfield `'visible-on-all-workspaces'` in manifest file (see https://github.com/rogerwang/node-webkit/wiki/Manifest-format#window-subfields ). - Add `Window.canSetVisibleOnAllWorkspaces()` API method returning a a boolean indicating if the platform (currently OS X and Linux) support `Window` API object method `setVisibleOnAllWorkspace()`. - Add manual test for `SetVisibleOnAllWorkspaces` method to the `Window` API object. FIX rogerwang/node-webkit#2523 --- src/api/window/window.cc | 4 ++ src/api/window/window.js | 6 ++ src/api/window_bindings.js | 4 ++ src/browser/native_window.cc | 5 ++ src/browser/native_window.h | 1 + src/browser/native_window_aura.cc | 8 +++ src/browser/native_window_aura.h | 2 + src/browser/native_window_mac.h | 1 + src/browser/native_window_mac.mm | 10 +++ src/common/shell_switches.cc | 3 + src/common/shell_switches.h | 1 + .../visible_on_all_workspaces/index.html | 65 +++++++++++++++++++ .../visible_on_all_workspaces/index2.html | 41 ++++++++++++ .../visible_on_all_workspaces/package.json | 8 +++ 14 files changed, 159 insertions(+) create mode 100644 tests/manual_tests/visible_on_all_workspaces/index.html create mode 100644 tests/manual_tests/visible_on_all_workspaces/index2.html create mode 100644 tests/manual_tests/visible_on_all_workspaces/package.json diff --git a/src/api/window/window.cc b/src/api/window/window.cc index 9765f51905..cb6f3d9fd1 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -255,6 +255,10 @@ void Window::Call(const std::string& method, bool show; if (arguments.GetBoolean(0, &show)) shell_->window()->SetShowInTaskbar(show); + } else if (method == "SetVisibleOnAllWorkspaces") { + bool all_workspaces; + if (arguments.GetBoolean(0, &all_workspaces)) + shell_->window()->SetVisibleOnAllWorkspaces(all_workspaces); } else if (method == "MoveTo") { int x, y; if (arguments.GetInteger(0, &x) && diff --git a/src/api/window/window.js b/src/api/window/window.js index 5124d90530..00bacf3034 100644 --- a/src/api/window/window.js +++ b/src/api/window/window.js @@ -18,6 +18,9 @@ // ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// OS X and Linux only, Windows does not have a concept of workspaces +var canSetVisibleOnAllWorkspaces = /(darwin|linux)/.test(require('os').platform()); + exports.Window = { get: function(other) { // Return other window. @@ -66,5 +69,8 @@ exports.Window = { var routing_id = nw.createShell(url, options); return new global.Window(routing_id, true, id); + }, + canSetVisibleOnAllWorkspaces: function() { + return canSetVisibleOnAllWorkspaces; } }; diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index ae11ec9ad9..49ec508675 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -412,6 +412,10 @@ Window.prototype.setShowInTaskbar = function(flag) { CallObjectMethod(this, 'SetShowInTaskbar', [ flag ]); } +Window.prototype.setVisibleOnAllWorkspaces = function(flag) { + CallObjectMethod(this, 'SetVisibleOnAllWorkspaces', [ Boolean(flag) ]); +} + Window.prototype.requestAttention = function(flash) { if (typeof flash == 'boolean') { // boolean true is redirected as -1 value diff --git a/src/browser/native_window.cc b/src/browser/native_window.cc index 6de6268641..f0b430e30b 100644 --- a/src/browser/native_window.cc +++ b/src/browser/native_window.cc @@ -130,6 +130,11 @@ void NativeWindow::InitFromManifest(base::DictionaryValue* manifest) { !showInTaskbar) { SetShowInTaskbar(false); } + bool all_workspaces; + if (manifest->GetBoolean(switches::kmVisibleOnAllWorkspaces, &all_workspaces) + && all_workspaces) { + SetVisibleOnAllWorkspaces(true); + } bool fullscreen; if (manifest->GetBoolean(switches::kmFullscreen, &fullscreen) && fullscreen) { SetFullscreen(true); diff --git a/src/browser/native_window.h b/src/browser/native_window.h index da72f275a1..1e904fea8b 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -96,6 +96,7 @@ class NativeWindow { virtual void SetResizable(bool resizable) = 0; virtual void SetAlwaysOnTop(bool top) = 0; virtual void SetShowInTaskbar(bool show = true) = 0; + virtual void SetVisibleOnAllWorkspaces(bool all_workspaces) = 0; virtual void SetPosition(const std::string& position) = 0; virtual void SetPosition(const gfx::Point& position) = 0; virtual gfx::Point GetPosition() = 0; diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index b8da0ebe72..27c1fc30ee 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -280,6 +280,7 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, toolbar_(NULL), web_view_(NULL), is_fullscreen_(false), + is_visible_on_all_workspaces_(false), is_minimized_(false), is_maximized_(false), is_focus_(false), @@ -293,6 +294,7 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, manifest->GetBoolean("focus", &initial_focus_); manifest->GetBoolean("fullscreen", &is_fullscreen_); manifest->GetBoolean("resizable", &resizable_); + manifest->GetBoolean("visible-on-all-workspaces", &is_visible_on_all_workspaces_); window_ = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); @@ -303,6 +305,7 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; if (is_fullscreen_) params.show_state = ui::SHOW_STATE_FULLSCREEN; + params.visible_on_all_workspaces = is_visible_on_all_workspaces_; #if defined(OS_WIN) if (has_frame()) window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE); @@ -565,6 +568,11 @@ void NativeWindowAura::SetAlwaysOnTop(bool top) { window_->SetAlwaysOnTop(top); } +void NativeWindowAura::SetVisibleOnAllWorkspaces(bool all_workspaces) { + is_visible_on_all_workspaces_ = all_workspaces; + window_->SetVisibleOnAllWorkspaces(all_workspaces); +} + void NativeWindowAura::OnWidgetActivationChanged(views::Widget* widget, bool active) { if (active) { if (shell()) diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index 861e540356..eed8560284 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -86,6 +86,7 @@ class NativeWindowAura : public NativeWindow, virtual void SetResizable(bool resizable) OVERRIDE; virtual void SetAlwaysOnTop(bool top) OVERRIDE; virtual void SetShowInTaskbar(bool show = true) OVERRIDE; + virtual void SetVisibleOnAllWorkspaces(bool all_workspaces) OVERRIDE; virtual void SetPosition(const std::string& position) OVERRIDE; virtual void SetPosition(const gfx::Point& position) OVERRIDE; virtual gfx::Point GetPosition() OVERRIDE; @@ -181,6 +182,7 @@ class NativeWindowAura : public NativeWindow, views::WebView* web_view_; views::Widget* window_; bool is_fullscreen_; + bool is_visible_on_all_workspaces_; // Flags used to prevent sending extra events. bool is_minimized_; diff --git a/src/browser/native_window_mac.h b/src/browser/native_window_mac.h index 7283c1a97c..01b7b3713a 100644 --- a/src/browser/native_window_mac.h +++ b/src/browser/native_window_mac.h @@ -60,6 +60,7 @@ class NativeWindowCocoa : public NativeWindow { virtual void SetResizable(bool resizable) OVERRIDE; virtual void SetAlwaysOnTop(bool top) OVERRIDE; virtual void SetShowInTaskbar(bool show = true) OVERRIDE; + virtual void SetVisibleOnAllWorkspaces(bool all_workspaces) OVERRIDE; virtual void SetPosition(const std::string& position) OVERRIDE; virtual void SetPosition(const gfx::Point& position) OVERRIDE; virtual gfx::Point GetPosition() OVERRIDE; diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index e7572fd0bb..5d5f1fd94b 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -665,6 +665,16 @@ - (void)drawRect:(NSRect)dirtyRect { [window() setLevel:(top ? NSFloatingWindowLevel : NSNormalWindowLevel)]; } +void NativeWindowCocoa::SetVisibleOnAllWorkspaces(bool all_workspaces) { + NSUInteger collectionBehavior = [window() collectionBehavior]; + if (all_workspaces) { + collectionBehavior |= NSWindowCollectionBehaviorCanJoinAllSpaces; + } else { + collectionBehavior &= ~NSWindowCollectionBehaviorCanJoinAllSpaces; + } + [window() setCollectionBehavior:collectionBehavior]; +} + void NativeWindowCocoa::SetShowInTaskbar(bool show) { ProcessSerialNumber psn = { 0, kCurrentProcess }; if (!show) { diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index 6a8aff14ca..9ffbdef8e8 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -85,6 +85,9 @@ const char kmKiosk[] = "kiosk"; // Make windows stays on the top of all other windows. const char kmAlwaysOnTop[] = "always-on-top"; +// Make window visible on all workspaces. +const char kmVisibleOnAllWorkspaces[] = "visible-on-all-workspaces"; + // Whether we should support WebGL. const char kmWebgl[] = "webgl"; diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 203fb328cc..4e0b532cbc 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -53,6 +53,7 @@ extern const char kmFullscreen[]; extern const char kmShowInTaskbar[]; extern const char kmKiosk[]; extern const char kmAlwaysOnTop[]; +extern const char kmVisibleOnAllWorkspaces[]; extern const char kmInitialFocus[]; extern const char kmTransparent[]; extern const char kmDisableTransparency[]; diff --git a/tests/manual_tests/visible_on_all_workspaces/index.html b/tests/manual_tests/visible_on_all_workspaces/index.html new file mode 100644 index 0000000000..8114b47d52 --- /dev/null +++ b/tests/manual_tests/visible_on_all_workspaces/index.html @@ -0,0 +1,65 @@ + + + Always on Visible Workspace Test - window #1 + + +
+

Window #1

+

This window is visible only on this workspace

+
+ Visible on all workspaces +

Makes the window visible on all workspaces simultaneously.

+
+
+ Only on this workspace +

Makes the window visible only on this workspace.

+
+

+
+ + + diff --git a/tests/manual_tests/visible_on_all_workspaces/index2.html b/tests/manual_tests/visible_on_all_workspaces/index2.html new file mode 100644 index 0000000000..e7ff6d3748 --- /dev/null +++ b/tests/manual_tests/visible_on_all_workspaces/index2.html @@ -0,0 +1,41 @@ + + + Always on Visible Workspace Test - window #2 + + +

Window #2

+

This window is visible only on this workspace

+
+ Visible on all workspaces +

Makes the window visible on all workspaces simultaneously.

+
+
+ Only on this workspace +

Makes the window visible only on this workspace.

+
+

+ + + diff --git a/tests/manual_tests/visible_on_all_workspaces/package.json b/tests/manual_tests/visible_on_all_workspaces/package.json new file mode 100644 index 0000000000..8c6eadaecd --- /dev/null +++ b/tests/manual_tests/visible_on_all_workspaces/package.json @@ -0,0 +1,8 @@ +{ + "name": "nw-always-on-visible-workspace-test", + "main": "index.html", + "window": { + "visible-on-all-workspaces": true + }, + "dependencies": {} +}