Commit d77a90c6 authored by Qiang Xu's avatar Qiang Xu Committed by Commit Bot

cros: restore bounds on Dis{Re}Connect & Off{On} mirror mode

changes:
- WindowState caches a member for saving PersistentWindowInfo, which is
  saved on OnWillProcessDisplayChanges() and restored on
  OnDisplayConfigurationChanged().
- Saving when it hasn't been saved.
- Restoring when (1) we have saved persistent info, (2) persistent
  display id is a valid display currently, (3) persistent display id
  is not current display id. We could have display position/layout
  changes, in which case we transform the window accordingly.
- Reset saved PersistentWindowInfo each time window bounds have restored
  or when bounds changed by user.

Bug: 805046
Test: ash_unittests --gtest_filter=PersistentWindowControllerTest*
Change-Id: I67426ca17f0d25f92284eb690f849bf77bb748be
Reviewed-on: https://chromium-review.googlesource.com/893644Reviewed-by: default avatarMitsuru Oshima (In Tokyo) <oshima@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Commit-Queue: Qiang Xu <warx@google.com>
Cr-Commit-Position: refs/heads/master@{#537849}
parent b7b5ebe3
...@@ -133,6 +133,10 @@ component("ash") { ...@@ -133,6 +133,10 @@ component("ash") {
"display/null_mouse_warp_controller.h", "display/null_mouse_warp_controller.h",
"display/overscan_calibrator.cc", "display/overscan_calibrator.cc",
"display/overscan_calibrator.h", "display/overscan_calibrator.h",
"display/persistent_window_controller.cc",
"display/persistent_window_controller.h",
"display/persistent_window_info.cc",
"display/persistent_window_info.h",
"display/projecting_observer_chromeos.cc", "display/projecting_observer_chromeos.cc",
"display/projecting_observer_chromeos.h", "display/projecting_observer_chromeos.h",
"display/resolution_notification_controller.cc", "display/resolution_notification_controller.cc",
...@@ -1373,6 +1377,7 @@ test("ash_unittests") { ...@@ -1373,6 +1377,7 @@ test("ash_unittests") {
"display/extended_mouse_warp_controller_unittest.cc", "display/extended_mouse_warp_controller_unittest.cc",
"display/mirror_window_controller_unittest.cc", "display/mirror_window_controller_unittest.cc",
"display/mouse_cursor_event_filter_unittest.cc", "display/mouse_cursor_event_filter_unittest.cc",
"display/persistent_window_controller_unittest.cc",
"display/projecting_observer_chromeos_unittest.cc", "display/projecting_observer_chromeos_unittest.cc",
"display/resolution_notification_controller_unittest.cc", "display/resolution_notification_controller_unittest.cc",
"display/root_window_transformers_unittest.cc", "display/root_window_transformers_unittest.cc",
......
// Copyright 2018 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.
#include "ash/display/persistent_window_controller.h"
#include "ash/display/persistent_window_info.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/window_state.h"
#include "base/command_line.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/screen.h"
namespace ash {
namespace {
display::DisplayManager* GetDisplayManager() {
return Shell::Get()->display_manager();
}
MruWindowTracker::WindowList GetWindowList() {
return Shell::Get()->mru_window_tracker()->BuildWindowForCycleList();
}
// Returns true when window cycle list can be processed to perform save/restore
// operations on observing display changes.
bool ShouldProcessWindowList() {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAshEnablePersistentWindowBounds)) {
return false;
}
// Window cycle list exists in active user session only.
if (Shell::Get()->session_controller()->IsUserSessionBlocked())
return false;
// TODO(warx): Decide on the correct behavior involving mixed mirror mode.
if (GetDisplayManager()->IsInMirrorMode())
return false;
return true;
}
void MaybeRestorePersistentWindowBounds() {
if (!ShouldProcessWindowList())
return;
display::Screen* screen = display::Screen::GetScreen();
for (auto* window : GetWindowList()) {
wm::WindowState* window_state = wm::GetWindowState(window);
if (!window_state->persistent_window_info())
continue;
const auto& persistent_window_info =
*window_state->persistent_window_info();
const int64_t persistent_display_id = persistent_window_info.display_id;
if (persistent_display_id == screen->GetDisplayNearestWindow(window).id())
continue;
const auto& display =
GetDisplayManager()->GetDisplayForId(persistent_display_id);
if (!display.is_valid())
continue;
// Update |persistent_window_bounds| based on |persistent_display_bounds|'s
// position change. This ensures that |persistent_window_bounds| is
// associated with the right target display.
gfx::Rect persistent_window_bounds =
persistent_window_info.window_bounds_in_screen;
const auto& persistent_display_bounds =
persistent_window_info.display_bounds_in_screen;
// It is possible to have display size change, such as changing cable, bad
// cable signal etc., but it should be rare.
DCHECK(display.bounds().size() == persistent_display_bounds.size());
const gfx::Vector2d offset = display.bounds().OffsetFromOrigin() -
persistent_display_bounds.OffsetFromOrigin();
persistent_window_bounds.Offset(offset);
window->SetBoundsInScreen(persistent_window_bounds, display);
// Reset persistent window info everytime the window bounds have restored.
window_state->ResetPersistentWindowInfo();
}
}
} // namespace
PersistentWindowController::PersistentWindowController() {
display::Screen::GetScreen()->AddObserver(this);
Shell::Get()->session_controller()->AddObserver(this);
Shell::Get()->window_tree_host_manager()->AddObserver(this);
}
PersistentWindowController::~PersistentWindowController() {
Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
Shell::Get()->session_controller()->RemoveObserver(this);
display::Screen::GetScreen()->RemoveObserver(this);
}
void PersistentWindowController::OnWillProcessDisplayChanges() {
if (!ShouldProcessWindowList())
return;
for (auto* window : GetWindowList()) {
wm::WindowState* window_state = wm::GetWindowState(window);
// This implies that we keep the first persistent info until they're valid
// to restore, or until they're cleared by user-invoked bounds change.
if (window_state->persistent_window_info())
continue;
window_state->SetPersistentWindowInfo(PersistentWindowInfo(window));
}
}
void PersistentWindowController::OnSessionStateChanged(
session_manager::SessionState state) {
MaybeRestorePersistentWindowBounds();
}
void PersistentWindowController::OnDisplayConfigurationChanged() {
MaybeRestorePersistentWindowBounds();
}
} // namespace ash
// Copyright 2018 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.
#ifndef ASH_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_
#define ASH_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_
#include "ash/ash_export.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/session/session_observer.h"
#include "base/macros.h"
#include "ui/display/display_observer.h"
namespace ash {
// Observes display changes and saves/restores window bounds persistently in
// multi-displays scenario.
class ASH_EXPORT PersistentWindowController
: public display::DisplayObserver,
public SessionObserver,
public WindowTreeHostManager::Observer {
public:
PersistentWindowController();
~PersistentWindowController() override;
private:
// display::DisplayObserver:
void OnWillProcessDisplayChanges() override;
// SessionObserver:
void OnSessionStateChanged(session_manager::SessionState state) override;
// WindowTreeHostManager::Observer:
void OnDisplayConfigurationChanged() override;
DISALLOW_COPY_AND_ASSIGN(PersistentWindowController);
};
} // namespace ash
#endif // ASH_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_
// Copyright 2018 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.
#include "ash/display/persistent_window_controller.h"
#include "ash/display/display_move_window_util.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/session/test_session_controller_client.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
using session_manager::SessionState;
namespace ash {
class PersistentWindowControllerTest : public AshTestBase {
protected:
PersistentWindowControllerTest() = default;
~PersistentWindowControllerTest() override = default;
// AshTestBase:
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAshEnableDisplayMoveWindowAccels);
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAshEnablePersistentWindowBounds);
AshTestBase::SetUp();
}
private:
DISALLOW_COPY_AND_ASSIGN(PersistentWindowControllerTest);
};
TEST_F(PersistentWindowControllerTest, DisconnectDisplay) {
UpdateDisplay("0+0-500x500,0+501-500x500");
aura::Window* w1 =
CreateTestWindowInShellWithBounds(gfx::Rect(200, 0, 100, 200));
aura::Window* w2 =
CreateTestWindowInShellWithBounds(gfx::Rect(501, 0, 200, 100));
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
const int64_t primary_id = WindowTreeHostManager::GetPrimaryDisplayId();
const int64_t secondary_id = display_manager()->GetSecondaryDisplay().id();
display::ManagedDisplayInfo primary_info =
display_manager()->GetDisplayInfo(primary_id);
display::ManagedDisplayInfo secondary_info =
display_manager()->GetDisplayInfo(secondary_id);
// Disconnects secondary display.
std::vector<display::ManagedDisplayInfo> display_info_list;
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Reconnects secondary display.
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
// Disconnects primary display.
display_info_list.clear();
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Reconnects primary display.
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
// Disconnects secondary display.
display_info_list.clear();
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
// A third id which is different from primary and secondary.
const int64_t third_id = secondary_id + 1;
display::ManagedDisplayInfo third_info =
display::CreateDisplayInfo(third_id, gfx::Rect(0, 501, 500, 500));
// Connects another secondary display with |third_id|.
display_info_list.push_back(third_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Connects secondary display with |secondary_id|.
display_info_list.clear();
display_info_list.push_back(primary_info);
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
// Disconnects secondary display.
display_info_list.clear();
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
// Sets |w2|'s bounds changed by user and then reconnects secondary display.
wm::WindowState* w2_state = wm::GetWindowState(w2);
w2_state->set_bounds_changed_by_user(true);
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
}
TEST_F(PersistentWindowControllerTest, ThreeDisplays) {
UpdateDisplay("0+0-500x500,0+501-500x500,0+1002-500x500");
aura::Window* w1 =
CreateTestWindowInShellWithBounds(gfx::Rect(200, 0, 100, 200));
aura::Window* w2 =
CreateTestWindowInShellWithBounds(gfx::Rect(501, 0, 200, 100));
aura::Window* w3 =
CreateTestWindowInShellWithBounds(gfx::Rect(1002, 0, 400, 200));
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1002, 0, 400, 200), w3->GetBoundsInScreen());
const int64_t primary_id = display_manager()->GetDisplayAt(0).id();
const int64_t second_id = display_manager()->GetDisplayAt(1).id();
const int64_t third_id = display_manager()->GetDisplayAt(2).id();
display::ManagedDisplayInfo primary_info =
display_manager()->GetDisplayInfo(primary_id);
display::ManagedDisplayInfo second_info =
display_manager()->GetDisplayInfo(second_id);
display::ManagedDisplayInfo third_info =
display_manager()->GetDisplayInfo(third_id);
// Disconnects third display.
std::vector<display::ManagedDisplayInfo> display_info_list;
display_info_list.push_back(primary_info);
display_info_list.push_back(second_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(2, 0, 400, 200), w3->GetBoundsInScreen());
// Disconnects second display.
display_info_list.clear();
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(2, 0, 400, 200), w3->GetBoundsInScreen());
// Reconnects third display.
display_info_list.push_back(third_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(502, 0, 400, 200), w3->GetBoundsInScreen());
// Reconnects second display.
display_info_list.push_back(second_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1002, 0, 400, 200), w3->GetBoundsInScreen());
// Disconnects both external displays.
display_info_list.clear();
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(2, 0, 400, 200), w3->GetBoundsInScreen());
// Reconnects second display.
display_info_list.push_back(second_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(2, 0, 400, 200), w3->GetBoundsInScreen());
// Reconnects third display.
display_info_list.push_back(third_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1002, 0, 400, 200), w3->GetBoundsInScreen());
}
TEST_F(PersistentWindowControllerTest, EnableAndDisableMirrorMode) {
UpdateDisplay("0+0-500x500,0+501-500x500");
aura::Window* w1 =
CreateTestWindowInShellWithBounds(gfx::Rect(200, 0, 100, 200));
aura::Window* w2 =
CreateTestWindowInShellWithBounds(gfx::Rect(501, 0, 200, 100));
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
// Enables mirror mode.
display_manager()->SetMirrorMode(display::MirrorMode::kNormal, base::nullopt);
EXPECT_TRUE(display_manager()->IsInMirrorMode());
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Disables mirror mode.
display_manager()->SetMirrorMode(display::MirrorMode::kOff, base::nullopt);
EXPECT_FALSE(display_manager()->IsInMirrorMode());
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
}
TEST_F(PersistentWindowControllerTest, WindowMovedByAccel) {
UpdateDisplay("0+0-500x500,0+501-500x500");
aura::Window* w1 =
CreateTestWindowInShellWithBounds(gfx::Rect(200, 0, 100, 200));
aura::Window* w2 =
CreateTestWindowInShellWithBounds(gfx::Rect(501, 0, 200, 100));
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
const int64_t primary_id = WindowTreeHostManager::GetPrimaryDisplayId();
const int64_t secondary_id = display_manager()->GetSecondaryDisplay().id();
display::ManagedDisplayInfo primary_info =
display_manager()->GetDisplayInfo(primary_id);
display::ManagedDisplayInfo secondary_info =
display_manager()->GetDisplayInfo(secondary_id);
// Disconnects secondary display.
std::vector<display::ManagedDisplayInfo> display_info_list;
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Reconnects secondary display.
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
// Moves |w2| to primary display by accelerators after we reset the persistent
// window info. It should be able to save persistent window info again on next
// display change.
wm::ActivateWindow(w2);
HandleMoveActiveWindowToDisplay(DisplayMoveWindowDirection::kLeft);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Disconnects secondary display.
display_info_list.clear();
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Reconnects secondary display.
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
}
TEST_F(PersistentWindowControllerTest, ReconnectOnLockScreen) {
UpdateDisplay("0+0-500x500,0+501-500x500");
aura::Window* w1 =
CreateTestWindowInShellWithBounds(gfx::Rect(200, 0, 100, 200));
aura::Window* w2 =
CreateTestWindowInShellWithBounds(gfx::Rect(501, 0, 200, 100));
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
const int64_t primary_id = WindowTreeHostManager::GetPrimaryDisplayId();
const int64_t secondary_id = display_manager()->GetSecondaryDisplay().id();
display::ManagedDisplayInfo primary_info =
display_manager()->GetDisplayInfo(primary_id);
display::ManagedDisplayInfo secondary_info =
display_manager()->GetDisplayInfo(secondary_id);
// Disconnects secondary display.
std::vector<display::ManagedDisplayInfo> display_info_list;
display_info_list.push_back(primary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Spin a run loop to ensure shelf is deleted. https://crbug.com/810807.
base::RunLoop().RunUntilIdle();
// Enters locked session state and reconnects secondary display.
GetSessionControllerClient()->SetSessionState(SessionState::LOCKED);
display_info_list.push_back(secondary_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(1, 0, 200, 100), w2->GetBoundsInScreen());
// Unlocks and checks that |w2| is restored.
GetSessionControllerClient()->SetSessionState(SessionState::ACTIVE);
EXPECT_EQ(gfx::Rect(200, 0, 100, 200), w1->GetBoundsInScreen());
EXPECT_EQ(gfx::Rect(501, 0, 200, 100), w2->GetBoundsInScreen());
}
} // namespace ash
// Copyright 2018 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.
#include "ash/display/persistent_window_info.h"
#include "ui/aura/window.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
namespace ash {
PersistentWindowInfo::PersistentWindowInfo(aura::Window* window) {
const auto& display =
display::Screen::GetScreen()->GetDisplayNearestWindow(window);
window_bounds_in_screen = window->GetBoundsInScreen();
display_id = display.id();
display_bounds_in_screen = display.bounds();
}
PersistentWindowInfo::~PersistentWindowInfo() = default;
} // namespace ash
// Copyright 2018 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.
#ifndef ASH_DISPLAY_PERSISTENT_WINDOW_INFO_H_
#define ASH_DISPLAY_PERSISTENT_WINDOW_INFO_H_
#include <stdint.h>
#include "ash/ash_export.h"
#include "ui/gfx/geometry/rect.h"
namespace aura {
class Window;
} // namespace aura
namespace ash {
// Describes the information that each window needs to carry for persistent
// window placement in multi-displays scenario.
struct ASH_EXPORT PersistentWindowInfo {
explicit PersistentWindowInfo(aura::Window* window);
~PersistentWindowInfo();
// Persistent window bounds in screen coordinates.
gfx::Rect window_bounds_in_screen;
// Indicates the display to restore to when available.
int64_t display_id;
// Indicates last display bounds for |display_id| in screen coordinates.
gfx::Rect display_bounds_in_screen;
};
} // namespace ash
#endif // ASH_DISPLAY_PERSISTENT_WINDOW_INFO_H_
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "ash/display/display_shutdown_observer.h" #include "ash/display/display_shutdown_observer.h"
#include "ash/display/event_transformation_handler.h" #include "ash/display/event_transformation_handler.h"
#include "ash/display/mouse_cursor_event_filter.h" #include "ash/display/mouse_cursor_event_filter.h"
#include "ash/display/persistent_window_controller.h"
#include "ash/display/projecting_observer_chromeos.h" #include "ash/display/projecting_observer_chromeos.h"
#include "ash/display/resolution_notification_controller.h" #include "ash/display/resolution_notification_controller.h"
#include "ash/display/screen_ash.h" #include "ash/display/screen_ash.h"
...@@ -726,6 +727,8 @@ Shell::~Shell() { ...@@ -726,6 +727,8 @@ Shell::~Shell() {
// Controllers who have WindowObserver added must be deleted // Controllers who have WindowObserver added must be deleted
// before |window_tree_host_manager_| is deleted. // before |window_tree_host_manager_| is deleted.
persistent_window_controller_.reset();
// VideoActivityNotifier must be deleted before |video_detector_| is // VideoActivityNotifier must be deleted before |video_detector_| is
// deleted because it's observing video activity through // deleted because it's observing video activity through
// VideoDetector::Observer interface. // VideoDetector::Observer interface.
...@@ -1166,6 +1169,8 @@ void Shell::InitializeDisplayManager() { ...@@ -1166,6 +1169,8 @@ void Shell::InitializeDisplayManager() {
display_manager_.get(), window_tree_host_manager_.get()); display_manager_.get(), window_tree_host_manager_.get());
display_configurator_->Init(shell_port_->CreateNativeDisplayDelegate(), display_configurator_->Init(shell_port_->CreateNativeDisplayDelegate(),
false); false);
persistent_window_controller_ =
std::make_unique<PersistentWindowController>();
projecting_observer_ = projecting_observer_ =
std::make_unique<ProjectingObserver>(display_configurator_.get()); std::make_unique<ProjectingObserver>(display_configurator_.get());
......
...@@ -125,6 +125,7 @@ class NoteTakingController; ...@@ -125,6 +125,7 @@ class NoteTakingController;
class OverlayEventFilter; class OverlayEventFilter;
class PartialMagnificationController; class PartialMagnificationController;
class PeripheralBatteryNotifier; class PeripheralBatteryNotifier;
class PersistentWindowController;
class PowerButtonController; class PowerButtonController;
class PowerEventObserver; class PowerEventObserver;
class ProjectingObserver; class ProjectingObserver;
...@@ -696,6 +697,7 @@ class ASH_EXPORT Shell : public SessionObserver, ...@@ -696,6 +697,7 @@ class ASH_EXPORT Shell : public SessionObserver,
std::unique_ptr<ui::UserActivityDetector> user_activity_detector_; std::unique_ptr<ui::UserActivityDetector> user_activity_detector_;
std::unique_ptr<VideoDetector> video_detector_; std::unique_ptr<VideoDetector> video_detector_;
std::unique_ptr<WindowTreeHostManager> window_tree_host_manager_; std::unique_ptr<WindowTreeHostManager> window_tree_host_manager_;
std::unique_ptr<PersistentWindowController> persistent_window_controller_;
std::unique_ptr<HighContrastController> high_contrast_controller_; std::unique_ptr<HighContrastController> high_contrast_controller_;
std::unique_ptr<MagnificationController> magnification_controller_; std::unique_ptr<MagnificationController> magnification_controller_;
std::unique_ptr<AutoclickController> autoclick_controller_; std::unique_ptr<AutoclickController> autoclick_controller_;
......
...@@ -385,6 +385,15 @@ void WindowState::SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds) { ...@@ -385,6 +385,15 @@ void WindowState::SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds) {
pre_added_to_workspace_window_bounds_ = base::make_optional(bounds); pre_added_to_workspace_window_bounds_ = base::make_optional(bounds);
} }
void WindowState::SetPersistentWindowInfo(
const PersistentWindowInfo& persistent_window_info) {
persistent_window_info_ = base::make_optional(persistent_window_info);
}
void WindowState::ResetPersistentWindowInfo() {
persistent_window_info_.reset();
}
void WindowState::AddObserver(WindowStateObserver* observer) { void WindowState::AddObserver(WindowStateObserver* observer) {
observer_list_.AddObserver(observer); observer_list_.AddObserver(observer);
} }
...@@ -432,6 +441,7 @@ void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) { ...@@ -432,6 +441,7 @@ void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) {
if (bounds_changed_by_user) { if (bounds_changed_by_user) {
pre_auto_manage_window_bounds_.reset(); pre_auto_manage_window_bounds_.reset();
pre_added_to_workspace_window_bounds_.reset(); pre_added_to_workspace_window_bounds_.reset();
persistent_window_info_.reset();
} }
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/display/persistent_window_info.h"
#include "ash/public/interfaces/window_state_type.mojom.h" #include "ash/public/interfaces/window_state_type.mojom.h"
#include "ash/wm/drag_details.h" #include "ash/wm/drag_details.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
...@@ -238,17 +239,26 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -238,17 +239,26 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
// Gets/Sets the bounds of the window before it was moved by the auto window // Gets/Sets the bounds of the window before it was moved by the auto window
// management. As long as it was not auto-managed, it will return NULL. // management. As long as it was not auto-managed, it will return NULL.
base::Optional<gfx::Rect> pre_auto_manage_window_bounds() const { const base::Optional<gfx::Rect> pre_auto_manage_window_bounds() {
return pre_auto_manage_window_bounds_; return pre_auto_manage_window_bounds_;
} }
void SetPreAutoManageWindowBounds(const gfx::Rect& bounds); void SetPreAutoManageWindowBounds(const gfx::Rect& bounds);
// Gets/Sets the property that is used on window added to workspace event. // Gets/Sets the property that is used on window added to workspace event.
base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds() const { const base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds() {
return pre_added_to_workspace_window_bounds_; return pre_added_to_workspace_window_bounds_;
} }
void SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds); void SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds);
// Gets/Sets the persistent window info that is used on restoring persistent
// window bounds in multi-displays scenario.
const base::Optional<PersistentWindowInfo> persistent_window_info() {
return persistent_window_info_;
}
void SetPersistentWindowInfo(
const PersistentWindowInfo& persistent_window_info);
void ResetPersistentWindowInfo();
// Layout related properties // Layout related properties
void AddObserver(WindowStateObserver* observer); void AddObserver(WindowStateObserver* observer);
...@@ -426,6 +436,11 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -426,6 +436,11 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
// nullptr, and window is removing from a workspace. // nullptr, and window is removing from a workspace.
base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds_; base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds_;
// A property to remember the persistent window info used in multi-displays
// scenario to attempt to restore windows to their original bounds when
// displays are restored to their previous states.
base::Optional<PersistentWindowInfo> persistent_window_info_;
base::ObserverList<WindowStateObserver> observer_list_; base::ObserverList<WindowStateObserver> observer_list_;
// True to ignore a property change event to avoid reentrance in // True to ignore a property change event to avoid reentrance in
......
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