blob: 1e380593d29eb9054d96e2d625223d3bc78099e3 [file] [log] [blame]
[email protected]d90b8392012-06-13 09:34:561// Copyright (c) 2012 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.
4
5#include "ash/root_window_controller.h"
6
[email protected]8d625fb2012-07-18 16:40:067#include <vector>
8
[email protected]b4ddc7a2012-08-07 04:17:329#include "ash/desktop_background/desktop_background_widget_controller.h"
[email protected]8d625fb2012-07-18 16:40:0610#include "ash/display/display_controller.h"
[email protected]6675e1c2012-09-11 09:15:4511#include "ash/display/multi_display_manager.h"
[email protected]d90b8392012-06-13 09:34:5612#include "ash/shell.h"
13#include "ash/shell_factory.h"
14#include "ash/shell_window_ids.h"
15#include "ash/wm/base_layout_manager.h"
16#include "ash/wm/event_client_impl.h"
17#include "ash/wm/property_util.h"
18#include "ash/wm/root_window_layout_manager.h"
19#include "ash/wm/screen_dimmer.h"
20#include "ash/wm/system_modal_container_layout_manager.h"
[email protected]5dc51db82012-09-11 03:39:0121#include "ash/wm/toplevel_window_event_handler.h"
[email protected]d90b8392012-06-13 09:34:5622#include "ash/wm/visibility_controller.h"
[email protected]8d625fb2012-07-18 16:40:0623#include "ash/wm/window_properties.h"
[email protected]d90b8392012-06-13 09:34:5624#include "ash/wm/workspace_controller.h"
[email protected]f1853122012-06-27 16:21:2625#include "ui/aura/client/activation_client.h"
26#include "ui/aura/client/aura_constants.h"
27#include "ui/aura/client/capture_client.h"
[email protected]d90b8392012-06-13 09:34:5628#include "ui/aura/client/tooltip_client.h"
[email protected]f1853122012-06-27 16:21:2629#include "ui/aura/focus_manager.h"
[email protected]d90b8392012-06-13 09:34:5630#include "ui/aura/root_window.h"
[email protected]f1853122012-06-27 16:21:2631#include "ui/aura/window.h"
32#include "ui/aura/window_observer.h"
[email protected]1d030242012-06-28 18:34:0833#include "ui/aura/window_tracker.h"
[email protected]8d625fb2012-07-18 16:40:0634#include "ui/gfx/display.h"
35#include "ui/gfx/screen.h"
[email protected]d90b8392012-06-13 09:34:5636
37namespace ash {
38namespace {
39
40// Creates a new window for use as a container.
41aura::Window* CreateContainer(int window_id,
42 const char* name,
43 aura::Window* parent) {
44 aura::Window* container = new aura::Window(NULL);
45 container->set_id(window_id);
46 container->SetName(name);
47 container->Init(ui::LAYER_NOT_DRAWN);
48 parent->AddChild(container);
49 if (window_id != internal::kShellWindowId_UnparentedControlContainer)
50 container->Show();
51 return container;
52}
53
[email protected]95058572012-08-20 14:57:2954// Returns all the children of the workspace windows, eg the standard top-level
55// windows.
56std::vector<aura::Window*> GetWorkspaceWindows(aura::RootWindow* root) {
57 using aura::Window;
58
59 std::vector<Window*> windows;
60 Window* container = Shell::GetContainer(
61 root, internal::kShellWindowId_DefaultContainer);
62 for (Window::Windows::const_reverse_iterator i =
63 container->children().rbegin();
64 i != container->children().rend(); ++i) {
65 Window* workspace_window = *i;
66 if (workspace_window->id() == internal::kShellWindowId_WorkspaceContainer) {
67 windows.insert(windows.end(), workspace_window->children().begin(),
68 workspace_window->children().end());
69 }
70 }
71 return windows;
72}
73
74// Reparents |window| to |new_parent|.
75void ReparentWindow(aura::Window* window, aura::Window* new_parent) {
76 // Update the restore bounds to make it relative to the display.
77 gfx::Rect restore_bounds(GetRestoreBoundsInParent(window));
78 new_parent->AddChild(window);
79 if (!restore_bounds.IsEmpty())
80 SetRestoreBoundsInParent(window, restore_bounds);
81}
82
83// Reparents the appropriate set of windows from |src| to |dst|.
84void ReparentAllWindows(aura::RootWindow* src, aura::RootWindow* dst) {
85 // Set of windows to move.
[email protected]f1853122012-06-27 16:21:2686 const int kContainerIdsToMove[] = {
87 internal::kShellWindowId_DefaultContainer,
88 internal::kShellWindowId_AlwaysOnTopContainer,
89 internal::kShellWindowId_SystemModalContainer,
90 internal::kShellWindowId_LockSystemModalContainer,
91 };
[email protected]95058572012-08-20 14:57:2992 // For Workspace2 we need to manually reparent the windows. This way
93 // Workspace2 can move the windows to the appropriate workspace.
94 if (internal::WorkspaceController::IsWorkspace2Enabled()) {
95 std::vector<aura::Window*> windows(GetWorkspaceWindows(src));
96 internal::WorkspaceController* workspace_controller =
97 GetRootWindowController(dst)->workspace_controller();
98 for (size_t i = 0; i < windows.size(); ++i) {
99 aura::Window* new_parent =
100 workspace_controller->GetParentForNewWindow(windows[i]);
101 ReparentWindow(windows[i], new_parent);
102 }
103 }
[email protected]f1853122012-06-27 16:21:26104 for (size_t i = 0; i < arraysize(kContainerIdsToMove); i++) {
105 int id = kContainerIdsToMove[i];
[email protected]95058572012-08-20 14:57:29106 if (id == internal::kShellWindowId_DefaultContainer &&
107 internal::WorkspaceController::IsWorkspace2Enabled())
108 continue;
109
[email protected]f1853122012-06-27 16:21:26110 aura::Window* src_container = Shell::GetContainer(src, id);
111 aura::Window* dst_container = Shell::GetContainer(dst, id);
112 aura::Window::Windows children = src_container->children();
113 for (aura::Window::Windows::iterator iter = children.begin();
114 iter != children.end(); ++iter) {
115 aura::Window* window = *iter;
116 // Don't move modal screen.
[email protected]f059c6942012-07-21 14:27:57117 if (internal::SystemModalContainerLayoutManager::IsModalScreen(window))
[email protected]f1853122012-06-27 16:21:26118 continue;
[email protected]f059c6942012-07-21 14:27:57119
[email protected]95058572012-08-20 14:57:29120 ReparentWindow(window, dst_container);
[email protected]f1853122012-06-27 16:21:26121 }
122 }
123}
124
[email protected]8d625fb2012-07-18 16:40:06125// Mark the container window so that a widget added to this container will
126// use the virtual screeen coordinates instead of parent.
127void SetUsesScreenCoordinates(aura::Window* container) {
128 container->SetProperty(internal::kUsesScreenCoordinatesKey, true);
129}
130
[email protected]d90b8392012-06-13 09:34:56131// Creates each of the special window containers that holds windows of various
132// types in the shell UI.
133void CreateContainersInRootWindow(aura::RootWindow* root_window) {
134 // These containers are just used by PowerButtonController to animate groups
135 // of containers simultaneously without messing up the current transformations
[email protected]4e5653042012-09-05 10:21:07136 // on those containers. These are direct children of the root window; all of
[email protected]d90b8392012-06-13 09:34:56137 // the other containers are their children.
[email protected]4e5653042012-09-05 10:21:07138 // Desktop and lock screen background containers are not part of the
139 // lock animation so they are not included in those animate groups.
140 // When screen is locked desktop background is moved to lock screen background
141 // container (moved back on unlock). We want to make sure that there's an
142 // opaque layer occluding the non-lock-screen layers.
143
[email protected]55de57d2012-09-06 04:29:02144 CreateContainer(internal::kShellWindowId_SystemBackgroundContainer,
145 "SystemBackgroundContainer", root_window);
146
[email protected]4e5653042012-09-05 10:21:07147 aura::Window* desktop_background_containers = CreateContainer(
148 internal::kShellWindowId_DesktopBackgroundContainer,
149 "DesktopBackgroundContainer",
150 root_window);
151 SetChildWindowVisibilityChangesAnimated(desktop_background_containers);
152
[email protected]d90b8392012-06-13 09:34:56153 aura::Window* non_lock_screen_containers = CreateContainer(
154 internal::kShellWindowId_NonLockScreenContainersContainer,
155 "NonLockScreenContainersContainer",
156 root_window);
[email protected]4e5653042012-09-05 10:21:07157
158 aura::Window* lock_background_containers = CreateContainer(
159 internal::kShellWindowId_LockScreenBackgroundContainer,
160 "LockScreenBackgroundContainer",
161 root_window);
162 SetChildWindowVisibilityChangesAnimated(lock_background_containers);
163
[email protected]d90b8392012-06-13 09:34:56164 aura::Window* lock_screen_containers = CreateContainer(
165 internal::kShellWindowId_LockScreenContainersContainer,
166 "LockScreenContainersContainer",
167 root_window);
168 aura::Window* lock_screen_related_containers = CreateContainer(
169 internal::kShellWindowId_LockScreenRelatedContainersContainer,
170 "LockScreenRelatedContainersContainer",
171 root_window);
172
173 CreateContainer(internal::kShellWindowId_UnparentedControlContainer,
174 "UnparentedControlContainer",
175 non_lock_screen_containers);
176
[email protected]d90b8392012-06-13 09:34:56177 aura::Window* default_container = CreateContainer(
178 internal::kShellWindowId_DefaultContainer,
179 "DefaultContainer",
180 non_lock_screen_containers);
[email protected]5dc51db82012-09-11 03:39:01181 if (!internal::WorkspaceController::IsWorkspace2Enabled()) {
182 default_container->AddPreTargetHandler(
183 new ToplevelWindowEventHandler(default_container));
184 }
[email protected]d90b8392012-06-13 09:34:56185 SetChildWindowVisibilityChangesAnimated(default_container);
[email protected]8d625fb2012-07-18 16:40:06186 SetUsesScreenCoordinates(default_container);
[email protected]d90b8392012-06-13 09:34:56187
188 aura::Window* always_on_top_container = CreateContainer(
189 internal::kShellWindowId_AlwaysOnTopContainer,
190 "AlwaysOnTopContainer",
191 non_lock_screen_containers);
[email protected]5dc51db82012-09-11 03:39:01192 always_on_top_container->AddPreTargetHandler(
193 new ToplevelWindowEventHandler(always_on_top_container));
[email protected]d90b8392012-06-13 09:34:56194 SetChildWindowVisibilityChangesAnimated(always_on_top_container);
[email protected]8d625fb2012-07-18 16:40:06195 SetUsesScreenCoordinates(always_on_top_container);
[email protected]d90b8392012-06-13 09:34:56196
[email protected]8d625fb2012-07-18 16:40:06197 aura::Window* panel_container = CreateContainer(
198 internal::kShellWindowId_PanelContainer,
199 "PanelContainer",
200 non_lock_screen_containers);
201 SetUsesScreenCoordinates(panel_container);
[email protected]d90b8392012-06-13 09:34:56202
[email protected]8d625fb2012-07-18 16:40:06203 aura::Window* launcher_container =
204 CreateContainer(internal::kShellWindowId_LauncherContainer,
205 "LauncherContainer",
206 non_lock_screen_containers);
207 SetUsesScreenCoordinates(launcher_container);
[email protected]d90b8392012-06-13 09:34:56208
209 CreateContainer(internal::kShellWindowId_AppListContainer,
210 "AppListContainer",
211 non_lock_screen_containers);
212
213 aura::Window* modal_container = CreateContainer(
214 internal::kShellWindowId_SystemModalContainer,
215 "SystemModalContainer",
216 non_lock_screen_containers);
[email protected]5dc51db82012-09-11 03:39:01217 modal_container->AddPreTargetHandler(
218 new ToplevelWindowEventHandler(modal_container));
[email protected]d90b8392012-06-13 09:34:56219 modal_container->SetLayoutManager(
220 new internal::SystemModalContainerLayoutManager(modal_container));
221 SetChildWindowVisibilityChangesAnimated(modal_container);
[email protected]8d625fb2012-07-18 16:40:06222 SetUsesScreenCoordinates(modal_container);
[email protected]d90b8392012-06-13 09:34:56223
[email protected]8d625fb2012-07-18 16:40:06224 aura::Window* input_method_container = CreateContainer(
225 internal::kShellWindowId_InputMethodContainer,
226 "InputMethodContainer",
227 non_lock_screen_containers);
228 SetUsesScreenCoordinates(input_method_container);
[email protected]f471accc2012-06-26 16:04:40229
[email protected]d90b8392012-06-13 09:34:56230 // TODO(beng): Figure out if we can make this use
231 // SystemModalContainerEventFilter instead of stops_event_propagation.
232 aura::Window* lock_container = CreateContainer(
233 internal::kShellWindowId_LockScreenContainer,
234 "LockScreenContainer",
235 lock_screen_containers);
236 lock_container->SetLayoutManager(
237 new internal::BaseLayoutManager(root_window));
[email protected]8d625fb2012-07-18 16:40:06238 SetUsesScreenCoordinates(lock_container);
[email protected]d90b8392012-06-13 09:34:56239 // TODO(beng): stopsevents
240
241 aura::Window* lock_modal_container = CreateContainer(
242 internal::kShellWindowId_LockSystemModalContainer,
243 "LockSystemModalContainer",
244 lock_screen_containers);
[email protected]5dc51db82012-09-11 03:39:01245 lock_modal_container->AddPreTargetHandler(
246 new ToplevelWindowEventHandler(lock_modal_container));
[email protected]d90b8392012-06-13 09:34:56247 lock_modal_container->SetLayoutManager(
248 new internal::SystemModalContainerLayoutManager(lock_modal_container));
249 SetChildWindowVisibilityChangesAnimated(lock_modal_container);
[email protected]8d625fb2012-07-18 16:40:06250 SetUsesScreenCoordinates(lock_modal_container);
[email protected]d90b8392012-06-13 09:34:56251
[email protected]ec1930c32012-07-19 23:57:42252 aura::Window* status_container =
253 CreateContainer(internal::kShellWindowId_StatusContainer,
254 "StatusContainer",
255 lock_screen_related_containers);
256 SetUsesScreenCoordinates(status_container);
[email protected]d90b8392012-06-13 09:34:56257
258 aura::Window* settings_bubble_container = CreateContainer(
259 internal::kShellWindowId_SettingBubbleContainer,
260 "SettingBubbleContainer",
261 lock_screen_related_containers);
262 SetChildWindowVisibilityChangesAnimated(settings_bubble_container);
[email protected]8d625fb2012-07-18 16:40:06263 SetUsesScreenCoordinates(settings_bubble_container);
[email protected]d90b8392012-06-13 09:34:56264
265 aura::Window* menu_container = CreateContainer(
266 internal::kShellWindowId_MenuContainer,
267 "MenuContainer",
268 lock_screen_related_containers);
269 SetChildWindowVisibilityChangesAnimated(menu_container);
[email protected]8d625fb2012-07-18 16:40:06270 SetUsesScreenCoordinates(menu_container);
[email protected]d90b8392012-06-13 09:34:56271
272 aura::Window* drag_drop_container = CreateContainer(
273 internal::kShellWindowId_DragImageAndTooltipContainer,
274 "DragImageAndTooltipContainer",
275 lock_screen_related_containers);
276 SetChildWindowVisibilityChangesAnimated(drag_drop_container);
[email protected]8d625fb2012-07-18 16:40:06277 SetUsesScreenCoordinates(drag_drop_container);
[email protected]d90b8392012-06-13 09:34:56278
[email protected]8d625fb2012-07-18 16:40:06279 aura::Window* overlay_container = CreateContainer(
280 internal::kShellWindowId_OverlayContainer,
281 "OverlayContainer",
282 lock_screen_related_containers);
283 SetUsesScreenCoordinates(overlay_container);
[email protected]d90b8392012-06-13 09:34:56284}
285
286} // namespace
287
288namespace internal {
289
290RootWindowController::RootWindowController(aura::RootWindow* root_window)
291 : root_window_(root_window) {
292 SetRootWindowController(root_window, this);
293
294 event_client_.reset(new internal::EventClientImpl(root_window));
295 screen_dimmer_.reset(new internal::ScreenDimmer(root_window));
296}
297
298RootWindowController::~RootWindowController() {
[email protected]6675e1c2012-09-11 09:15:45299 Shutdown();
300 root_window_.reset();
301}
302
303void RootWindowController::Shutdown() {
304 CloseChildWindows();
[email protected]f634dd32012-07-23 22:49:07305 if (Shell::GetActiveRootWindow() == root_window_.get()) {
306 Shell::GetInstance()->set_active_root_window(
307 Shell::GetPrimaryRootWindow() == root_window_.get() ?
308 NULL : Shell::GetPrimaryRootWindow());
309 }
[email protected]d90b8392012-06-13 09:34:56310 SetRootWindowController(root_window_.get(), NULL);
311 event_client_.reset();
312 screen_dimmer_.reset();
313 workspace_controller_.reset();
[email protected]6675e1c2012-09-11 09:15:45314 // Forget with the display ID so that display lookup
315 // ends up with invalid display.
316 root_window_->ClearProperty(kDisplayIdKey);
317 // And this root window should no longer process events.
318 root_window_->PrepareForShutdown();
[email protected]d90b8392012-06-13 09:34:56319}
320
321aura::Window* RootWindowController::GetContainer(int container_id) {
322 return root_window_->GetChildById(container_id);
323}
324
325void RootWindowController::InitLayoutManagers() {
326 root_window_layout_ =
327 new internal::RootWindowLayoutManager(root_window_.get());
328 root_window_->SetLayoutManager(root_window_layout_);
329
330 aura::Window* default_container =
331 GetContainer(internal::kShellWindowId_DefaultContainer);
332 // Workspace manager has its own layout managers.
333 workspace_controller_.reset(
334 new internal::WorkspaceController(default_container));
335
336 aura::Window* always_on_top_container =
337 GetContainer(internal::kShellWindowId_AlwaysOnTopContainer);
338 always_on_top_container->SetLayoutManager(
339 new internal::BaseLayoutManager(
340 always_on_top_container->GetRootWindow()));
341}
342
343void RootWindowController::CreateContainers() {
344 CreateContainersInRootWindow(root_window_.get());
345}
346
347void RootWindowController::CloseChildWindows() {
348 // Close background widget first as it depends on tooltip.
[email protected]b4ddc7a2012-08-07 04:17:32349 root_window_->SetProperty(kWindowDesktopComponent,
350 static_cast<DesktopBackgroundWidgetController*>(NULL));
[email protected]f262a9e2012-08-14 20:05:56351 root_window_->SetProperty(kComponentWrapper,
352 static_cast<ComponentWrapper*>(NULL));
[email protected]b4ddc7a2012-08-07 04:17:32353
[email protected]d90b8392012-06-13 09:34:56354 workspace_controller_.reset();
355 aura::client::SetTooltipClient(root_window_.get(), NULL);
356
357 while (!root_window_->children().empty()) {
358 aura::Window* child = root_window_->children()[0];
359 delete child;
360 }
361}
362
363bool RootWindowController::IsInMaximizedMode() const {
[email protected]f4bb9fde2012-08-03 19:33:50364 return workspace_controller_->IsInMaximizedMode();
[email protected]d90b8392012-06-13 09:34:56365}
366
[email protected]f1853122012-06-27 16:21:26367void RootWindowController::MoveWindowsTo(aura::RootWindow* dst) {
368 aura::Window* focused = dst->GetFocusManager()->GetFocusedWindow();
369 aura::client::ActivationClient* activation_client =
370 aura::client::GetActivationClient(dst);
371 aura::Window* active = activation_client->GetActiveWindow();
372 // Deactivate the window to close menu / bubble windows.
373 activation_client->DeactivateWindow(active);
374 // Release capture if any.
375 aura::client::GetCaptureClient(root_window_.get())->
376 SetCapture(NULL);
[email protected]1d030242012-06-28 18:34:08377 aura::WindowTracker tracker;
[email protected]f1853122012-06-27 16:21:26378 if (focused)
[email protected]1d030242012-06-28 18:34:08379 tracker.Add(focused);
[email protected]f1853122012-06-27 16:21:26380 if (active && focused != active)
[email protected]1d030242012-06-28 18:34:08381 tracker.Add(active);
[email protected]f1853122012-06-27 16:21:26382
[email protected]95058572012-08-20 14:57:29383 ReparentAllWindows(root_window_.get(), dst);
[email protected]f1853122012-06-27 16:21:26384
385 // Restore focused or active window if it's still alive.
[email protected]1d030242012-06-28 18:34:08386 if (focused && tracker.Contains(focused) && dst->Contains(focused)) {
[email protected]f1853122012-06-27 16:21:26387 dst->GetFocusManager()->SetFocusedWindow(focused, NULL);
[email protected]1d030242012-06-28 18:34:08388 } else if (active && tracker.Contains(active) && dst->Contains(active)) {
[email protected]f1853122012-06-27 16:21:26389 activation_client->ActivateWindow(active);
390 }
391}
392
[email protected]d90b8392012-06-13 09:34:56393} // namespace internal
394} // namespace ash