harfbuzz-ng roll
[chromium-blink-merge.git] / ash / root_window_controller.cc
blob8155f35f7276e56ce4378185d49fdc8004948972
1 // 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.
5 #include "ash/root_window_controller.h"
7 #include <vector>
9 #include "ash/desktop_background/desktop_background_widget_controller.h"
10 #include "ash/display/display_controller.h"
11 #include "ash/shell.h"
12 #include "ash/shell_factory.h"
13 #include "ash/shell_window_ids.h"
14 #include "ash/wm/base_layout_manager.h"
15 #include "ash/wm/event_client_impl.h"
16 #include "ash/wm/property_util.h"
17 #include "ash/wm/root_window_layout_manager.h"
18 #include "ash/wm/screen_dimmer.h"
19 #include "ash/wm/system_modal_container_layout_manager.h"
20 #include "ash/wm/toplevel_window_event_filter.h"
21 #include "ash/wm/visibility_controller.h"
22 #include "ash/wm/window_properties.h"
23 #include "ash/wm/workspace_controller.h"
24 #include "ui/aura/client/activation_client.h"
25 #include "ui/aura/client/aura_constants.h"
26 #include "ui/aura/client/capture_client.h"
27 #include "ui/aura/client/tooltip_client.h"
28 #include "ui/aura/focus_manager.h"
29 #include "ui/aura/root_window.h"
30 #include "ui/aura/window.h"
31 #include "ui/aura/window_observer.h"
32 #include "ui/aura/window_tracker.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/screen.h"
36 namespace ash {
37 namespace {
39 // Creates a new window for use as a container.
40 aura::Window* CreateContainer(int window_id,
41 const char* name,
42 aura::Window* parent) {
43 aura::Window* container = new aura::Window(NULL);
44 container->set_id(window_id);
45 container->SetName(name);
46 container->Init(ui::LAYER_NOT_DRAWN);
47 parent->AddChild(container);
48 if (window_id != internal::kShellWindowId_UnparentedControlContainer)
49 container->Show();
50 return container;
53 // Returns all the children of the workspace windows, eg the standard top-level
54 // windows.
55 std::vector<aura::Window*> GetWorkspaceWindows(aura::RootWindow* root) {
56 using aura::Window;
58 std::vector<Window*> windows;
59 Window* container = Shell::GetContainer(
60 root, internal::kShellWindowId_DefaultContainer);
61 for (Window::Windows::const_reverse_iterator i =
62 container->children().rbegin();
63 i != container->children().rend(); ++i) {
64 Window* workspace_window = *i;
65 if (workspace_window->id() == internal::kShellWindowId_WorkspaceContainer) {
66 windows.insert(windows.end(), workspace_window->children().begin(),
67 workspace_window->children().end());
70 return windows;
73 // Reparents |window| to |new_parent|.
74 void ReparentWindow(aura::Window* window, aura::Window* new_parent) {
75 // Update the restore bounds to make it relative to the display.
76 gfx::Rect restore_bounds(GetRestoreBoundsInParent(window));
77 new_parent->AddChild(window);
78 if (!restore_bounds.IsEmpty())
79 SetRestoreBoundsInParent(window, restore_bounds);
82 // Reparents the appropriate set of windows from |src| to |dst|.
83 void ReparentAllWindows(aura::RootWindow* src, aura::RootWindow* dst) {
84 // Set of windows to move.
85 const int kContainerIdsToMove[] = {
86 internal::kShellWindowId_DefaultContainer,
87 internal::kShellWindowId_AlwaysOnTopContainer,
88 internal::kShellWindowId_SystemModalContainer,
89 internal::kShellWindowId_LockSystemModalContainer,
91 // For Workspace2 we need to manually reparent the windows. This way
92 // Workspace2 can move the windows to the appropriate workspace.
93 if (internal::WorkspaceController::IsWorkspace2Enabled()) {
94 std::vector<aura::Window*> windows(GetWorkspaceWindows(src));
95 internal::WorkspaceController* workspace_controller =
96 GetRootWindowController(dst)->workspace_controller();
97 for (size_t i = 0; i < windows.size(); ++i) {
98 aura::Window* new_parent =
99 workspace_controller->GetParentForNewWindow(windows[i]);
100 ReparentWindow(windows[i], new_parent);
103 for (size_t i = 0; i < arraysize(kContainerIdsToMove); i++) {
104 int id = kContainerIdsToMove[i];
105 if (id == internal::kShellWindowId_DefaultContainer &&
106 internal::WorkspaceController::IsWorkspace2Enabled())
107 continue;
109 aura::Window* src_container = Shell::GetContainer(src, id);
110 aura::Window* dst_container = Shell::GetContainer(dst, id);
111 aura::Window::Windows children = src_container->children();
112 for (aura::Window::Windows::iterator iter = children.begin();
113 iter != children.end(); ++iter) {
114 aura::Window* window = *iter;
115 // Don't move modal screen.
116 if (internal::SystemModalContainerLayoutManager::IsModalScreen(window))
117 continue;
119 ReparentWindow(window, dst_container);
124 // Mark the container window so that a widget added to this container will
125 // use the virtual screeen coordinates instead of parent.
126 void SetUsesScreenCoordinates(aura::Window* container) {
127 container->SetProperty(internal::kUsesScreenCoordinatesKey, true);
130 // Creates each of the special window containers that holds windows of various
131 // types in the shell UI.
132 void CreateContainersInRootWindow(aura::RootWindow* root_window) {
133 // These containers are just used by PowerButtonController to animate groups
134 // of containers simultaneously without messing up the current transformations
135 // on those containers. These are direct children of the root window; all of
136 // the other containers are their children.
137 // Desktop and lock screen background containers are not part of the
138 // lock animation so they are not included in those animate groups.
139 // When screen is locked desktop background is moved to lock screen background
140 // container (moved back on unlock). We want to make sure that there's an
141 // opaque layer occluding the non-lock-screen layers.
143 CreateContainer(internal::kShellWindowId_SystemBackgroundContainer,
144 "SystemBackgroundContainer", root_window);
146 aura::Window* desktop_background_containers = CreateContainer(
147 internal::kShellWindowId_DesktopBackgroundContainer,
148 "DesktopBackgroundContainer",
149 root_window);
150 SetChildWindowVisibilityChangesAnimated(desktop_background_containers);
152 aura::Window* non_lock_screen_containers = CreateContainer(
153 internal::kShellWindowId_NonLockScreenContainersContainer,
154 "NonLockScreenContainersContainer",
155 root_window);
157 aura::Window* lock_background_containers = CreateContainer(
158 internal::kShellWindowId_LockScreenBackgroundContainer,
159 "LockScreenBackgroundContainer",
160 root_window);
161 SetChildWindowVisibilityChangesAnimated(lock_background_containers);
163 aura::Window* lock_screen_containers = CreateContainer(
164 internal::kShellWindowId_LockScreenContainersContainer,
165 "LockScreenContainersContainer",
166 root_window);
167 aura::Window* lock_screen_related_containers = CreateContainer(
168 internal::kShellWindowId_LockScreenRelatedContainersContainer,
169 "LockScreenRelatedContainersContainer",
170 root_window);
172 CreateContainer(internal::kShellWindowId_UnparentedControlContainer,
173 "UnparentedControlContainer",
174 non_lock_screen_containers);
176 aura::Window* default_container = CreateContainer(
177 internal::kShellWindowId_DefaultContainer,
178 "DefaultContainer",
179 non_lock_screen_containers);
180 default_container->SetEventFilter(
181 new ToplevelWindowEventFilter(default_container));
182 SetChildWindowVisibilityChangesAnimated(default_container);
183 SetUsesScreenCoordinates(default_container);
185 aura::Window* always_on_top_container = CreateContainer(
186 internal::kShellWindowId_AlwaysOnTopContainer,
187 "AlwaysOnTopContainer",
188 non_lock_screen_containers);
189 always_on_top_container->SetEventFilter(
190 new ToplevelWindowEventFilter(always_on_top_container));
191 SetChildWindowVisibilityChangesAnimated(always_on_top_container);
192 SetUsesScreenCoordinates(always_on_top_container);
194 aura::Window* panel_container = CreateContainer(
195 internal::kShellWindowId_PanelContainer,
196 "PanelContainer",
197 non_lock_screen_containers);
198 SetUsesScreenCoordinates(panel_container);
200 aura::Window* launcher_container =
201 CreateContainer(internal::kShellWindowId_LauncherContainer,
202 "LauncherContainer",
203 non_lock_screen_containers);
204 SetUsesScreenCoordinates(launcher_container);
206 CreateContainer(internal::kShellWindowId_AppListContainer,
207 "AppListContainer",
208 non_lock_screen_containers);
210 aura::Window* modal_container = CreateContainer(
211 internal::kShellWindowId_SystemModalContainer,
212 "SystemModalContainer",
213 non_lock_screen_containers);
214 modal_container->SetEventFilter(
215 new ToplevelWindowEventFilter(modal_container));
216 modal_container->SetLayoutManager(
217 new internal::SystemModalContainerLayoutManager(modal_container));
218 SetChildWindowVisibilityChangesAnimated(modal_container);
219 SetUsesScreenCoordinates(modal_container);
221 aura::Window* input_method_container = CreateContainer(
222 internal::kShellWindowId_InputMethodContainer,
223 "InputMethodContainer",
224 non_lock_screen_containers);
225 SetUsesScreenCoordinates(input_method_container);
227 // TODO(beng): Figure out if we can make this use
228 // SystemModalContainerEventFilter instead of stops_event_propagation.
229 aura::Window* lock_container = CreateContainer(
230 internal::kShellWindowId_LockScreenContainer,
231 "LockScreenContainer",
232 lock_screen_containers);
233 lock_container->SetLayoutManager(
234 new internal::BaseLayoutManager(root_window));
235 SetUsesScreenCoordinates(lock_container);
236 // TODO(beng): stopsevents
238 aura::Window* lock_modal_container = CreateContainer(
239 internal::kShellWindowId_LockSystemModalContainer,
240 "LockSystemModalContainer",
241 lock_screen_containers);
242 lock_modal_container->SetEventFilter(
243 new ToplevelWindowEventFilter(lock_modal_container));
244 lock_modal_container->SetLayoutManager(
245 new internal::SystemModalContainerLayoutManager(lock_modal_container));
246 SetChildWindowVisibilityChangesAnimated(lock_modal_container);
247 SetUsesScreenCoordinates(lock_modal_container);
249 aura::Window* status_container =
250 CreateContainer(internal::kShellWindowId_StatusContainer,
251 "StatusContainer",
252 lock_screen_related_containers);
253 SetUsesScreenCoordinates(status_container);
255 aura::Window* settings_bubble_container = CreateContainer(
256 internal::kShellWindowId_SettingBubbleContainer,
257 "SettingBubbleContainer",
258 lock_screen_related_containers);
259 SetChildWindowVisibilityChangesAnimated(settings_bubble_container);
260 SetUsesScreenCoordinates(settings_bubble_container);
262 aura::Window* menu_container = CreateContainer(
263 internal::kShellWindowId_MenuContainer,
264 "MenuContainer",
265 lock_screen_related_containers);
266 SetChildWindowVisibilityChangesAnimated(menu_container);
267 SetUsesScreenCoordinates(menu_container);
269 aura::Window* drag_drop_container = CreateContainer(
270 internal::kShellWindowId_DragImageAndTooltipContainer,
271 "DragImageAndTooltipContainer",
272 lock_screen_related_containers);
273 SetChildWindowVisibilityChangesAnimated(drag_drop_container);
274 SetUsesScreenCoordinates(drag_drop_container);
276 aura::Window* overlay_container = CreateContainer(
277 internal::kShellWindowId_OverlayContainer,
278 "OverlayContainer",
279 lock_screen_related_containers);
280 SetUsesScreenCoordinates(overlay_container);
283 } // namespace
285 namespace internal {
287 RootWindowController::RootWindowController(aura::RootWindow* root_window)
288 : root_window_(root_window) {
289 SetRootWindowController(root_window, this);
291 event_client_.reset(new internal::EventClientImpl(root_window));
292 screen_dimmer_.reset(new internal::ScreenDimmer(root_window));
295 RootWindowController::~RootWindowController() {
296 if (Shell::GetActiveRootWindow() == root_window_.get()) {
297 Shell::GetInstance()->set_active_root_window(
298 Shell::GetPrimaryRootWindow() == root_window_.get() ?
299 NULL : Shell::GetPrimaryRootWindow());
301 SetRootWindowController(root_window_.get(), NULL);
302 event_client_.reset();
303 screen_dimmer_.reset();
304 workspace_controller_.reset();
305 root_window_.reset();
308 aura::Window* RootWindowController::GetContainer(int container_id) {
309 return root_window_->GetChildById(container_id);
312 void RootWindowController::InitLayoutManagers() {
313 root_window_layout_ =
314 new internal::RootWindowLayoutManager(root_window_.get());
315 root_window_->SetLayoutManager(root_window_layout_);
317 aura::Window* default_container =
318 GetContainer(internal::kShellWindowId_DefaultContainer);
319 // Workspace manager has its own layout managers.
320 workspace_controller_.reset(
321 new internal::WorkspaceController(default_container));
323 aura::Window* always_on_top_container =
324 GetContainer(internal::kShellWindowId_AlwaysOnTopContainer);
325 always_on_top_container->SetLayoutManager(
326 new internal::BaseLayoutManager(
327 always_on_top_container->GetRootWindow()));
330 void RootWindowController::CreateContainers() {
331 CreateContainersInRootWindow(root_window_.get());
334 void RootWindowController::CloseChildWindows() {
335 // Close background widget first as it depends on tooltip.
336 root_window_->SetProperty(kWindowDesktopComponent,
337 static_cast<DesktopBackgroundWidgetController*>(NULL));
338 root_window_->SetProperty(kComponentWrapper,
339 static_cast<ComponentWrapper*>(NULL));
341 workspace_controller_.reset();
342 aura::client::SetTooltipClient(root_window_.get(), NULL);
344 while (!root_window_->children().empty()) {
345 aura::Window* child = root_window_->children()[0];
346 delete child;
350 bool RootWindowController::IsInMaximizedMode() const {
351 return workspace_controller_->IsInMaximizedMode();
354 void RootWindowController::MoveWindowsTo(aura::RootWindow* dst) {
355 aura::Window* focused = dst->GetFocusManager()->GetFocusedWindow();
356 aura::client::ActivationClient* activation_client =
357 aura::client::GetActivationClient(dst);
358 aura::Window* active = activation_client->GetActiveWindow();
359 // Deactivate the window to close menu / bubble windows.
360 activation_client->DeactivateWindow(active);
361 // Release capture if any.
362 aura::client::GetCaptureClient(root_window_.get())->
363 SetCapture(NULL);
364 aura::WindowTracker tracker;
365 if (focused)
366 tracker.Add(focused);
367 if (active && focused != active)
368 tracker.Add(active);
370 ReparentAllWindows(root_window_.get(), dst);
372 // Restore focused or active window if it's still alive.
373 if (focused && tracker.Contains(focused) && dst->Contains(focused)) {
374 dst->GetFocusManager()->SetFocusedWindow(focused, NULL);
375 } else if (active && tracker.Contains(active) && dst->Contains(active)) {
376 activation_client->ActivateWindow(active);
380 } // namespace internal
381 } // namespace ash