diff options
author | varkha <varkha@chromium.org> | 2015-06-29 15:35:46 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-29 22:37:23 +0000 |
commit | d99fa94f20bd74f7837ce3df44052ce2a707ab83 (patch) | |
tree | ac0d7c45a2263c50315ba530aa387fe106253d4d | |
parent | 97236cc8f139bb6cba9ddd1a34a4889fe0b4a66f (diff) | |
download | chromium_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.cc | 6 | ||||
-rw-r--r-- | ash/root_window_controller.h | 2 | ||||
-rw-r--r-- | ash/wm/window_state.cc | 37 | ||||
-rw-r--r-- | ash/wm/window_state.h | 11 | ||||
-rw-r--r-- | ash/wm/window_state_delegate.cc | 4 | ||||
-rw-r--r-- | ash/wm/window_state_delegate.h | 5 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager.cc | 27 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager.h | 2 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager_unittest.cc | 28 | ||||
-rw-r--r-- | chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc | 6 | ||||
-rw-r--r-- | extensions/browser/app_window/app_window.cc | 11 | ||||
-rw-r--r-- | extensions/browser/app_window/app_window.h | 3 |
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); |