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"
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"
39 // Creates a new window for use as a container.
40 aura::Window
* CreateContainer(int window_id
,
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
)
53 // Returns all the children of the workspace windows, eg the standard top-level
55 std::vector
<aura::Window
*> GetWorkspaceWindows(aura::RootWindow
* root
) {
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());
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())
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
))
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",
150 SetChildWindowVisibilityChangesAnimated(desktop_background_containers
);
152 aura::Window
* non_lock_screen_containers
= CreateContainer(
153 internal::kShellWindowId_NonLockScreenContainersContainer
,
154 "NonLockScreenContainersContainer",
157 aura::Window
* lock_background_containers
= CreateContainer(
158 internal::kShellWindowId_LockScreenBackgroundContainer
,
159 "LockScreenBackgroundContainer",
161 SetChildWindowVisibilityChangesAnimated(lock_background_containers
);
163 aura::Window
* lock_screen_containers
= CreateContainer(
164 internal::kShellWindowId_LockScreenContainersContainer
,
165 "LockScreenContainersContainer",
167 aura::Window
* lock_screen_related_containers
= CreateContainer(
168 internal::kShellWindowId_LockScreenRelatedContainersContainer
,
169 "LockScreenRelatedContainersContainer",
172 CreateContainer(internal::kShellWindowId_UnparentedControlContainer
,
173 "UnparentedControlContainer",
174 non_lock_screen_containers
);
176 aura::Window
* default_container
= CreateContainer(
177 internal::kShellWindowId_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
,
197 non_lock_screen_containers
);
198 SetUsesScreenCoordinates(panel_container
);
200 aura::Window
* launcher_container
=
201 CreateContainer(internal::kShellWindowId_LauncherContainer
,
203 non_lock_screen_containers
);
204 SetUsesScreenCoordinates(launcher_container
);
206 CreateContainer(internal::kShellWindowId_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
,
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
,
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
,
279 lock_screen_related_containers
);
280 SetUsesScreenCoordinates(overlay_container
);
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];
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())->
364 aura::WindowTracker tracker
;
366 tracker
.Add(focused
);
367 if (active
&& focused
!= 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