Commit c76ef732 authored by jackhou's avatar jackhou Committed by Commit bot

Add AppWindow.setVisibleOnAllWorkspaces.

For platforms that support multiple workspaces (currently Mac and Linux), this
allows app windows be visible on all workspaces simultaneously.

API proposal:
https://docs.google.com/document/d/1RC3CYwsrVxS_5hXg6nE3zA9y59G98z9Ezmmmq_Gzx9o/edit?usp=sharing

BUG=384644

Review URL: https://codereview.chromium.org/469993003

Cr-Commit-Position: refs/heads/master@{#293676}
parent 9f11d3bc
......@@ -401,4 +401,8 @@ bool NativeAppWindowViews::CanHaveAlphaEnabled() const {
return widget_->IsTranslucentWindowOpacitySupported();
}
void NativeAppWindowViews::SetVisibleOnAllWorkspaces(bool always_visible) {
widget_->SetVisibleOnAllWorkspaces(always_visible);
}
} // namespace apps
......@@ -161,6 +161,7 @@ class NativeAppWindowViews : public extensions::NativeAppWindow,
virtual void SetContentSizeConstraints(const gfx::Size& min_size,
const gfx::Size& max_size) OVERRIDE;
virtual bool CanHaveAlphaEnabled() const OVERRIDE;
virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
// web_modal::WebContentsModalDialogHost implementation.
virtual gfx::NativeView GetHostView() const OVERRIDE;
......
......@@ -257,3 +257,9 @@ IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestFrameColorsInStable) {
ASSERT_TRUE(RunAppWindowAPITest("testFrameColors")) << message_;
}
#endif
IN_PROC_BROWSER_TEST_F(AppWindowAPITest, TestVisibleOnAllWorkspaces) {
ASSERT_TRUE(
RunAppWindowAPITestAndWaitForRoundTrip("testVisibleOnAllWorkspaces"))
<< message_;
}
......@@ -27,6 +27,8 @@ namespace SetIcon = app_current_window_internal::SetIcon;
namespace SetBadgeIcon = app_current_window_internal::SetBadgeIcon;
namespace SetShape = app_current_window_internal::SetShape;
namespace SetAlwaysOnTop = app_current_window_internal::SetAlwaysOnTop;
namespace SetVisibleOnAllWorkspaces =
app_current_window_internal::SetVisibleOnAllWorkspaces;
using app_current_window_internal::Bounds;
using app_current_window_internal::Region;
......@@ -397,4 +399,18 @@ bool AppCurrentWindowInternalSetAlwaysOnTopFunction::RunWithWindow(
return true;
}
bool AppCurrentWindowInternalSetVisibleOnAllWorkspacesFunction::RunWithWindow(
AppWindow* window) {
if (GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV) {
error_ = kDevChannelOnly;
return false;
}
scoped_ptr<SetVisibleOnAllWorkspaces::Params> params(
SetVisibleOnAllWorkspaces::Params::Create(*args_));
CHECK(params.get());
window->GetBaseWindow()->SetVisibleOnAllWorkspaces(params->always_visible);
return true;
}
} // namespace extensions
......@@ -197,6 +197,18 @@ class AppCurrentWindowInternalSetAlwaysOnTopFunction
virtual bool RunWithWindow(AppWindow* window) OVERRIDE;
};
class AppCurrentWindowInternalSetVisibleOnAllWorkspacesFunction
: public AppCurrentWindowInternalExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION(
"app.currentWindowInternal.setVisibleOnAllWorkspaces",
APP_CURRENTWINDOWINTERNAL_SETVISIBLEONALLWORKSPACES)
protected:
virtual ~AppCurrentWindowInternalSetVisibleOnAllWorkspacesFunction() {}
virtual bool RunWithWindow(AppWindow* window) OVERRIDE;
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_APP_CURRENT_WINDOW_INTERNAL_APP_CURRENT_WINDOW_INTERNAL_API_H_
......@@ -148,6 +148,7 @@ class NativeAppWindowCocoa : public extensions::NativeAppWindow,
virtual gfx::Size GetContentMaximumSize() const OVERRIDE;
virtual void SetContentSizeConstraints(const gfx::Size& min_size,
const gfx::Size& max_size) OVERRIDE;
virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
// WebContentsObserver implementation.
virtual void RenderViewCreated(content::RenderViewHost* rvh) OVERRIDE;
......
......@@ -60,6 +60,15 @@ void SetFullScreenCollectionBehavior(NSWindow* window, bool allow_fullscreen) {
[window setCollectionBehavior:behavior];
}
void SetWorkspacesCollectionBehavior(NSWindow* window, bool always_visible) {
NSWindowCollectionBehavior behavior = [window collectionBehavior];
if (always_visible)
behavior |= NSWindowCollectionBehaviorCanJoinAllSpaces;
else
behavior &= ~NSWindowCollectionBehaviorCanJoinAllSpaces;
[window setCollectionBehavior:behavior];
}
void InitCollectionBehavior(NSWindow* window) {
// Since always-on-top windows have a higher window level
// than NSNormalWindowLevel, they will default to
......@@ -379,6 +388,8 @@ NativeAppWindowCocoa::NativeAppWindowCocoa(
[window setLevel:AlwaysOnTopWindowLevel()];
InitCollectionBehavior(window);
SetWorkspacesCollectionBehavior(window, params.visible_on_all_workspaces);
window_controller_.reset(
[[NativeAppWindowController alloc] initWithWindow:window.release()]);
......@@ -967,6 +978,10 @@ void NativeAppWindowCocoa::SetAlwaysOnTop(bool always_on_top) {
NSNormalWindowLevel)];
}
void NativeAppWindowCocoa::SetVisibleOnAllWorkspaces(bool always_visible) {
SetWorkspacesCollectionBehavior(window(), always_visible);
}
NativeAppWindowCocoa::~NativeAppWindowCocoa() {
}
......
......@@ -215,6 +215,8 @@ void ChromeNativeAppWindowViews::InitializeDefaultWindow(
if (create_params.alpha_enabled)
init_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
init_params.keep_on_top = create_params.always_on_top;
init_params.visible_on_all_workspaces =
create_params.visible_on_all_workspaces;
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Set up a custom WM_CLASS for app windows. This allows task switchers in
......
......@@ -75,6 +75,9 @@
"extension_types": ["platform_app"],
"noparent": true
},
"app.window.canSetVisibleOnAllWorkspaces": {
"channel": "dev"
},
"app.currentWindowInternal": {
"noparent": true,
"internal": true,
......
......@@ -52,6 +52,7 @@
static void clearBadge();
static void setShape(Region region);
static void setAlwaysOnTop(boolean always_on_top);
static void setVisibleOnAllWorkspaces(boolean always_visible);
};
interface Events {
......
......@@ -1352,6 +1352,21 @@ function testFrameColors() {
]);
}
function testVisibleOnAllWorkspaces() {
chrome.test.runTests([
function setAndUnsetVisibleOnAllWorkspaces() {
chrome.app.window.create('test.html', {
visibleOnAllWorkspaces: true
}, callbackPass(function(win) {
win.setVisibleOnAllWorkspaces(false);
win.setVisibleOnAllWorkspaces(true);
chrome.test.sendMessage(
'WaitForRoundTrip', callbackPass(function(reply) {}));
}));
},
]);
}
chrome.app.runtime.onLaunched.addListener(function() {
chrome.test.sendMessage('Launched', function(reply) {
window[reply]();
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// All these tests are run in Stable channel.
var error = "The visibleOnAllWorkspaces option requires dev channel or newer.";
chrome.app.runtime.onLaunched.addListener(function() {
chrome.test.runTests([
// Check CreateWindowOptions.visibleOnAllWorkspaces().
function testCreateOption() {
chrome.app.window.create(
'index.html', {
visibleOnAllWorkspaces: true,
}, chrome.test.callbackFail(error));
},
// Check chrome.app.window.canSetVisibleOnAllWorkspaces().
function testCanSetVisibleOnAllWorkspaces() {
chrome.test.assertTrue(
chrome.app.window.canSetVisibleOnAllWorkspaces === undefined);
chrome.test.callbackPass(function () {})();
},
]);
});
{
"name": "Windows API - visibleOnAllWorkspaces (in Stable Channel)",
"version": "1",
"manifest_version": 2,
"app": {
"background": {
"scripts": ["background.js"]
}
}
}
......@@ -56,6 +56,8 @@ const char kAlphaEnabledMissingPermission[] =
"The alphaEnabled option requires app.window.alpha permission.";
const char kAlphaEnabledNeedsFrameNone[] =
"The alphaEnabled option can only be used with \"frame: 'none'\".";
const char kVisibleOnAllWorkspacesWrongChannel[] =
"The visibleOnAllWorkspaces option requires dev channel or newer.";
} // namespace app_window_constants
const char kNoneFrameOption[] = "none";
......@@ -259,6 +261,15 @@ bool AppWindowCreateFunction::RunAsync() {
if (options->focused.get())
create_params.focused = *options->focused.get();
if (options->visible_on_all_workspaces.get()) {
if (AppsClient::Get()->IsCurrentChannelOlderThanDev()) {
error_ = app_window_constants::kVisibleOnAllWorkspacesWrongChannel;
return false;
}
create_params.visible_on_all_workspaces =
*options->visible_on_all_workspaces.get();
}
if (options->type != app_window::WINDOW_TYPE_PANEL) {
switch (options->state) {
case app_window::STATE_NONE:
......
......@@ -160,4 +160,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
<< message_;
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
WindowsApiVisibleOnAllWorkspacesInStable) {
extensions::ScopedCurrentChannel channel(chrome::VersionInfo::CHANNEL_STABLE);
EXPECT_TRUE(RunPlatformAppTest(
"platform_apps/windows_api_visible_on_all_workspaces/in_stable"))
<< message_;
}
} // namespace extensions
......@@ -180,6 +180,9 @@ class AppWindow : public content::NotificationObserver,
// configured to be always on top. Defaults to false.
bool always_on_top;
// If true, the window will be visible on all workspaces. Defaults to false.
bool visible_on_all_workspaces;
// The API enables developers to specify content or window bounds. This
// function combines them into a single, constrained window size.
gfx::Rect GetInitialWindowBounds(const gfx::Insets& frame_insets) const;
......
......@@ -92,6 +92,9 @@ class NativeAppWindow : public ui::BaseWindow,
virtual void SetContentSizeConstraints(const gfx::Size& min_size,
const gfx::Size& max_size) = 0;
// Returns whether the window show be visible on all workspaces.
virtual void SetVisibleOnAllWorkspaces(bool always_visible) = 0;
// Returns false if the underlying native window ignores alpha transparency
// when compositing.
virtual bool CanHaveAlphaEnabled() const = 0;
......
......@@ -948,6 +948,7 @@ enum HistogramValue {
MEDIAGALLERIES_GETALLGALLERYWATCH,
MEDIAGALLERIES_REMOVEALLGALLERYWATCH,
MANAGEMENT_GETSELF,
APP_CURRENTWINDOWINTERNAL_SETVISIBLEONALLWORKSPACES,
// Last entry: Add new entries above and ensure to update
// tools/metrics/histograms/histograms.xml.
ENUM_BOUNDARY
......
......@@ -263,6 +263,10 @@ namespace app.window {
// If true, the window will be focused when created. Defaults to true.
boolean? focused;
// If true, the window will be visible on all workspaces.
// This is only available on dev channel.
boolean? visibleOnAllWorkspaces;
};
// Called in the creating window (parent) before the load event is called in
......@@ -369,6 +373,11 @@ namespace app.window {
// TODO(jackhou): Document this properly before going to stable.
[nodoc] static boolean alphaEnabled();
// For platforms that support multiple workspaces, is this window visible on
// all of them?
// This is only available on dev channel.
static void setVisibleOnAllWorkspaces(boolean alwaysVisible);
// The JavaScript 'window' object for the created child.
[instanceOf=Window] object contentWindow;
......@@ -426,6 +435,10 @@ namespace app.window {
// Gets an $(ref:AppWindow) with the given id. If no window with the given id
// exists null is returned. This method is new in Chrome 33.
[nocompile] static AppWindow get(DOMString id);
// Does the current platform support windows being visible on all
// workspaces?
[nocompile] static boolean canSetVisibleOnAllWorkspaces();
};
interface Events {
......
......@@ -193,6 +193,10 @@ appWindow.registerCustomHook(function(bindingsAPI) {
return windows.length > 0 ? windows[0] : null;
});
apiFunctions.setHandleRequest('canSetVisibleOnAllWorkspaces', function() {
return /Mac/.test(navigator.platform) || /Linux/.test(navigator.userAgent);
});
// This is an internal function, but needs to be bound into a closure
// so the correct JS context is used for global variables such as
// currentWindowInternal, appWindowData, etc.
......
......@@ -238,6 +238,10 @@ void ShellNativeAppWindow::SetContentSizeConstraints(
NOTIMPLEMENTED();
}
void ShellNativeAppWindow::SetVisibleOnAllWorkspaces(bool always_visible) {
NOTIMPLEMENTED();
}
bool ShellNativeAppWindow::CanHaveAlphaEnabled() const {
NOTIMPLEMENTED();
return false;
......
......@@ -75,6 +75,7 @@ class ShellNativeAppWindow : public NativeAppWindow {
virtual gfx::Size GetContentMaximumSize() const OVERRIDE;
virtual void SetContentSizeConstraints(const gfx::Size& min_size,
const gfx::Size& max_size) OVERRIDE;
virtual void SetVisibleOnAllWorkspaces(bool always_visible) OVERRIDE;
virtual bool CanHaveAlphaEnabled() const OVERRIDE;
private:
......
......@@ -41368,6 +41368,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="887" label="MEDIAGALLERIES_GETALLGALLERYWATCH"/>
<int value="888" label="MEDIAGALLERIES_REMOVEALLGALLERYWATCH"/>
<int value="889" label="MANAGEMENT_GETSELF"/>
<int value="890" label="APP_CURRENTWINDOWINTERNAL_SETVISIBLEONALLWORKSPACES"/>
</enum>
<enum name="ExtensionInstallCause" type="int">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment