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") {
"display/null_mouse_warp_controller.h",
"display/overscan_calibrator.cc",
"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.h",
"display/resolution_notification_controller.cc",
......@@ -1373,6 +1377,7 @@ test("ash_unittests") {
"display/extended_mouse_warp_controller_unittest.cc",
"display/mirror_window_controller_unittest.cc",
"display/mouse_cursor_event_filter_unittest.cc",
"display/persistent_window_controller_unittest.cc",
"display/projecting_observer_chromeos_unittest.cc",
"display/resolution_notification_controller_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_
This diff is collapsed.
// 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 @@
#include "ash/display/display_shutdown_observer.h"
#include "ash/display/event_transformation_handler.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/resolution_notification_controller.h"
#include "ash/display/screen_ash.h"
......@@ -726,6 +727,8 @@ Shell::~Shell() {
// Controllers who have WindowObserver added must be deleted
// before |window_tree_host_manager_| is deleted.
persistent_window_controller_.reset();
// VideoActivityNotifier must be deleted before |video_detector_| is
// deleted because it's observing video activity through
// VideoDetector::Observer interface.
......@@ -1166,6 +1169,8 @@ void Shell::InitializeDisplayManager() {
display_manager_.get(), window_tree_host_manager_.get());
display_configurator_->Init(shell_port_->CreateNativeDisplayDelegate(),
false);
persistent_window_controller_ =
std::make_unique<PersistentWindowController>();
projecting_observer_ =
std::make_unique<ProjectingObserver>(display_configurator_.get());
......
......@@ -125,6 +125,7 @@ class NoteTakingController;
class OverlayEventFilter;
class PartialMagnificationController;
class PeripheralBatteryNotifier;
class PersistentWindowController;
class PowerButtonController;
class PowerEventObserver;
class ProjectingObserver;
......@@ -696,6 +697,7 @@ class ASH_EXPORT Shell : public SessionObserver,
std::unique_ptr<ui::UserActivityDetector> user_activity_detector_;
std::unique_ptr<VideoDetector> video_detector_;
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<MagnificationController> magnification_controller_;
std::unique_ptr<AutoclickController> autoclick_controller_;
......
......@@ -385,6 +385,15 @@ void WindowState::SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& 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) {
observer_list_.AddObserver(observer);
}
......@@ -432,6 +441,7 @@ void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) {
if (bounds_changed_by_user) {
pre_auto_manage_window_bounds_.reset();
pre_added_to_workspace_window_bounds_.reset();
persistent_window_info_.reset();
}
}
......
......@@ -8,6 +8,7 @@
#include <memory>
#include "ash/ash_export.h"
#include "ash/display/persistent_window_info.h"
#include "ash/public/interfaces/window_state_type.mojom.h"
#include "ash/wm/drag_details.h"
#include "base/gtest_prod_util.h"
......@@ -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
// 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_;
}
void SetPreAutoManageWindowBounds(const gfx::Rect& bounds);
// 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_;
}
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
void AddObserver(WindowStateObserver* observer);
......@@ -426,6 +436,11 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
// nullptr, and window is removing from a workspace.
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_;
// 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