Commit 269d5135 authored by Sammie Quon's avatar Sammie Quon Committed by Commit Bot

wm: Only store persistent bounds when removing display.

Without this, we can get some cases where a non-remove display change
can get some persistent bounds stored and won't get overwritten when
a remove display change happens.

Introduce a mechanism where persistent bounds are calculated when a
display change signal is received, but not written to the window
state unless a remove signal is received.

Test: manual, added tests
Bug: 1115675
Change-Id: Id3b642d5912510c451e78a0f9227437d1ce2de1b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2353065Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797895}
parent f73a8722
...@@ -46,11 +46,9 @@ constexpr char PersistentWindowController::kNumOfWindowsRestoredHistogramName[]; ...@@ -46,11 +46,9 @@ constexpr char PersistentWindowController::kNumOfWindowsRestoredHistogramName[];
PersistentWindowController::PersistentWindowController() { PersistentWindowController::PersistentWindowController() {
display::Screen::GetScreen()->AddObserver(this); display::Screen::GetScreen()->AddObserver(this);
Shell::Get()->window_tree_host_manager()->AddObserver(this);
} }
PersistentWindowController::~PersistentWindowController() { PersistentWindowController::~PersistentWindowController() {
Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
display::Screen::GetScreen()->RemoveObserver(this); display::Screen::GetScreen()->RemoveObserver(this);
} }
...@@ -64,7 +62,10 @@ void PersistentWindowController::OnWillProcessDisplayChanges() { ...@@ -64,7 +62,10 @@ void PersistentWindowController::OnWillProcessDisplayChanges() {
// to restore, or until they're cleared by user-invoked bounds change. // to restore, or until they're cleared by user-invoked bounds change.
if (window_state->persistent_window_info()) if (window_state->persistent_window_info())
continue; continue;
window_state->SetPersistentWindowInfo(PersistentWindowInfo(window)); // Place the window that needs persistent window info into the temporary
// set. The persistent window info will be created and set if a display is
// removed.
need_persistent_info_windows_.Add(window);
} }
} }
...@@ -75,16 +76,25 @@ void PersistentWindowController::OnDisplayAdded( ...@@ -75,16 +76,25 @@ void PersistentWindowController::OnDisplayAdded(
base::Unretained(this)); base::Unretained(this));
} }
void PersistentWindowController::OnDisplayConfigurationChanged() { void PersistentWindowController::OnDisplayRemoved(
const display::Display& old_display) {
for (aura::Window* window : need_persistent_info_windows_.windows()) {
WindowState* window_state = WindowState::Get(window);
window_state->SetPersistentWindowInfo(PersistentWindowInfo(window));
}
need_persistent_info_windows_.RemoveAll();
}
void PersistentWindowController::OnDidProcessDisplayChanges() {
if (restore_callback_) if (restore_callback_)
std::move(restore_callback_).Run(); std::move(restore_callback_).Run();
need_persistent_info_windows_.RemoveAll();
} }
void PersistentWindowController::MaybeRestorePersistentWindowBounds() { void PersistentWindowController::MaybeRestorePersistentWindowBounds() {
if (!ShouldProcessWindowList()) if (!ShouldProcessWindowList())
return; return;
display::Screen* screen = display::Screen::GetScreen();
int window_restored_count = 0; int window_restored_count = 0;
// Maybe add the windows to a new display via SetBoundsInScreen() depending on // Maybe add the windows to a new display via SetBoundsInScreen() depending on
// their persistent window info. Go backwards so that if they do get added to // their persistent window info. Go backwards so that if they do get added to
...@@ -98,8 +108,6 @@ void PersistentWindowController::MaybeRestorePersistentWindowBounds() { ...@@ -98,8 +108,6 @@ void PersistentWindowController::MaybeRestorePersistentWindowBounds() {
PersistentWindowInfo persistent_window_info = PersistentWindowInfo persistent_window_info =
*window_state->persistent_window_info(); *window_state->persistent_window_info();
const int64_t persistent_display_id = persistent_window_info.display_id; const int64_t persistent_display_id = persistent_window_info.display_id;
if (persistent_display_id == screen->GetDisplayNearestWindow(window).id())
continue;
auto* display_manager = GetDisplayManager(); auto* display_manager = GetDisplayManager();
if (!display_manager->IsDisplayIdValid(persistent_display_id)) if (!display_manager->IsDisplayIdValid(persistent_display_id))
continue; continue;
...@@ -115,7 +123,8 @@ void PersistentWindowController::MaybeRestorePersistentWindowBounds() { ...@@ -115,7 +123,8 @@ void PersistentWindowController::MaybeRestorePersistentWindowBounds() {
persistent_window_info.display_bounds_in_screen; persistent_window_info.display_bounds_in_screen;
// It is possible to have display size change, such as changing cable, bad // It is possible to have display size change, such as changing cable, bad
// cable signal etc., but it should be rare. // cable signal etc., but it should be rare.
DCHECK(display.bounds().size() == persistent_display_bounds.size()); if (display.bounds().size() != persistent_display_bounds.size())
continue;
const gfx::Vector2d offset = display.bounds().OffsetFromOrigin() - const gfx::Vector2d offset = display.bounds().OffsetFromOrigin() -
persistent_display_bounds.OffsetFromOrigin(); persistent_display_bounds.OffsetFromOrigin();
persistent_window_bounds.Offset(offset); persistent_window_bounds.Offset(offset);
......
...@@ -6,17 +6,15 @@ ...@@ -6,17 +6,15 @@
#define ASH_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_ #define ASH_DISPLAY_PERSISTENT_WINDOW_CONTROLLER_H_
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/display/window_tree_host_manager.h"
#include "base/callback.h" #include "base/callback.h"
#include "ui/aura/window_tracker.h"
#include "ui/display/display_observer.h" #include "ui/display/display_observer.h"
namespace ash { namespace ash {
// Observes display changes and saves/restores window bounds persistently in // Observes display changes and saves/restores window bounds persistently in
// multi-displays scenario. // multi-displays scenario.
class ASH_EXPORT PersistentWindowController class ASH_EXPORT PersistentWindowController : public display::DisplayObserver {
: public display::DisplayObserver,
public WindowTreeHostManager::Observer {
public: public:
// Public so it can be used by unit tests. // Public so it can be used by unit tests.
constexpr static char kNumOfWindowsRestoredHistogramName[] = constexpr static char kNumOfWindowsRestoredHistogramName[] =
...@@ -32,15 +30,18 @@ class ASH_EXPORT PersistentWindowController ...@@ -32,15 +30,18 @@ class ASH_EXPORT PersistentWindowController
// display::DisplayObserver: // display::DisplayObserver:
void OnWillProcessDisplayChanges() override; void OnWillProcessDisplayChanges() override;
void OnDisplayAdded(const display::Display& new_display) override; void OnDisplayAdded(const display::Display& new_display) override;
void OnDisplayRemoved(const display::Display& old_display) override;
// WindowTreeHostManager::Observer: void OnDidProcessDisplayChanges() override;
void OnDisplayConfigurationChanged() override;
// Called when restoring persistent window placement is wanted. // Called when restoring persistent window placement is wanted.
void MaybeRestorePersistentWindowBounds(); void MaybeRestorePersistentWindowBounds();
// Callback binded on display added and run on display configuration changed. // Callback binded on display added and run on display changes are processed.
base::OnceCallback<void()> restore_callback_; base::OnceClosure restore_callback_;
// Temporary storage that stores windows that may need persistent info
// stored on display removal. Cleared when display changes are processed.
aura::WindowTracker need_persistent_info_windows_;
}; };
} // namespace ash } // namespace ash
......
...@@ -606,4 +606,43 @@ TEST_F(PersistentWindowControllerTest, MRUOrderMatchesStackingInterleaved) { ...@@ -606,4 +606,43 @@ TEST_F(PersistentWindowControllerTest, MRUOrderMatchesStackingInterleaved) {
EXPECT_EQ(window4.get(), parent->children()[1]); EXPECT_EQ(window4.get(), parent->children()[1]);
} }
// Tests that if a window is on a primary display which gets disconnected, on
// reconnect the windows bounds will be persisted.
TEST_F(PersistentWindowControllerTest, DisconnectingPrimaryDisplay) {
// Create two displays with the one higher resolution.
UpdateDisplay("0+0-500x500,0+501-1500x500");
const int64_t small_id = WindowTreeHostManager::GetPrimaryDisplayId();
const int64_t large_id =
display::test::DisplayManagerTestApi(display_manager())
.GetSecondaryDisplay()
.id();
// Set the larger display to be the primary display.
Shell::Get()->window_tree_host_manager()->SetPrimaryDisplayId(large_id);
ASSERT_EQ(large_id, WindowTreeHostManager::GetPrimaryDisplayId());
// Add a window on the larger display.
const gfx::Rect bounds(0, 200, 1500, 200);
std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
// Disconnect the large display. The windows should move to the new primary
// display (small display) and shrink to fit.
display::ManagedDisplayInfo small_info =
display_manager()->GetDisplayInfo(small_id);
display::ManagedDisplayInfo large_info =
display_manager()->GetDisplayInfo(large_id);
std::vector<display::ManagedDisplayInfo> display_info_list;
display_info_list.push_back(small_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(small_id, WindowTreeHostManager::GetPrimaryDisplayId());
EXPECT_EQ(gfx::Size(500, 200), window->bounds().size());
// Reconnect the large display. The window should move back and have the old
// size.
display_info_list.push_back(large_info);
display_manager()->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(large_id, WindowTreeHostManager::GetPrimaryDisplayId());
EXPECT_EQ(gfx::Size(1500, 200), window->bounds().size());
}
} // namespace ash } // namespace ash
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