athena: Fix switching windows with title-drag in split-view.
[chromium-blink-merge.git] / athena / wm / window_manager_impl.cc
blobe3bb2b281d521222e130fcd69acf6e53204607fa
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "athena/wm/public/window_manager.h"
7 #include <algorithm>
9 #include "athena/common/container_priorities.h"
10 #include "athena/input/public/accelerator_manager.h"
11 #include "athena/screen/public/screen_manager.h"
12 #include "athena/wm/bezel_controller.h"
13 #include "athena/wm/public/window_manager_observer.h"
14 #include "athena/wm/split_view_controller.h"
15 #include "athena/wm/title_drag_controller.h"
16 #include "athena/wm/window_list_provider_impl.h"
17 #include "athena/wm/window_overview_mode.h"
18 #include "base/logging.h"
19 #include "base/observer_list.h"
20 #include "ui/aura/layout_manager.h"
21 #include "ui/aura/window.h"
22 #include "ui/wm/core/shadow_controller.h"
23 #include "ui/wm/core/window_util.h"
24 #include "ui/wm/core/wm_state.h"
25 #include "ui/wm/public/activation_client.h"
26 #include "ui/wm/public/window_types.h"
28 namespace athena {
29 namespace {
31 class WindowManagerImpl : public WindowManager,
32 public WindowOverviewModeDelegate,
33 public aura::WindowObserver,
34 public AcceleratorHandler,
35 public TitleDragControllerDelegate {
36 public:
37 WindowManagerImpl();
38 virtual ~WindowManagerImpl();
40 void Layout();
42 // WindowManager:
43 virtual void ToggleOverview() OVERRIDE;
45 virtual bool IsOverviewModeActive() OVERRIDE;
47 private:
48 enum Command {
49 CMD_TOGGLE_OVERVIEW,
52 // Sets whether overview mode is active.
53 void SetInOverview(bool active);
55 void InstallAccelerators();
57 // WindowManager:
58 virtual void AddObserver(WindowManagerObserver* observer) OVERRIDE;
59 virtual void RemoveObserver(WindowManagerObserver* observer) OVERRIDE;
61 // WindowOverviewModeDelegate:
62 virtual void OnSelectWindow(aura::Window* window) OVERRIDE;
63 virtual void OnSplitViewMode(aura::Window* left,
64 aura::Window* right) OVERRIDE;
66 // aura::WindowObserver
67 virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE;
68 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
70 // AcceleratorHandler:
71 virtual bool IsCommandEnabled(int command_id) const OVERRIDE;
72 virtual bool OnAcceleratorFired(int command_id,
73 const ui::Accelerator& accelerator) OVERRIDE;
75 // TitleDragControllerDelegate:
76 virtual aura::Window* GetWindowBehind(aura::Window* window) OVERRIDE;
77 virtual void OnTitleDragStarted(aura::Window* window) OVERRIDE;
78 virtual void OnTitleDragCompleted(aura::Window* window) OVERRIDE;
79 virtual void OnTitleDragCanceled(aura::Window* window) OVERRIDE;
81 scoped_ptr<aura::Window> container_;
82 scoped_ptr<WindowListProvider> window_list_provider_;
83 scoped_ptr<WindowOverviewMode> overview_;
84 scoped_ptr<BezelController> bezel_controller_;
85 scoped_ptr<SplitViewController> split_view_controller_;
86 scoped_ptr<wm::WMState> wm_state_;
87 scoped_ptr<TitleDragController> title_drag_controller_;
88 scoped_ptr<wm::ShadowController> shadow_controller_;
89 ObserverList<WindowManagerObserver> observers_;
91 DISALLOW_COPY_AND_ASSIGN(WindowManagerImpl);
94 class AthenaContainerLayoutManager : public aura::LayoutManager {
95 public:
96 AthenaContainerLayoutManager();
97 virtual ~AthenaContainerLayoutManager();
99 private:
100 // aura::LayoutManager:
101 virtual void OnWindowResized() OVERRIDE;
102 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
103 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE;
104 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE;
105 virtual void OnChildWindowVisibilityChanged(aura::Window* child,
106 bool visible) OVERRIDE;
107 virtual void SetChildBounds(aura::Window* child,
108 const gfx::Rect& requested_bounds) OVERRIDE;
110 DISALLOW_COPY_AND_ASSIGN(AthenaContainerLayoutManager);
113 class WindowManagerImpl* instance = NULL;
115 WindowManagerImpl::WindowManagerImpl() {
116 ScreenManager::ContainerParams params("DefaultContainer", CP_DEFAULT);
117 params.can_activate_children = true;
118 container_.reset(ScreenManager::Get()->CreateDefaultContainer(params));
119 container_->SetLayoutManager(new AthenaContainerLayoutManager);
120 container_->AddObserver(this);
121 window_list_provider_.reset(new WindowListProviderImpl(container_.get()));
122 bezel_controller_.reset(new BezelController(container_.get()));
123 split_view_controller_.reset(
124 new SplitViewController(container_.get(), window_list_provider_.get()));
125 bezel_controller_->set_left_right_delegate(split_view_controller_.get());
126 container_->AddPreTargetHandler(bezel_controller_.get());
127 title_drag_controller_.reset(new TitleDragController(container_.get(), this));
128 wm_state_.reset(new wm::WMState());
129 aura::client::ActivationClient* activation_client =
130 aura::client::GetActivationClient(container_->GetRootWindow());
131 shadow_controller_.reset(new wm::ShadowController(activation_client));
132 instance = this;
133 InstallAccelerators();
136 WindowManagerImpl::~WindowManagerImpl() {
137 overview_.reset();
138 split_view_controller_.reset();
139 window_list_provider_.reset();
140 if (container_) {
141 container_->RemoveObserver(this);
142 container_->RemovePreTargetHandler(bezel_controller_.get());
144 // |title_drag_controller_| needs to be reset before |container_|.
145 title_drag_controller_.reset();
146 container_.reset();
147 instance = NULL;
150 void WindowManagerImpl::Layout() {
151 if (!container_)
152 return;
153 gfx::Rect bounds = gfx::Rect(container_->bounds().size());
154 const aura::Window::Windows& children = container_->children();
155 for (aura::Window::Windows::const_iterator iter = children.begin();
156 iter != children.end();
157 ++iter) {
158 if ((*iter)->type() == ui::wm::WINDOW_TYPE_NORMAL)
159 (*iter)->SetBounds(bounds);
163 void WindowManagerImpl::ToggleOverview() {
164 SetInOverview(overview_.get() == NULL);
167 bool WindowManagerImpl::IsOverviewModeActive() {
168 return overview_;
171 void WindowManagerImpl::SetInOverview(bool active) {
172 bool in_overview = !!overview_;
173 if (active == in_overview)
174 return;
176 bezel_controller_->set_left_right_delegate(
177 active ? NULL : split_view_controller_.get());
178 if (active) {
179 split_view_controller_->DeactivateSplitMode();
180 FOR_EACH_OBSERVER(WindowManagerObserver, observers_,
181 OnOverviewModeEnter());
182 // Re-stack all windows in the order defined by window_list_provider_.
183 aura::Window::Windows window_list = window_list_provider_->GetWindowList();
184 aura::Window::Windows::iterator it;
185 for (it = window_list.begin(); it != window_list.end(); ++it)
186 container_->StackChildAtTop(*it);
187 overview_ = WindowOverviewMode::Create(
188 container_.get(), window_list_provider_.get(), this);
189 } else {
190 CHECK(!split_view_controller_->IsSplitViewModeActive());
191 overview_.reset();
192 FOR_EACH_OBSERVER(WindowManagerObserver, observers_,
193 OnOverviewModeExit());
197 void WindowManagerImpl::InstallAccelerators() {
198 const AcceleratorData accelerator_data[] = {
199 {TRIGGER_ON_PRESS, ui::VKEY_F6, ui::EF_NONE, CMD_TOGGLE_OVERVIEW,
200 AF_NONE},
202 AcceleratorManager::Get()->RegisterAccelerators(
203 accelerator_data, arraysize(accelerator_data), this);
206 void WindowManagerImpl::AddObserver(WindowManagerObserver* observer) {
207 observers_.AddObserver(observer);
210 void WindowManagerImpl::RemoveObserver(WindowManagerObserver* observer) {
211 observers_.RemoveObserver(observer);
214 void WindowManagerImpl::OnSelectWindow(aura::Window* window) {
215 wm::ActivateWindow(window);
216 SetInOverview(false);
219 void WindowManagerImpl::OnSplitViewMode(aura::Window* left,
220 aura::Window* right) {
221 SetInOverview(false);
222 split_view_controller_->ActivateSplitMode(left, right);
225 void WindowManagerImpl::OnWindowAdded(aura::Window* new_window) {
226 if (new_window->type() == ui::wm::WINDOW_TYPE_NORMAL)
227 SetInOverview(false);
230 void WindowManagerImpl::OnWindowDestroying(aura::Window* window) {
231 if (window == container_)
232 container_.reset();
235 bool WindowManagerImpl::IsCommandEnabled(int command_id) const {
236 return true;
239 bool WindowManagerImpl::OnAcceleratorFired(int command_id,
240 const ui::Accelerator& accelerator) {
241 switch (command_id) {
242 case CMD_TOGGLE_OVERVIEW:
243 ToggleOverview();
244 break;
246 return true;
249 aura::Window* WindowManagerImpl::GetWindowBehind(aura::Window* window) {
250 const aura::Window::Windows& windows = window_list_provider_->GetWindowList();
251 aura::Window::Windows::const_reverse_iterator iter =
252 std::find(windows.rbegin(), windows.rend(), window);
253 CHECK(iter != windows.rend());
254 ++iter;
255 aura::Window* behind = NULL;
256 if (iter != windows.rend())
257 behind = *iter++;
259 if (split_view_controller_->IsSplitViewModeActive()) {
260 aura::Window* left = split_view_controller_->left_window();
261 aura::Window* right = split_view_controller_->right_window();
262 CHECK(window == left || window == right);
263 if (behind == left || behind == right)
264 behind = (iter == windows.rend()) ? NULL : *iter;
267 return behind;
270 void WindowManagerImpl::OnTitleDragStarted(aura::Window* window) {
271 aura::Window* next_window = GetWindowBehind(window);
272 if (!next_window)
273 return;
274 // Make sure |window| is active. Also make sure that |next_window| is visible,
275 // and positioned to match the top-left edge of |window|.
276 wm::ActivateWindow(window);
277 next_window->Show();
278 int dx = window->bounds().x() - next_window->bounds().x();
279 if (dx) {
280 gfx::Transform transform;
281 transform.Translate(dx, 0);
282 next_window->SetTransform(transform);
286 void WindowManagerImpl::OnTitleDragCompleted(aura::Window* window) {
287 aura::Window* next_window = GetWindowBehind(window);
288 if (!next_window)
289 return;
290 if (split_view_controller_->IsSplitViewModeActive())
291 split_view_controller_->ReplaceWindow(window, next_window);
292 else
293 OnSelectWindow(next_window);
294 wm::ActivateWindow(next_window);
297 void WindowManagerImpl::OnTitleDragCanceled(aura::Window* window) {
298 aura::Window* next_window = GetWindowBehind(window);
299 if (!next_window)
300 return;
301 next_window->SetTransform(gfx::Transform());
304 AthenaContainerLayoutManager::AthenaContainerLayoutManager() {
307 AthenaContainerLayoutManager::~AthenaContainerLayoutManager() {
310 void AthenaContainerLayoutManager::OnWindowResized() {
311 instance->Layout();
314 void AthenaContainerLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
315 instance->Layout();
318 void AthenaContainerLayoutManager::OnWillRemoveWindowFromLayout(
319 aura::Window* child) {
322 void AthenaContainerLayoutManager::OnWindowRemovedFromLayout(
323 aura::Window* child) {
324 instance->Layout();
327 void AthenaContainerLayoutManager::OnChildWindowVisibilityChanged(
328 aura::Window* child,
329 bool visible) {
330 instance->Layout();
333 void AthenaContainerLayoutManager::SetChildBounds(
334 aura::Window* child,
335 const gfx::Rect& requested_bounds) {
336 if (!requested_bounds.IsEmpty())
337 SetChildBoundsDirect(child, requested_bounds);
340 } // namespace
342 // static
343 WindowManager* WindowManager::Create() {
344 DCHECK(!instance);
345 new WindowManagerImpl;
346 DCHECK(instance);
347 return instance;
350 // static
351 void WindowManager::Shutdown() {
352 DCHECK(instance);
353 delete instance;
354 DCHECK(!instance);
357 // static
358 WindowManager* WindowManager::GetInstance() {
359 DCHECK(instance);
360 return instance;
363 } // namespace athena