summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvarkha <varkha@chromium.org>2015-06-29 15:35:46 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-29 22:37:23 +0000
commitd99fa94f20bd74f7837ce3df44052ce2a707ab83 (patch)
treeac0d7c45a2263c50315ba530aa387fe106253d4d
parent97236cc8f139bb6cba9ddd1a34a4889fe0b4a66f (diff)
downloadchromium_src-d99fa94f20bd74f7837ce3df44052ce2a707ab83.zip
chromium_src-d99fa94f20bd74f7837ce3df44052ce2a707ab83.tar.gz
chromium_src-d99fa94f20bd74f7837ce3df44052ce2a707ab83.tar.bz2
Temporarily sets always-on-top property to off when another window is fullscreen
A chrome app window with always-on-top property (e.g. Hangouts app) stays on top of even the fullscreen window (e.g. a video playing on full screen) and it would be better to temporarily clear the always-on-top property while another window is in fullscreen mode. We already track fullscreen mode in Chrome OS and we already have a concept of temporarily clearing always-on-top property when that very window enters fullscreen state. This CL wires those together so that always-on-top windows are pushed below a fullscreen window and reassert their always-on-top property when workspace is no longer in fullscreen state. This only applies to Chrome OS, Windows case may be more difficult to get right. BUG=450055 Review URL: https://codereview.chromium.org/1180673012 Cr-Commit-Position: refs/heads/master@{#336663}
-rw-r--r--ash/root_window_controller.cc6
-rw-r--r--ash/root_window_controller.h2
-rw-r--r--ash/wm/window_state.cc37
-rw-r--r--ash/wm/window_state.h11
-rw-r--r--ash/wm/window_state_delegate.cc4
-rw-r--r--ash/wm/window_state_delegate.h5
-rw-r--r--ash/wm/workspace/workspace_layout_manager.cc27
-rw-r--r--ash/wm/workspace/workspace_layout_manager.h2
-rw-r--r--ash/wm/workspace/workspace_layout_manager_unittest.cc28
-rw-r--r--chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc6
-rw-r--r--extensions/browser/app_window/app_window.cc11
-rw-r--r--extensions/browser/app_window/app_window.h3
12 files changed, 134 insertions, 8 deletions
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 3a5733e..0b8ed2a 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -595,9 +595,9 @@ void RootWindowController::UpdateShelfVisibility() {
shelf_->shelf_layout_manager()->UpdateVisibilityState();
}
-const aura::Window* RootWindowController::GetWindowForFullscreenMode() const {
- const aura::Window* topmost_window = NULL;
- const aura::Window* active_window = wm::GetActiveWindow();
+aura::Window* RootWindowController::GetWindowForFullscreenMode() {
+ aura::Window* topmost_window = NULL;
+ aura::Window* active_window = wm::GetActiveWindow();
if (active_window && active_window->GetRootWindow() == GetRootWindow() &&
IsSwitchableContainer(active_window->parent())) {
// Use the active window when it is on the current root window to determine
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 7d0f689..44d1b40 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -223,7 +223,7 @@ class ASH_EXPORT RootWindowController : public ShellObserver {
// Returns the topmost window or one of its transient parents, if any of them
// are in fullscreen mode.
- const aura::Window* GetWindowForFullscreenMode() const;
+ aura::Window* GetWindowForFullscreenMode();
// Activate virtual keyboard on current root window controller.
void ActivateKeyboard(keyboard::KeyboardController* keyboard_controller);
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index bf6bc22..b314c95 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -216,6 +216,38 @@ void WindowState::Restore() {
}
}
+void WindowState::DisableAlwaysOnTop(aura::Window* window_on_top) {
+ DCHECK(window_on_top);
+ if (GetAlwaysOnTop()) {
+ // |window_| is hidden first to avoid canceling fullscreen mode when it is
+ // no longer always on top and gets added to default container. This avoids
+ // sending redundant OnFullscreenStateChanged to the layout manager. The
+ // |window_| visibility is restored after it no longer obscures the
+ // |window_on_top|.
+ bool visible = window_->IsVisible();
+ if (visible)
+ window_->Hide();
+ window_->SetProperty(aura::client::kAlwaysOnTopKey, false);
+ // Technically it is possible that a |window_| could make itself
+ // always_on_top really quickly. This is probably not a realistic case but
+ // check if the two windows are in the same container just in case.
+ if (window_on_top->parent() == window_->parent())
+ window_->parent()->StackChildAbove(window_on_top, window_);
+ if (visible)
+ window_->Show();
+ cached_always_on_top_ = true;
+ }
+}
+
+void WindowState::RestoreAlwaysOnTop() {
+ if (delegate() && delegate()->RestoreAlwaysOnTop(this))
+ return;
+ if (cached_always_on_top_) {
+ cached_always_on_top_ = false;
+ window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
+ }
+}
+
void WindowState::OnWMEvent(const WMEvent* event) {
current_state_->OnWMEvent(this, event);
}
@@ -318,11 +350,16 @@ WindowState::WindowState(aura::Window* window)
hide_shelf_when_fullscreen_(true),
minimum_visibility_(false),
can_be_dragged_(true),
+ cached_always_on_top_(false),
ignore_property_change_(false),
current_state_(new DefaultState(ToWindowStateType(GetShowState()))) {
window_->AddObserver(this);
}
+bool WindowState::GetAlwaysOnTop() const {
+ return window_->GetProperty(aura::client::kAlwaysOnTopKey);
+}
+
ui::WindowShowState WindowState::GetShowState() const {
return window_->GetProperty(aura::client::kShowStateKey);
}
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index c42461c..99ca7ec 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -135,6 +135,13 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
// TODO(oshima): Change to use RESTORE event.
void Restore();
+ // Caches, then disables always on top state and then stacks |window_| below
+ // |window_on_top| if a |window_| is currently in always on top state.
+ void DisableAlwaysOnTop(aura::Window* window_on_top);
+
+ // Restores always on top state that a window might have cached.
+ void RestoreAlwaysOnTop();
+
// Invoked when a WMevent occurs, which drives the internal
// state machine.
void OnWMEvent(const WMEvent* event);
@@ -318,6 +325,9 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
WindowStateDelegate* delegate() { return delegate_.get(); }
+ // Returns the window's current always_on_top state.
+ bool GetAlwaysOnTop() const;
+
// Returns the window's current show state.
ui::WindowShowState GetShowState() const;
@@ -367,6 +377,7 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
bool hide_shelf_when_fullscreen_;
bool minimum_visibility_;
bool can_be_dragged_;
+ bool cached_always_on_top_;
// A property to remember the window position which was set before the
// auto window position manager changed the window bounds, so that it can get
diff --git a/ash/wm/window_state_delegate.cc b/ash/wm/window_state_delegate.cc
index 0004073..71868d6 100644
--- a/ash/wm/window_state_delegate.cc
+++ b/ash/wm/window_state_delegate.cc
@@ -17,5 +17,9 @@ bool WindowStateDelegate::ToggleFullscreen(WindowState* window_state) {
return false;
}
+bool WindowStateDelegate::RestoreAlwaysOnTop(WindowState* window_state) {
+ return false;
+}
+
} // namespace wm
} // namespace ash
diff --git a/ash/wm/window_state_delegate.h b/ash/wm/window_state_delegate.h
index 53badcf..f3480c3 100644
--- a/ash/wm/window_state_delegate.h
+++ b/ash/wm/window_state_delegate.h
@@ -25,6 +25,11 @@ class ASH_EXPORT WindowStateDelegate {
// returns false.
virtual bool ToggleFullscreen(WindowState* window_state);
+ // Invoked when workspace fullscreen state changes and a window may need to
+ // reassert its always on top state. Returns true if delegate has handled this
+ // and no additional work is needed, false otherwise.
+ virtual bool RestoreAlwaysOnTop(WindowState* window_state);
+
private:
DISALLOW_COPY_AND_ASSIGN(WindowStateDelegate);
};
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 89c26af..d09f4f4 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -184,6 +184,33 @@ void WorkspaceLayoutManager::OnDisplayWorkAreaInsetsChanged() {
backdrop_delegate_->OnDisplayWorkAreaInsetsChanged();
}
+void WorkspaceLayoutManager::OnFullscreenStateChanged(
+ bool is_fullscreen,
+ aura::Window* root_window) {
+ if (window_->GetRootWindow() != root_window ||
+ is_fullscreen_ == is_fullscreen) {
+ return;
+ }
+ is_fullscreen_ = is_fullscreen;
+ Window* fullscreen_window =
+ is_fullscreen
+ ? GetRootWindowController(window_->GetRootWindow())
+ ->GetWindowForFullscreenMode()
+ : NULL;
+ // Changing always on top state may change window's parent. Iterate on a copy
+ // of |windows_| to avoid invalidating an iterator. Since both workspace and
+ // always_on_top containers' layouts are managed by this class all the
+ // appropriate windows will be included in the iteration.
+ WindowSet windows(windows_);
+ for (auto window : windows) {
+ wm::WindowState* window_state = wm::GetWindowState(window);
+ if (is_fullscreen)
+ window_state->DisableAlwaysOnTop(fullscreen_window);
+ else
+ window_state->RestoreAlwaysOnTop();
+ }
+}
+
//////////////////////////////////////////////////////////////////////////////
// WorkspaceLayoutManager, aura::WindowObserver implementation:
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index d5e57ec..06cc9b9 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -70,6 +70,8 @@ class ASH_EXPORT WorkspaceLayoutManager
// ash::ShellObserver overrides:
void OnDisplayWorkAreaInsetsChanged() override;
+ void OnFullscreenStateChanged(bool is_fullscreen,
+ aura::Window* root_window) override;
// Overriden from WindowObserver:
void OnWindowHierarchyChanged(
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 63826fc..5bf7011 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -645,6 +645,34 @@ TEST_F(WorkspaceLayoutManagerSoloTest, Fullscreen) {
EXPECT_EQ(bounds.ToString(), window->bounds().ToString());
}
+// Tests that fullscreen window causes always_on_top windows to stack below.
+TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenSuspendsAlwaysOnTop) {
+ gfx::Rect bounds(100, 100, 200, 200);
+ scoped_ptr<aura::Window> fullscreen_window(CreateTestWindow(bounds));
+ scoped_ptr<aura::Window> always_on_top_window1(CreateTestWindow(bounds));
+ scoped_ptr<aura::Window> always_on_top_window2(CreateTestWindow(bounds));
+ always_on_top_window1->SetProperty(aura::client::kAlwaysOnTopKey, true);
+ always_on_top_window2->SetProperty(aura::client::kAlwaysOnTopKey, true);
+ // Making a window fullscreen temporarily suspends always on top state.
+ fullscreen_window->SetProperty(aura::client::kShowStateKey,
+ ui::SHOW_STATE_FULLSCREEN);
+ EXPECT_FALSE(
+ always_on_top_window1->GetProperty(aura::client::kAlwaysOnTopKey));
+ EXPECT_FALSE(
+ always_on_top_window2->GetProperty(aura::client::kAlwaysOnTopKey));
+ EXPECT_NE(nullptr, GetRootWindowController(fullscreen_window->GetRootWindow())
+ ->GetWindowForFullscreenMode());
+ // Making fullscreen window normal restores always on top windows.
+ fullscreen_window->SetProperty(aura::client::kShowStateKey,
+ ui::SHOW_STATE_NORMAL);
+ EXPECT_TRUE(
+ always_on_top_window1->GetProperty(aura::client::kAlwaysOnTopKey));
+ EXPECT_TRUE(
+ always_on_top_window2->GetProperty(aura::client::kAlwaysOnTopKey));
+ EXPECT_EQ(nullptr, GetRootWindowController(fullscreen_window->GetRootWindow())
+ ->GetWindowForFullscreenMode());
+}
+
// Tests fullscreen window size during root window resize.
TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenRootWindowResize) {
gfx::Rect bounds(100, 100, 200, 200);
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
index 22db788..2adfb24 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
@@ -79,6 +79,12 @@ class NativeAppWindowStateDelegate : public ash::wm::WindowStateDelegate,
return true;
}
+ // Overridden from ash::wm::WindowStateDelegate.
+ bool RestoreAlwaysOnTop(ash::wm::WindowState* window_state) override {
+ app_window_->RestoreAlwaysOnTop();
+ return true;
+ }
+
// Overridden from ash::wm::WindowStateObserver:
void OnPostWindowStateTypeChange(ash::wm::WindowState* window_state,
ash::wm::WindowStateType old_type) override {
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index 4ebc38e..5a40efd 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -472,8 +472,7 @@ void AppWindow::OnNativeWindowChanged() {
fullscreen_types_ = FULLSCREEN_TYPE_NONE;
}
- if (cached_always_on_top_)
- UpdateNativeAlwaysOnTop(); // Same as in SetNativeWindowFullscreen.
+ RestoreAlwaysOnTop(); // Same as in SetNativeWindowFullscreen.
#endif
SaveWindowPosition();
@@ -703,6 +702,11 @@ void AppWindow::SetAlwaysOnTop(bool always_on_top) {
bool AppWindow::IsAlwaysOnTop() const { return cached_always_on_top_; }
+void AppWindow::RestoreAlwaysOnTop() {
+ if (cached_always_on_top_)
+ UpdateNativeAlwaysOnTop();
+}
+
void AppWindow::SetInterceptAllKeys(bool want_all_keys) {
native_app_window_->SetInterceptAllKeys(want_all_keys);
}
@@ -815,8 +819,7 @@ void AppWindow::UpdateExtensionAppIcon() {
void AppWindow::SetNativeWindowFullscreen() {
native_app_window_->SetFullscreen(fullscreen_types_);
- if (cached_always_on_top_)
- UpdateNativeAlwaysOnTop();
+ RestoreAlwaysOnTop();
}
bool AppWindow::IntersectsWithTaskbar() const {
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h
index 10267f6..12eb78d 100644
--- a/extensions/browser/app_window/app_window.h
+++ b/extensions/browser/app_window/app_window.h
@@ -327,6 +327,9 @@ class AppWindow : public content::WebContentsDelegate,
// may be false if the bit is silently switched off for security reasons.
bool IsAlwaysOnTop() const;
+ // Restores the always-on-top property according to |cached_always_on_top_|.
+ void RestoreAlwaysOnTop();
+
// Set whether the window should get even reserved keys (modulo platform
// restrictions).
void SetInterceptAllKeys(bool want_all_keys);