Commit fee7a0a3 authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

Refactor WorkspaceController into a window property

This makes it possible to store the WorkspaceController as a property
of desks containers instead of tracking each in the RootWindowController

BUG=866622
TEST=ash_unittests pass.

Change-Id: I7f47c3c9adecbfb03a4b374bc36f57d2ec3dbc1f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1553715Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#648387}
parent 6dffa38b
......@@ -149,10 +149,13 @@ bool IsLastEventInTopHalf(const gfx::Point& location_in_screen,
// Returns the window of the widget which contains the workspace backdrop. May
// be nullptr if the backdrop is not shown.
aura::Window* GetBackdropWindow(aura::Window* window) {
WorkspaceController* workspace_controller =
GetWorkspaceControllerForContext(window);
DCHECK(workspace_controller);
WorkspaceLayoutManager* layout_manager =
RootWindowController::ForWindow(window->GetRootWindow())
->workspace_controller()
->layout_manager();
workspace_controller->layout_manager();
return layout_manager
? layout_manager->backdrop_controller()->backdrop_window()
: nullptr;
......
......@@ -43,6 +43,7 @@
#include "ash/window_factory.h"
#include "ash/wm/always_on_top_controller.h"
#include "ash/wm/container_finder.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/fullscreen_window_finder.h"
#include "ash/wm/lock_action_handler_layout_manager.h"
#include "ash/wm/lock_layout_manager.h"
......@@ -275,6 +276,13 @@ bool ShouldDestroyWindowInCloseChildWindows(aura::Window* window) {
return window->owned_by_parent();
}
// Clears the workspace controllers from the properties of all virtual desks
// containers in |root|.
void ClearWorkspaceControllers(aura::Window* root) {
for (auto* desk_container : desks_util::GetDesksContainers(root))
SetWorkspaceController(desk_container, nullptr);
}
class RootWindowTargeter : public aura::WindowTargeter {
public:
RootWindowTargeter() = default;
......@@ -409,11 +417,6 @@ const aura::Window* RootWindowController::GetRootWindow() const {
return GetHost()->window();
}
wm::WorkspaceWindowState RootWindowController::GetWorkspaceWindowState() {
return workspace_controller_ ? workspace_controller()->GetWindowState()
: wm::WORKSPACE_WINDOW_STATE_DEFAULT;
}
void RootWindowController::InitializeShelf() {
if (shelf_initialized_)
return;
......@@ -565,12 +568,12 @@ void RootWindowController::CloseChildWindows() {
shelf_->ShutdownShelfWidget();
workspace_controller_.reset();
aura::Window* root = GetRootWindow();
ClearWorkspaceControllers(root);
// Explicitly destroy top level windows. We do this because such windows may
// query the RootWindow for state.
aura::WindowTracker non_toplevel_windows;
aura::Window* root = GetRootWindow();
non_toplevel_windows.Add(root);
while (!non_toplevel_windows.windows().empty()) {
aura::Window* non_toplevel_window = non_toplevel_windows.Pop();
......@@ -604,9 +607,17 @@ void RootWindowController::CloseChildWindows() {
}
void RootWindowController::MoveWindowsTo(aura::Window* dst) {
// Clear the workspace controller, so it doesn't incorrectly update the shelf.
workspace_controller_.reset();
ReparentAllWindows(GetRootWindow(), dst);
// Suspend unnecessary updates of the shelf visibility.
shelf_->SetSuspendVisibilityUpdate(true);
// Clear the workspace controller to avoid a lot of unnessary operations when
// window are removed.
// TODO(afakhry): Should we also clear the WorkspaceLayoutManagers of the pip,
// always-on-top, and other containers?
aura::Window* root = GetRootWindow();
ClearWorkspaceControllers(root);
ReparentAllWindows(root, dst);
}
void RootWindowController::UpdateShelfVisibility() {
......@@ -763,10 +774,10 @@ void RootWindowController::InitLayoutManagers() {
root_window_layout_manager_ = new wm::RootWindowLayoutManager(root);
root->SetLayoutManager(root_window_layout_manager_);
aura::Window* default_container =
GetContainer(kShellWindowId_DefaultContainer);
// Installs WorkspaceLayoutManager on |default_container|.
workspace_controller_.reset(new WorkspaceController(default_container));
for (auto* container : desks_util::GetDesksContainers(root)) {
// Installs WorkspaceLayoutManager on the container.
SetWorkspaceController(container, new WorkspaceController(container));
}
aura::Window* modal_container =
GetContainer(kShellWindowId_SystemModalContainer);
......@@ -868,13 +879,18 @@ void RootWindowController::CreateContainers() {
CreateContainer(kShellWindowId_UnparentedControlContainer,
"UnparentedControlContainer", non_lock_screen_containers);
aura::Window* default_container =
CreateContainer(kShellWindowId_DefaultContainer, "DefaultContainer",
non_lock_screen_containers);
::wm::SetChildWindowVisibilityChangesAnimated(default_container);
wm::SetSnapsChildrenToPhysicalPixelBoundary(default_container);
default_container->SetProperty(::wm::kUsesScreenCoordinatesKey, true);
wm::SetChildrenUseExtendedHitRegionForWindow(default_container);
for (const auto& id : desks_util::GetDesksContainersIds()) {
aura::Window* container = CreateContainer(
id, desks_util::GetDeskContainerName(id), non_lock_screen_containers);
::wm::SetChildWindowVisibilityChangesAnimated(container);
wm::SetSnapsChildrenToPhysicalPixelBoundary(container);
container->SetProperty(::wm::kUsesScreenCoordinatesKey, true);
wm::SetChildrenUseExtendedHitRegionForWindow(container);
// Hide the non-active containers.
if (id != desks_util::GetActiveDeskContainerId())
container->Hide();
}
aura::Window* always_on_top_container =
CreateContainer(kShellWindowId_AlwaysOnTopContainer,
......
......@@ -54,7 +54,6 @@ class TouchObserverHUD;
class WallpaperWidgetController;
class WindowManager;
class WorkAreaInsets;
class WorkspaceController;
namespace wm {
class RootWindowLayoutManager;
......@@ -103,12 +102,6 @@ class ASH_EXPORT RootWindowController {
aura::Window* GetRootWindow();
const aura::Window* GetRootWindow() const;
WorkspaceController* workspace_controller() {
return workspace_controller_.get();
}
wm::WorkspaceWindowState GetWorkspaceWindowState();
Shelf* shelf() const { return shelf_.get(); }
TouchObserverHUD* touch_observer_hud() const { return touch_observer_hud_; }
......@@ -183,6 +176,10 @@ class ASH_EXPORT RootWindowController {
void CloseChildWindows();
// Moves child windows to |dest|.
// TODO(afakhry): Consider renaming this function to avoid misuse. It is only
// called by WindowTreeHostManager::DeleteHost(), and has destructive side
// effects like deleting the workspace controllers, so it shouldn't be called
// for something else.
void MoveWindowsTo(aura::Window* dest);
// Force the shelf to query for it's current visibility state.
......@@ -267,7 +264,6 @@ class ASH_EXPORT RootWindowController {
wm::RootWindowLayoutManager* root_window_layout_manager_ = nullptr;
std::unique_ptr<WallpaperWidgetController> wallpaper_widget_controller_;
std::unique_ptr<WorkspaceController> workspace_controller_;
std::unique_ptr<AlwaysOnTopController> always_on_top_controller_;
......
......@@ -226,6 +226,11 @@ void Shelf::UpdateVisibilityState() {
shelf_layout_manager_->UpdateVisibilityState();
}
void Shelf::SetSuspendVisibilityUpdate(bool value) {
if (shelf_layout_manager_)
shelf_layout_manager_->set_suspend_visibility_update(value);
}
void Shelf::MaybeUpdateShelfBackground() {
if (!shelf_layout_manager_)
return;
......
......@@ -113,6 +113,9 @@ class ASH_EXPORT Shelf : public ShelfLayoutManagerObserver {
void UpdateVisibilityState();
// Sets whether shelf's visibility state updates should be suspended.
void SetSuspendVisibilityUpdate(bool value);
void MaybeUpdateShelfBackground();
ShelfVisibilityState GetVisibilityState() const;
......
......@@ -39,6 +39,7 @@
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ash/wm/work_area_insets.h"
#include "ash/wm/workspace_controller.h"
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/i18n/rtl.h"
......@@ -115,6 +116,20 @@ bool IsHomeScreenAvailable() {
return Shell::Get()->home_screen_controller()->IsHomeScreenAvailable();
}
// Returns the |WorkspaceWindowState| of the currently active desk on the root
// window of |shelf_window|.
wm::WorkspaceWindowState GetShelfWorkspaceWindowState(
aura::Window* shelf_window) {
DCHECK(shelf_window);
// Shelf window does not belong to any desk, use the root to get the active
// desk's workspace state.
auto* controller =
GetActiveWorkspaceController(shelf_window->GetRootWindow());
DCHECK(controller);
return controller->GetWindowState();
}
} // namespace
// ShelfLayoutManager::UpdateShelfObserver -------------------------------------
......@@ -269,8 +284,8 @@ void ShelfLayoutManager::UpdateVisibilityState() {
if (in_shutdown_ || !shelf_window || suspend_visibility_update_)
return;
wm::WorkspaceWindowState window_state(
RootWindowController::ForWindow(shelf_window)->GetWorkspaceWindowState());
const wm::WorkspaceWindowState window_state =
GetShelfWorkspaceWindowState(shelf_window);
if (shelf_->ShouldHideOnSecondaryDisplay(state_.session_state)) {
// Needed to hide system tray on secondary display.
......@@ -718,11 +733,9 @@ void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) {
state.visibility_state = visibility_state;
state.auto_hide_state = CalculateAutoHideState(visibility_state);
state.is_status_area_visible = CalculateStatusAreaVisibility(state);
state.window_state =
GetShelfWorkspaceWindowState(shelf_widget_->GetNativeWindow());
RootWindowController* controller =
RootWindowController::ForWindow(shelf_widget_->GetNativeWindow());
state.window_state = controller ? controller->GetWorkspaceWindowState()
: wm::WORKSPACE_WINDOW_STATE_DEFAULT;
// Preserve the log in screen states.
state.session_state = state_.session_state;
state.pre_lock_screen_animation_active =
......
......@@ -196,6 +196,10 @@ class ASH_EXPORT ShelfLayoutManager
bool updating_bounds() const { return updating_bounds_; }
ShelfAutoHideState auto_hide_state() const { return state_.auto_hide_state; }
void set_suspend_visibility_update(bool value) {
suspend_visibility_update_ = value;
}
// TODO(harrym|oshima): These templates will be moved to a new Shelf class.
// A helper function for choosing values specific to a shelf alignment.
template <typename T>
......
......@@ -43,6 +43,7 @@
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h"
#include "ash/wm/workspace_controller.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/optional.h"
......@@ -446,9 +447,14 @@ class ShelfLayoutManagerTest : public AshTestBase {
}
wm::WorkspaceWindowState GetWorkspaceWindowState() const {
const auto* shelf_window = GetShelfWidget()->GetNativeWindow();
return RootWindowController::ForWindow(shelf_window)
->GetWorkspaceWindowState();
// Shelf window does not belong to any desk, use the root to get the active
// desk's workspace state.
auto* shelf_window = GetShelfWidget()->GetNativeWindow();
auto* controller =
GetActiveWorkspaceController(shelf_window->GetRootWindow());
DCHECK(controller);
return controller->GetWindowState();
}
const ui::Layer* GetNonLockScreenContainersContainerLayer() const {
......
......@@ -542,9 +542,10 @@ void Shell::SetCursorCompositingEnabled(bool enabled) {
}
void Shell::DoInitialWorkspaceAnimation() {
return GetPrimaryRootWindowController()
->workspace_controller()
->DoInitialAnimation();
// Uses the active desk's workspace.
auto* workspace = GetActiveWorkspaceController(GetPrimaryRootWindow());
DCHECK(workspace);
workspace->DoInitialAnimation();
}
bool Shell::IsSplitViewModeActive() const {
......
......@@ -16,6 +16,7 @@
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/workspace_controller.h"
#include "ash/ws/window_service_owner.h"
#include "base/run_loop.h"
#include "components/prefs/testing_pref_service.h"
......@@ -86,7 +87,8 @@ SystemGestureEventFilter* ShellTestApi::system_gesture_event_filter() {
}
WorkspaceController* ShellTestApi::workspace_controller() {
return shell_->GetPrimaryRootWindowController()->workspace_controller();
// TODO(afakhry): Split this into two, one for root, and one for context.
return GetActiveWorkspaceController(shell_->GetPrimaryRootWindow());
}
ScreenPositionController* ShellTestApi::screen_position_controller() {
......
......@@ -17,6 +17,7 @@
#include "ash/wm/window_state_delegate.h"
#include "ash/wm/window_state_util.h"
#include "ash/wm/wm_event.h"
#include "ash/wm/workspace_controller.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/aura/window_delegate.h"
......@@ -191,9 +192,14 @@ void DefaultState::HandleWorkspaceEvents(WindowState* window_state,
case WM_EVENT_WORKAREA_BOUNDS_CHANGED: {
// Don't resize the maximized window when the desktop is covered
// by fullscreen window. crbug.com/504299.
bool in_fullscreen =
RootWindowController::ForWindow(window_state->window())
->GetWorkspaceWindowState() == WORKSPACE_WINDOW_STATE_FULL_SCREEN;
// TODO(afakhry): Decide whether we want the active desk's workspace, or
// the workspace of the desk of `window_state->window()`.
// For now use the active desk's.
auto* workspace_controller =
GetActiveWorkspaceController(window_state->window()->GetRootWindow());
DCHECK(workspace_controller);
bool in_fullscreen = workspace_controller->GetWindowState() ==
WORKSPACE_WINDOW_STATE_FULL_SCREEN;
if (in_fullscreen && window_state->IsMaximized())
return;
......
......@@ -11,9 +11,50 @@ namespace ash {
namespace desks_util {
bool IsDeskContainerId(int id) {
namespace {
constexpr std::array<int, kMaxNumberOfDesks> kDesksContainersIds = {
// TODO(afakhry): Fill this.
kShellWindowId_DefaultContainer,
};
} // namespace
const std::array<int, kMaxNumberOfDesks>& GetDesksContainersIds() {
return kDesksContainersIds;
}
const char* GetDeskContainerName(int container_id) {
switch (container_id) {
case kShellWindowId_DefaultContainer:
return "Desk_Container_A";
// TODO(afakhry): Fill this.
default:
NOTREACHED();
return "";
}
}
std::vector<aura::Window*> GetDesksContainers(aura::Window* root) {
DCHECK(root);
DCHECK(root->IsRootWindow());
std::vector<aura::Window*> containers;
for (const auto& id : kDesksContainersIds) {
auto* container = root->GetChildById(id);
DCHECK(container);
containers.emplace_back(container);
}
return containers;
}
bool IsDeskContainer(aura::Window* container) {
DCHECK(container);
// TODO(afakhry): Add the rest of the desks containers.
return id == kShellWindowId_DefaultContainer;
return container->id() == kShellWindowId_DefaultContainer;
}
int GetActiveDeskContainerId() {
......
......@@ -5,6 +5,9 @@
#ifndef ASH_WM_DESKS_DESKS_UTIL_H_
#define ASH_WM_DESKS_DESKS_UTIL_H_
#include <array>
#include <vector>
#include "ash/ash_export.h"
namespace aura {
......@@ -15,7 +18,17 @@ namespace ash {
namespace desks_util {
ASH_EXPORT bool IsDeskContainerId(int id);
// TODO(afakhry): Fix the size of the array when you add the rest of the desks'
// containters.
constexpr size_t kMaxNumberOfDesks = 1;
ASH_EXPORT const std::array<int, kMaxNumberOfDesks>& GetDesksContainersIds();
ASH_EXPORT std::vector<aura::Window*> GetDesksContainers(aura::Window* root);
ASH_EXPORT const char* GetDeskContainerName(int container_id);
ASH_EXPORT bool IsDeskContainer(aura::Window* container);
ASH_EXPORT int GetActiveDeskContainerId();
......
......@@ -13,6 +13,7 @@
#include "ash/scoped_animation_disabler.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_session.h"
......@@ -496,11 +497,11 @@ void TabletModeWindowManager::AddWindowCreationObservers() {
// Observe window activations/creations in the default containers on all root
// windows.
for (aura::Window* root : Shell::GetAllRootWindows()) {
aura::Window* default_container =
root->GetChildById(kShellWindowId_DefaultContainer);
DCHECK(!base::ContainsKey(observed_container_windows_, default_container));
default_container->AddObserver(this);
observed_container_windows_.insert(default_container);
for (auto* desk_container : desks_util::GetDesksContainers(root)) {
DCHECK(!base::ContainsKey(observed_container_windows_, desk_container));
desk_container->AddObserver(this);
observed_container_windows_.insert(desk_container);
}
}
}
......@@ -525,9 +526,15 @@ void TabletModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay(
bool enable) {
// Inform the WorkspaceLayoutManager that we want to show a backdrop behind
// the topmost window of its container.
for (auto* controller : Shell::GetAllRootWindowControllers()) {
controller->workspace_controller()->SetBackdropDelegate(
enable ? std::make_unique<TabletModeBackdropDelegateImpl>() : nullptr);
for (auto* root : Shell::GetAllRootWindows()) {
for (auto* desk_container : desks_util::GetDesksContainers(root)) {
WorkspaceController* controller = GetWorkspaceController(desk_container);
DCHECK(controller);
controller->SetBackdropDelegate(
enable ? std::make_unique<TabletModeBackdropDelegateImpl>()
: nullptr);
}
}
}
......
......@@ -10,6 +10,7 @@
#include "ash/root_window_controller.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/fullscreen_window_finder.h"
#include "ash/wm/mru_window_tracker.h"
#include "ash/wm/overview/overview_controller.h"
......@@ -24,6 +25,17 @@
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/wm/core/window_animations.h"
// Defines a window property to store a WorkspaceController in the properties of
// virtual desks container windows.
ASH_EXPORT extern const aura::WindowProperty<ash::WorkspaceController*>* const
kWorkspaceController;
DEFINE_UI_CLASS_PROPERTY_TYPE(ash::WorkspaceController*)
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ash::WorkspaceController,
kWorkspaceController,
nullptr)
namespace ash {
namespace {
......@@ -127,4 +139,42 @@ void WorkspaceController::OnWindowDestroying(aura::Window* window) {
layout_manager_ = nullptr;
}
void SetWorkspaceController(aura::Window* desk_container,
WorkspaceController* workspace_controller) {
DCHECK(desk_container);
DCHECK(desks_util::IsDeskContainer(desk_container));
if (workspace_controller)
desk_container->SetProperty(kWorkspaceController, workspace_controller);
else
desk_container->ClearProperty(kWorkspaceController);
}
WorkspaceController* GetWorkspaceController(aura::Window* desk_container) {
DCHECK(desk_container);
DCHECK(desks_util::IsDeskContainer(desk_container));
return desk_container->GetProperty(kWorkspaceController);
}
WorkspaceController* GetWorkspaceControllerForContext(aura::Window* context) {
DCHECK(!context->IsRootWindow());
// Find the desk container to which |context| belongs.
while (context && !desks_util::IsDeskContainer(context))
context = context->parent();
if (!context)
return nullptr;
return GetWorkspaceController(context);
}
WorkspaceController* GetActiveWorkspaceController(aura::Window* root) {
DCHECK(root->IsRootWindow());
return GetWorkspaceController(
desks_util::GetActiveDeskContainerForRoot(root));
}
} // namespace ash
......@@ -10,6 +10,7 @@
#include "ash/ash_export.h"
#include "ash/wm/workspace/workspace_types.h"
#include "base/macros.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
namespace ash {
......@@ -53,6 +54,29 @@ class ASH_EXPORT WorkspaceController : public aura::WindowObserver {
DISALLOW_COPY_AND_ASSIGN(WorkspaceController);
};
// Sets the given |workspace_controller| as a property of |desk_container|. Only
// virtual desks containers are accepted. If |workspace_controller| is nullptr,
// the property will be cleared from |desk_container|.
ASH_EXPORT void SetWorkspaceController(
aura::Window* desk_container,
WorkspaceController* workspace_controller);
// Gets the worspace controller from the properties of the specific given
// |desk_container|. Only virtual desks containers are accepted.
ASH_EXPORT WorkspaceController* GetWorkspaceController(
aura::Window* desk_container);
// Gets the workspace controller from the properties of the virtual desk
// container anscestor of |context|. Returns nullptr if |context| doesn't belong
// to any virtual desk.
ASH_EXPORT WorkspaceController* GetWorkspaceControllerForContext(
aura::Window* context);
// Gets the workspace controller from the properties of the currently active
// virtual desk container on the given |root|.
ASH_EXPORT WorkspaceController* GetActiveWorkspaceController(
aura::Window* root);
} // namespace ash
#endif // ASH_WM_WORKSPACE_CONTROLLER_H_
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