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. 4 5 #include "ash/root_window_controller.h" 6 7 #include <queue> 8 #include <vector> 9 10 #include "ash/ash_constants.h" 11 #include "ash/ash_switches.h" 12 #include "ash/desktop_background/desktop_background_controller.h" 13 #include "ash/desktop_background/desktop_background_widget_controller.h" 14 #include "ash/desktop_background/user_wallpaper_delegate.h" 15 #include "ash/display/display_manager.h" 16 #include "ash/focus_cycler.h" 17 #include "ash/high_contrast/high_contrast_controller.h" 18 #include "ash/host/ash_window_tree_host.h" 19 #include "ash/root_window_settings.h" 20 #include "ash/session/session_state_delegate.h" 21 #include "ash/shelf/shelf_layout_manager.h" 22 #include "ash/shelf/shelf_types.h" 23 #include "ash/shelf/shelf_widget.h" 24 #include "ash/shell.h" 25 #include "ash/shell_delegate.h" 26 #include "ash/shell_factory.h" 27 #include "ash/shell_window_ids.h" 28 #include "ash/switchable_windows.h" 29 #include "ash/system/status_area_widget.h" 30 #include "ash/system/tray/system_tray_delegate.h" 31 #include "ash/system/tray/system_tray_notifier.h" 32 #include "ash/touch/touch_hud_debug.h" 33 #include "ash/touch/touch_hud_projection.h" 34 #include "ash/touch/touch_observer_hud.h" 35 #include "ash/wm/always_on_top_controller.h" 36 #include "ash/wm/dock/docked_window_layout_manager.h" 37 #include "ash/wm/lock_layout_manager.h" 38 #include "ash/wm/panels/attached_panel_window_targeter.h" 39 #include "ash/wm/panels/panel_layout_manager.h" 40 #include "ash/wm/panels/panel_window_event_handler.h" 41 #include "ash/wm/root_window_layout_manager.h" 42 #include "ash/wm/screen_dimmer.h" 43 #include "ash/wm/stacking_controller.h" 44 #include "ash/wm/status_area_layout_manager.h" 45 #include "ash/wm/system_background_controller.h" 46 #include "ash/wm/system_modal_container_layout_manager.h" 47 #include "ash/wm/virtual_keyboard_container_layout_manager.h" 48 #include "ash/wm/window_properties.h" 49 #include "ash/wm/window_state.h" 50 #include "ash/wm/window_util.h" 51 #include "ash/wm/workspace/workspace_layout_manager.h" 52 #include "ash/wm/workspace_controller.h" 53 #include "base/command_line.h" 54 #include "base/time/time.h" 55 #include "ui/aura/client/aura_constants.h" 56 #include "ui/aura/client/screen_position_client.h" 57 #include "ui/aura/window.h" 58 #include "ui/aura/window_delegate.h" 59 #include "ui/aura/window_event_dispatcher.h" 60 #include "ui/aura/window_observer.h" 61 #include "ui/aura/window_tracker.h" 62 #include "ui/base/hit_test.h" 63 #include "ui/base/models/menu_model.h" 64 #include "ui/gfx/display.h" 65 #include "ui/gfx/screen.h" 66 #include "ui/keyboard/keyboard_controller.h" 67 #include "ui/keyboard/keyboard_util.h" 68 #include "ui/views/controls/menu/menu_runner.h" 69 #include "ui/views/view_model.h" 70 #include "ui/views/view_model_utils.h" 71 #include "ui/wm/core/capture_controller.h" 72 #include "ui/wm/core/easy_resize_window_targeter.h" 73 #include "ui/wm/core/visibility_controller.h" 74 #include "ui/wm/core/window_util.h" 75 #include "ui/wm/public/drag_drop_client.h" 76 #include "ui/wm/public/tooltip_client.h" 77 #include "ui/wm/public/window_types.h" 78 79 #if defined(OS_CHROMEOS) 80 #include "ash/ash_touch_exploration_manager_chromeos.h" 81 #include "ash/wm/boot_splash_screen_chromeos.h" 82 #include "ui/chromeos/touch_exploration_controller.h" 83 #endif 84 85 namespace ash { 86 namespace { 87 88 #if defined(OS_CHROMEOS) 89 // Duration for the animation that hides the boot splash screen, in 90 // milliseconds. This should be short enough in relation to 91 // wm/window_animation.cc's brightness/grayscale fade animation that the login 92 // background image animation isn't hidden by the splash screen animation. 93 const int kBootSplashScreenHideDurationMs = 500; 94 #endif 95 96 // Creates a new window for use as a container. 97 aura::Window* CreateContainer(int window_id, 98 const char* name, 99 aura::Window* parent) { 100 aura::Window* container = new aura::Window(NULL); 101 container->set_id(window_id); 102 container->SetName(name); 103 container->Init(aura::WINDOW_LAYER_NOT_DRAWN); 104 parent->AddChild(container); 105 if (window_id != kShellWindowId_UnparentedControlContainer) 106 container->Show(); 107 return container; 108 } 109 110 float ToRelativeValue(int value, int src, int dst) { 111 return static_cast<float>(value) / static_cast<float>(src) * dst; 112 } 113 114 void MoveOriginRelativeToSize(const gfx::Size& src_size, 115 const gfx::Size& dst_size, 116 gfx::Rect* bounds_in_out) { 117 gfx::Point origin = bounds_in_out->origin(); 118 bounds_in_out->set_origin(gfx::Point( 119 ToRelativeValue(origin.x(), src_size.width(), dst_size.width()), 120 ToRelativeValue(origin.y(), src_size.height(), dst_size.height()))); 121 } 122 123 // Reparents |window| to |new_parent|. 124 void ReparentWindow(aura::Window* window, aura::Window* new_parent) { 125 const gfx::Size src_size = window->parent()->bounds().size(); 126 const gfx::Size dst_size = new_parent->bounds().size(); 127 // Update the restore bounds to make it relative to the display. 128 wm::WindowState* state = wm::GetWindowState(window); 129 gfx::Rect restore_bounds; 130 bool has_restore_bounds = state->HasRestoreBounds(); 131 132 bool update_bounds = (state->IsNormalOrSnapped() || state->IsMinimized()) && 133 new_parent->id() != kShellWindowId_DockedContainer; 134 gfx::Rect local_bounds; 135 if (update_bounds) { 136 local_bounds = state->window()->bounds(); 137 MoveOriginRelativeToSize(src_size, dst_size, &local_bounds); 138 } 139 140 if (has_restore_bounds) { 141 restore_bounds = state->GetRestoreBoundsInParent(); 142 MoveOriginRelativeToSize(src_size, dst_size, &restore_bounds); 143 } 144 145 new_parent->AddChild(window); 146 147 // Docked windows have bounds handled by the layout manager in AddChild(). 148 if (update_bounds) 149 window->SetBounds(local_bounds); 150 151 if (has_restore_bounds) 152 state->SetRestoreBoundsInParent(restore_bounds); 153 } 154 155 // Reparents the appropriate set of windows from |src| to |dst|. 156 void ReparentAllWindows(aura::Window* src, aura::Window* dst) { 157 // Set of windows to move. 158 const int kContainerIdsToMove[] = { 159 kShellWindowId_DefaultContainer, 160 kShellWindowId_DockedContainer, 161 kShellWindowId_PanelContainer, 162 kShellWindowId_AlwaysOnTopContainer, 163 kShellWindowId_SystemModalContainer, 164 kShellWindowId_LockSystemModalContainer, 165 kShellWindowId_UnparentedControlContainer, }; 166 for (size_t i = 0; i < arraysize(kContainerIdsToMove); i++) { 167 int id = kContainerIdsToMove[i]; 168 aura::Window* src_container = Shell::GetContainer(src, id); 169 aura::Window* dst_container = Shell::GetContainer(dst, id); 170 while (!src_container->children().empty()) { 171 // Restart iteration from the source container windows each time as they 172 // may change as a result of moving other windows. 173 aura::Window::Windows::const_iterator iter = 174 src_container->children().begin(); 175 while (iter != src_container->children().end() && 176 SystemModalContainerLayoutManager::IsModalBackground(*iter)) { 177 ++iter; 178 } 179 // If the entire window list is modal background windows then stop. 180 if (iter == src_container->children().end()) 181 break; 182 ReparentWindow(*iter, dst_container); 183 } 184 } 185 } 186 187 // Mark the container window so that a widget added to this container will 188 // use the virtual screeen coordinates instead of parent. 189 void SetUsesScreenCoordinates(aura::Window* container) { 190 container->SetProperty(kUsesScreenCoordinatesKey, true); 191 } 192 193 // Mark the container window so that a widget added to this container will 194 // say in the same root window regardless of the bounds specified. 195 void DescendantShouldStayInSameRootWindow(aura::Window* container) { 196 container->SetProperty(kStayInSameRootWindowKey, true); 197 } 198 199 void SetUsesEasyResizeTargeter(aura::Window* container) { 200 gfx::Insets mouse_extend(-kResizeOutsideBoundsSize, 201 -kResizeOutsideBoundsSize, 202 -kResizeOutsideBoundsSize, 203 -kResizeOutsideBoundsSize); 204 gfx::Insets touch_extend = mouse_extend.Scale( 205 kResizeOutsideBoundsScaleForTouch); 206 container->SetEventTargeter(scoped_ptr<ui::EventTargeter>( 207 new ::wm::EasyResizeWindowTargeter(container, mouse_extend, 208 touch_extend))); 209 } 210 211 // A window delegate which does nothing. Used to create a window that 212 // is a event target, but do nothing. 213 class EmptyWindowDelegate : public aura::WindowDelegate { 214 public: 215 EmptyWindowDelegate() {} 216 virtual ~EmptyWindowDelegate() {} 217 218 // aura::WindowDelegate overrides: 219 virtual gfx::Size GetMinimumSize() const OVERRIDE { 220 return gfx::Size(); 221 } 222 virtual gfx::Size GetMaximumSize() const OVERRIDE { 223 return gfx::Size(); 224 } 225 virtual void OnBoundsChanged(const gfx::Rect& old_bounds, 226 const gfx::Rect& new_bounds) OVERRIDE { 227 } 228 virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { 229 return gfx::kNullCursor; 230 } 231 virtual int GetNonClientComponent( 232 const gfx::Point& point) const OVERRIDE { 233 return HTNOWHERE; 234 } 235 virtual bool ShouldDescendIntoChildForEventHandling( 236 aura::Window* child, 237 const gfx::Point& location) OVERRIDE { 238 return false; 239 } 240 virtual bool CanFocus() OVERRIDE { 241 return false; 242 } 243 virtual void OnCaptureLost() OVERRIDE { 244 } 245 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 246 } 247 virtual void OnDeviceScaleFactorChanged( 248 float device_scale_factor) OVERRIDE { 249 } 250 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {} 251 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 252 delete this; 253 } 254 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE { 255 } 256 virtual bool HasHitTestMask() const OVERRIDE { 257 return false; 258 } 259 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} 260 261 private: 262 DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate); 263 }; 264 265 } // namespace 266 267 void RootWindowController::CreateForPrimaryDisplay(AshWindowTreeHost* host) { 268 RootWindowController* controller = new RootWindowController(host); 269 controller->Init(RootWindowController::PRIMARY, 270 Shell::GetInstance()->delegate()->IsFirstRunAfterBoot()); 271 } 272 273 void RootWindowController::CreateForSecondaryDisplay(AshWindowTreeHost* host) { 274 RootWindowController* controller = new RootWindowController(host); 275 controller->Init(RootWindowController::SECONDARY, false /* first run */); 276 } 277 278 // static 279 RootWindowController* RootWindowController::ForShelf( 280 const aura::Window* window) { 281 CHECK(Shell::HasInstance()); 282 return GetRootWindowController(window->GetRootWindow()); 283 } 284 285 // static 286 RootWindowController* RootWindowController::ForWindow( 287 const aura::Window* window) { 288 CHECK(Shell::HasInstance()); 289 return GetRootWindowController(window->GetRootWindow()); 290 } 291 292 // static 293 RootWindowController* RootWindowController::ForTargetRootWindow() { 294 CHECK(Shell::HasInstance()); 295 return GetRootWindowController(Shell::GetTargetRootWindow()); 296 } 297 298 // static 299 aura::Window* RootWindowController::GetContainerForWindow( 300 aura::Window* window) { 301 aura::Window* container = window->parent(); 302 while (container && container->type() != ui::wm::WINDOW_TYPE_UNKNOWN) 303 container = container->parent(); 304 return container; 305 } 306 307 RootWindowController::~RootWindowController() { 308 Shutdown(); 309 ash_host_.reset(); 310 // The CaptureClient needs to be around for as long as the RootWindow is 311 // valid. 312 capture_client_.reset(); 313 } 314 315 aura::WindowTreeHost* RootWindowController::GetHost() { 316 return ash_host_->AsWindowTreeHost(); 317 } 318 319 const aura::WindowTreeHost* RootWindowController::GetHost() const { 320 return ash_host_->AsWindowTreeHost(); 321 } 322 323 aura::Window* RootWindowController::GetRootWindow() { 324 return GetHost()->window(); 325 } 326 327 const aura::Window* RootWindowController::GetRootWindow() const { 328 return GetHost()->window(); 329 } 330 331 void RootWindowController::SetWallpaperController( 332 DesktopBackgroundWidgetController* controller) { 333 wallpaper_controller_.reset(controller); 334 } 335 336 void RootWindowController::SetAnimatingWallpaperController( 337 AnimatingDesktopController* controller) { 338 if (animating_wallpaper_controller_.get()) 339 animating_wallpaper_controller_->StopAnimating(); 340 animating_wallpaper_controller_.reset(controller); 341 } 342 343 void RootWindowController::Shutdown() { 344 Shell* shell = Shell::GetInstance(); 345 shell->RemoveShellObserver(this); 346 347 #if defined(OS_CHROMEOS) 348 if (touch_exploration_manager_) { 349 touch_exploration_manager_.reset(); 350 } 351 #endif 352 353 if (animating_wallpaper_controller_.get()) 354 animating_wallpaper_controller_->StopAnimating(); 355 wallpaper_controller_.reset(); 356 animating_wallpaper_controller_.reset(); 357 aura::Window* root_window = GetRootWindow(); 358 // Change the target root window before closing child windows. If any child 359 // being removed triggers a relayout of the shelf it will try to build a 360 // window list adding windows from the target root window's containers which 361 // may have already gone away. 362 if (Shell::GetTargetRootWindow() == root_window) { 363 shell->set_target_root_window( 364 Shell::GetPrimaryRootWindow() == root_window 365 ? NULL 366 : Shell::GetPrimaryRootWindow()); 367 } 368 369 CloseChildWindows(); 370 GetRootWindowSettings(root_window)->controller = NULL; 371 screen_dimmer_.reset(); 372 workspace_controller_.reset(); 373 // Forget with the display ID so that display lookup 374 // ends up with invalid display. 375 GetRootWindowSettings(root_window)->display_id = 376 gfx::Display::kInvalidDisplayID; 377 ash_host_->PrepareForShutdown(); 378 379 system_background_.reset(); 380 aura::client::SetScreenPositionClient(root_window, NULL); 381 } 382 383 SystemModalContainerLayoutManager* 384 RootWindowController::GetSystemModalLayoutManager(aura::Window* window) { 385 aura::Window* modal_container = NULL; 386 if (window) { 387 aura::Window* window_container = GetContainerForWindow(window); 388 if (window_container && 389 window_container->id() >= kShellWindowId_LockScreenContainer) { 390 modal_container = GetContainer(kShellWindowId_LockSystemModalContainer); 391 } else { 392 modal_container = GetContainer(kShellWindowId_SystemModalContainer); 393 } 394 } else { 395 int modal_window_id = Shell::GetInstance()->session_state_delegate() 396 ->IsUserSessionBlocked() ? kShellWindowId_LockSystemModalContainer : 397 kShellWindowId_SystemModalContainer; 398 modal_container = GetContainer(modal_window_id); 399 } 400 return modal_container ? static_cast<SystemModalContainerLayoutManager*>( 401 modal_container->layout_manager()) : NULL; 402 } 403 404 aura::Window* RootWindowController::GetContainer(int container_id) { 405 return GetRootWindow()->GetChildById(container_id); 406 } 407 408 const aura::Window* RootWindowController::GetContainer(int container_id) const { 409 return ash_host_->AsWindowTreeHost()->window()->GetChildById(container_id); 410 } 411 412 void RootWindowController::ShowShelf() { 413 if (!shelf_->shelf()) 414 return; 415 shelf_->shelf()->SetVisible(true); 416 shelf_->status_area_widget()->Show(); 417 } 418 419 void RootWindowController::OnShelfCreated() { 420 if (panel_layout_manager_) 421 panel_layout_manager_->SetShelf(shelf_->shelf()); 422 if (docked_layout_manager_) { 423 docked_layout_manager_->SetShelf(shelf_->shelf()); 424 if (shelf_->shelf_layout_manager()) 425 docked_layout_manager_->AddObserver(shelf_->shelf_layout_manager()); 426 } 427 428 // Notify shell observers that the shelf has been created. 429 Shell::GetInstance()->OnShelfCreatedForRootWindow(GetRootWindow()); 430 } 431 432 void RootWindowController::UpdateAfterLoginStatusChange( 433 user::LoginStatus status) { 434 if (status != user::LOGGED_IN_NONE) 435 mouse_event_target_.reset(); 436 if (shelf_->status_area_widget()) 437 shelf_->status_area_widget()->UpdateAfterLoginStatusChange(status); 438 } 439 440 void RootWindowController::HandleInitialDesktopBackgroundAnimationStarted() { 441 #if defined(OS_CHROMEOS) 442 if (CommandLine::ForCurrentProcess()->HasSwitch( 443 switches::kAshAnimateFromBootSplashScreen) && 444 boot_splash_screen_.get()) { 445 // Make the splash screen fade out so it doesn't obscure the desktop 446 // wallpaper's brightness/grayscale animation. 447 boot_splash_screen_->StartHideAnimation( 448 base::TimeDelta::FromMilliseconds(kBootSplashScreenHideDurationMs)); 449 } 450 #endif 451 } 452 453 void RootWindowController::OnWallpaperAnimationFinished(views::Widget* widget) { 454 // Make sure the wallpaper is visible. 455 system_background_->SetColor(SK_ColorBLACK); 456 #if defined(OS_CHROMEOS) 457 boot_splash_screen_.reset(); 458 #endif 459 460 Shell::GetInstance()->user_wallpaper_delegate()-> 461 OnWallpaperAnimationFinished(); 462 // Only removes old component when wallpaper animation finished. If we 463 // remove the old one before the new wallpaper is done fading in there will 464 // be a white flash during the animation. 465 if (animating_wallpaper_controller()) { 466 DesktopBackgroundWidgetController* controller = 467 animating_wallpaper_controller()->GetController(true); 468 // |desktop_widget_| should be the same animating widget we try to move 469 // to |kDesktopController|. Otherwise, we may close |desktop_widget_| 470 // before move it to |kDesktopController|. 471 DCHECK_EQ(controller->widget(), widget); 472 // Release the old controller and close its background widget. 473 SetWallpaperController(controller); 474 } 475 } 476 477 void RootWindowController::CloseChildWindows() { 478 mouse_event_target_.reset(); 479 480 // Remove observer as deactivating keyboard causes |docked_layout_manager_| 481 // to fire notifications. 482 if (docked_layout_manager_ && shelf_ && shelf_->shelf_layout_manager()) 483 docked_layout_manager_->RemoveObserver(shelf_->shelf_layout_manager()); 484 485 // Deactivate keyboard container before closing child windows and shutting 486 // down associated layout managers. 487 DeactivateKeyboard(keyboard::KeyboardController::GetInstance()); 488 489 // panel_layout_manager_ needs to be shut down before windows are destroyed. 490 if (panel_layout_manager_) { 491 panel_layout_manager_->Shutdown(); 492 panel_layout_manager_ = NULL; 493 } 494 // docked_layout_manager_ needs to be shut down before windows are destroyed. 495 if (docked_layout_manager_) { 496 docked_layout_manager_->Shutdown(); 497 docked_layout_manager_ = NULL; 498 } 499 aura::Window* root_window = GetRootWindow(); 500 aura::client::SetDragDropClient(root_window, NULL); 501 502 // TODO(harrym): Remove when Status Area Widget is a child view. 503 if (shelf_) { 504 shelf_->ShutdownStatusAreaWidget(); 505 506 if (shelf_->shelf_layout_manager()) 507 shelf_->shelf_layout_manager()->PrepareForShutdown(); 508 } 509 510 // Close background widget first as it depends on tooltip. 511 wallpaper_controller_.reset(); 512 animating_wallpaper_controller_.reset(); 513 514 workspace_controller_.reset(); 515 aura::client::SetTooltipClient(root_window, NULL); 516 517 // Explicitly destroy top level windows. We do this as during part of 518 // destruction such windows may query the RootWindow for state. 519 std::queue<aura::Window*> non_toplevel_windows; 520 non_toplevel_windows.push(root_window); 521 while (!non_toplevel_windows.empty()) { 522 aura::Window* non_toplevel_window = non_toplevel_windows.front(); 523 non_toplevel_windows.pop(); 524 aura::WindowTracker toplevel_windows; 525 for (size_t i = 0; i < non_toplevel_window->children().size(); ++i) { 526 aura::Window* child = non_toplevel_window->children()[i]; 527 if (!child->owned_by_parent()) 528 continue; 529 if (child->delegate()) 530 toplevel_windows.Add(child); 531 else 532 non_toplevel_windows.push(child); 533 } 534 while (!toplevel_windows.windows().empty()) 535 delete *toplevel_windows.windows().begin(); 536 } 537 // And then remove the containers. 538 while (!root_window->children().empty()) { 539 aura::Window* window = root_window->children()[0]; 540 if (window->owned_by_parent()) { 541 delete window; 542 } else { 543 root_window->RemoveChild(window); 544 } 545 } 546 547 shelf_.reset(); 548 } 549 550 void RootWindowController::MoveWindowsTo(aura::Window* dst) { 551 // Forget the shelf early so that shelf don't update itself using wrong 552 // display info. 553 workspace_controller_->SetShelf(NULL); 554 ReparentAllWindows(GetRootWindow(), dst); 555 } 556 557 ShelfLayoutManager* RootWindowController::GetShelfLayoutManager() { 558 return shelf_->shelf_layout_manager(); 559 } 560 561 SystemTray* RootWindowController::GetSystemTray() { 562 // We assume in throughout the code that this will not return NULL. If code 563 // triggers this for valid reasons, it should test status_area_widget first. 564 CHECK(shelf_->status_area_widget()); 565 return shelf_->status_area_widget()->system_tray(); 566 } 567 568 void RootWindowController::ShowContextMenu(const gfx::Point& location_in_screen, 569 ui::MenuSourceType source_type) { 570 DCHECK(Shell::GetInstance()->delegate()); 571 scoped_ptr<ui::MenuModel> menu_model( 572 Shell::GetInstance()->delegate()->CreateContextMenu( 573 GetRootWindow(), NULL, NULL)); 574 if (!menu_model) 575 return; 576 577 // Background controller may not be set yet if user clicked on status are 578 // before initial animation completion. See crbug.com/222218 579 if (!wallpaper_controller_.get()) 580 return; 581 582 views::MenuRunner menu_runner(menu_model.get(), 583 views::MenuRunner::CONTEXT_MENU); 584 if (menu_runner.RunMenuAt(wallpaper_controller_->widget(), 585 NULL, 586 gfx::Rect(location_in_screen, gfx::Size()), 587 views::MENU_ANCHOR_TOPLEFT, 588 source_type) == views::MenuRunner::MENU_DELETED) { 589 return; 590 } 591 592 Shell::GetInstance()->UpdateShelfVisibility(); 593 } 594 595 void RootWindowController::UpdateShelfVisibility() { 596 shelf_->shelf_layout_manager()->UpdateVisibilityState(); 597 } 598 599 const aura::Window* RootWindowController::GetWindowForFullscreenMode() const { 600 const aura::Window* topmost_window = NULL; 601 const aura::Window* active_window = wm::GetActiveWindow(); 602 if (active_window && active_window->GetRootWindow() == GetRootWindow() && 603 IsSwitchableContainer(active_window->parent())) { 604 // Use the active window when it is on the current root window to determine 605 // the fullscreen state to allow temporarily using a panel or docked window 606 // (which are always above the default container) while a fullscreen 607 // window is open. We only use the active window when in a switchable 608 // container as the launcher should not exit fullscreen mode. 609 topmost_window = active_window; 610 } else { 611 // Otherwise, use the topmost window on the root window's default container 612 // when there is no active window on this root window. 613 const aura::Window::Windows& windows = 614 GetContainer(kShellWindowId_DefaultContainer)->children(); 615 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin(); 616 iter != windows.rend(); ++iter) { 617 if (((*iter)->type() == ui::wm::WINDOW_TYPE_NORMAL || 618 (*iter)->type() == ui::wm::WINDOW_TYPE_PANEL) && 619 (*iter)->layer()->GetTargetVisibility()) { 620 topmost_window = *iter; 621 break; 622 } 623 } 624 } 625 while (topmost_window) { 626 if (wm::GetWindowState(topmost_window)->IsFullscreen()) 627 return topmost_window; 628 topmost_window = ::wm::GetTransientParent(topmost_window); 629 } 630 return NULL; 631 } 632 633 void RootWindowController::ActivateKeyboard( 634 keyboard::KeyboardController* keyboard_controller) { 635 if (!keyboard::IsKeyboardEnabled() || 636 GetContainer(kShellWindowId_VirtualKeyboardContainer)) { 637 return; 638 } 639 DCHECK(keyboard_controller); 640 keyboard_controller->AddObserver(shelf()->shelf_layout_manager()); 641 keyboard_controller->AddObserver(panel_layout_manager_); 642 keyboard_controller->AddObserver(docked_layout_manager_); 643 keyboard_controller->AddObserver(workspace_controller_->layout_manager()); 644 Shell::GetInstance()->delegate()->VirtualKeyboardActivated(true); 645 aura::Window* parent = GetContainer( 646 kShellWindowId_VirtualKeyboardParentContainer); 647 DCHECK(parent); 648 aura::Window* keyboard_container = 649 keyboard_controller->GetContainerWindow(); 650 keyboard_container->set_id(kShellWindowId_VirtualKeyboardContainer); 651 parent->AddChild(keyboard_container); 652 // TODO(oshima): Bounds of keyboard container should be handled by 653 // RootWindowLayoutManager. Remove this after fixed RootWindowLayoutManager. 654 keyboard_container->SetBounds(parent->bounds()); 655 } 656 657 void RootWindowController::DeactivateKeyboard( 658 keyboard::KeyboardController* keyboard_controller) { 659 if (!keyboard_controller || 660 !keyboard_controller->keyboard_container_initialized()) { 661 return; 662 } 663 aura::Window* keyboard_container = 664 keyboard_controller->GetContainerWindow(); 665 if (keyboard_container->GetRootWindow() == GetRootWindow()) { 666 aura::Window* parent = GetContainer( 667 kShellWindowId_VirtualKeyboardParentContainer); 668 DCHECK(parent); 669 parent->RemoveChild(keyboard_container); 670 // Virtual keyboard may be deactivated while still showing, notify all 671 // observers that keyboard bounds changed to 0 before remove them. 672 keyboard_controller->NotifyKeyboardBoundsChanging(gfx::Rect()); 673 keyboard_controller->RemoveObserver(shelf()->shelf_layout_manager()); 674 keyboard_controller->RemoveObserver(panel_layout_manager_); 675 keyboard_controller->RemoveObserver(docked_layout_manager_); 676 keyboard_controller->RemoveObserver( 677 workspace_controller_->layout_manager()); 678 Shell::GetInstance()->delegate()->VirtualKeyboardActivated(false); 679 } 680 } 681 682 bool RootWindowController::IsVirtualKeyboardWindow(aura::Window* window) { 683 aura::Window* parent = GetContainer( 684 kShellWindowId_VirtualKeyboardParentContainer); 685 return parent ? parent->Contains(window) : false; 686 } 687 688 //////////////////////////////////////////////////////////////////////////////// 689 // RootWindowController, private: 690 691 RootWindowController::RootWindowController(AshWindowTreeHost* ash_host) 692 : ash_host_(ash_host), 693 root_window_layout_(NULL), 694 docked_layout_manager_(NULL), 695 panel_layout_manager_(NULL), 696 touch_hud_debug_(NULL), 697 touch_hud_projection_(NULL) { 698 aura::Window* root_window = GetRootWindow(); 699 GetRootWindowSettings(root_window)->controller = this; 700 screen_dimmer_.reset(new ScreenDimmer(root_window)); 701 702 stacking_controller_.reset(new StackingController); 703 aura::client::SetWindowTreeClient(root_window, stacking_controller_.get()); 704 capture_client_.reset(new ::wm::ScopedCaptureClient(root_window)); 705 } 706 707 void RootWindowController::Init(RootWindowType root_window_type, 708 bool first_run_after_boot) { 709 aura::Window* root_window = GetRootWindow(); 710 Shell* shell = Shell::GetInstance(); 711 shell->InitRootWindow(root_window); 712 713 ash_host_->AsWindowTreeHost()->SetCursor(ui::kCursorPointer); 714 CreateContainersInRootWindow(root_window); 715 716 CreateSystemBackground(first_run_after_boot); 717 718 InitLayoutManagers(); 719 InitTouchHuds(); 720 721 if (Shell::GetPrimaryRootWindowController()-> 722 GetSystemModalLayoutManager(NULL)->has_modal_background()) { 723 GetSystemModalLayoutManager(NULL)->CreateModalBackground(); 724 } 725 726 shell->AddShellObserver(this); 727 728 if (root_window_type == PRIMARY) { 729 root_window_layout()->OnWindowResized(); 730 shell->InitKeyboard(); 731 } else { 732 root_window_layout()->OnWindowResized(); 733 ash_host_->AsWindowTreeHost()->Show(); 734 735 // Create a shelf if a user is already logged in. 736 if (shell->session_state_delegate()->NumberOfLoggedInUsers()) 737 shelf()->CreateShelf(); 738 739 // Notify shell observers about new root window. 740 shell->OnRootWindowAdded(root_window); 741 } 742 743 #if defined(OS_CHROMEOS) 744 if (!CommandLine::ForCurrentProcess()->HasSwitch( 745 switches::kAshDisableTouchExplorationMode)) { 746 touch_exploration_manager_.reset(new AshTouchExplorationManager(this)); 747 } 748 #endif 749 } 750 751 void RootWindowController::InitLayoutManagers() { 752 aura::Window* root_window = GetRootWindow(); 753 root_window_layout_ = new RootWindowLayoutManager(root_window); 754 root_window->SetLayoutManager(root_window_layout_); 755 756 aura::Window* default_container = 757 GetContainer(kShellWindowId_DefaultContainer); 758 // Workspace manager has its own layout managers. 759 workspace_controller_.reset( 760 new WorkspaceController(default_container)); 761 762 aura::Window* always_on_top_container = 763 GetContainer(kShellWindowId_AlwaysOnTopContainer); 764 always_on_top_container->SetLayoutManager( 765 new WorkspaceLayoutManager(always_on_top_container)); 766 always_on_top_controller_.reset(new AlwaysOnTopController); 767 always_on_top_controller_->SetAlwaysOnTopContainer(always_on_top_container); 768 769 DCHECK(!shelf_.get()); 770 aura::Window* shelf_container = GetContainer(kShellWindowId_ShelfContainer); 771 // TODO(harrym): Remove when status area is view. 772 aura::Window* status_container = GetContainer(kShellWindowId_StatusContainer); 773 shelf_.reset(new ShelfWidget( 774 shelf_container, status_container, workspace_controller())); 775 776 if (!Shell::GetInstance()->session_state_delegate()-> 777 IsActiveUserSessionStarted()) { 778 // This window exists only to be a event target on login screen. 779 // It does not have to handle events, nor be visible. 780 mouse_event_target_.reset(new aura::Window(new EmptyWindowDelegate)); 781 mouse_event_target_->Init(aura::WINDOW_LAYER_NOT_DRAWN); 782 783 aura::Window* lock_background_container = 784 GetContainer(kShellWindowId_LockScreenBackgroundContainer); 785 lock_background_container->AddChild(mouse_event_target_.get()); 786 mouse_event_target_->Show(); 787 } 788 789 // Create Docked windows layout manager 790 aura::Window* docked_container = GetContainer(kShellWindowId_DockedContainer); 791 docked_layout_manager_ = 792 new DockedWindowLayoutManager(docked_container, workspace_controller()); 793 docked_container->SetLayoutManager(docked_layout_manager_); 794 795 // Installs SnapLayoutManager to containers who set the 796 // |kSnapsChildrenToPhysicalPixelBoundary| property. 797 wm::InstallSnapLayoutManagerToContainers(root_window); 798 799 // Create Panel layout manager 800 aura::Window* panel_container = GetContainer(kShellWindowId_PanelContainer); 801 panel_layout_manager_ = new PanelLayoutManager(panel_container); 802 panel_container->SetLayoutManager(panel_layout_manager_); 803 panel_container_handler_.reset(new PanelWindowEventHandler); 804 panel_container->AddPreTargetHandler(panel_container_handler_.get()); 805 806 // Install an AttachedPanelWindowTargeter on the panel container to make it 807 // easier to correctly target shelf buttons with touch. 808 gfx::Insets mouse_extend(-kResizeOutsideBoundsSize, 809 -kResizeOutsideBoundsSize, 810 -kResizeOutsideBoundsSize, 811 -kResizeOutsideBoundsSize); 812 gfx::Insets touch_extend = mouse_extend.Scale( 813 kResizeOutsideBoundsScaleForTouch); 814 panel_container->SetEventTargeter(scoped_ptr<ui::EventTargeter>( 815 new AttachedPanelWindowTargeter(panel_container, 816 mouse_extend, 817 touch_extend, 818 panel_layout_manager_))); 819 } 820 821 void RootWindowController::InitTouchHuds() { 822 CommandLine* command_line = CommandLine::ForCurrentProcess(); 823 if (command_line->HasSwitch(switches::kAshTouchHud)) 824 set_touch_hud_debug(new TouchHudDebug(GetRootWindow())); 825 if (Shell::GetInstance()->is_touch_hud_projection_enabled()) 826 EnableTouchHudProjection(); 827 } 828 829 void RootWindowController::CreateSystemBackground( 830 bool is_first_run_after_boot) { 831 SkColor color = SK_ColorBLACK; 832 #if defined(OS_CHROMEOS) 833 if (is_first_run_after_boot) 834 color = kChromeOsBootColor; 835 #endif 836 system_background_.reset( 837 new SystemBackgroundController(GetRootWindow(), color)); 838 839 #if defined(OS_CHROMEOS) 840 // Make a copy of the system's boot splash screen so we can composite it 841 // onscreen until the desktop background is ready. 842 if (is_first_run_after_boot && 843 (CommandLine::ForCurrentProcess()->HasSwitch( 844 switches::kAshCopyHostBackgroundAtBoot) || 845 CommandLine::ForCurrentProcess()->HasSwitch( 846 switches::kAshAnimateFromBootSplashScreen))) 847 boot_splash_screen_.reset(new BootSplashScreen(GetHost())); 848 #endif 849 } 850 851 void RootWindowController::CreateContainersInRootWindow( 852 aura::Window* root_window) { 853 // These containers are just used by PowerButtonController to animate groups 854 // of containers simultaneously without messing up the current transformations 855 // on those containers. These are direct children of the root window; all of 856 // the other containers are their children. 857 858 // The desktop background container is not part of the lock animation, so it 859 // is not included in those animate groups. 860 // When screen is locked desktop background is moved to lock screen background 861 // container (moved back on unlock). We want to make sure that there's an 862 // opaque layer occluding the non-lock-screen layers. 863 aura::Window* desktop_background_container = CreateContainer( 864 kShellWindowId_DesktopBackgroundContainer, 865 "DesktopBackgroundContainer", 866 root_window); 867 ::wm::SetChildWindowVisibilityChangesAnimated(desktop_background_container); 868 869 aura::Window* non_lock_screen_containers = CreateContainer( 870 kShellWindowId_NonLockScreenContainersContainer, 871 "NonLockScreenContainersContainer", 872 root_window); 873 874 aura::Window* lock_background_containers = CreateContainer( 875 kShellWindowId_LockScreenBackgroundContainer, 876 "LockScreenBackgroundContainer", 877 root_window); 878 ::wm::SetChildWindowVisibilityChangesAnimated(lock_background_containers); 879 880 aura::Window* lock_screen_containers = CreateContainer( 881 kShellWindowId_LockScreenContainersContainer, 882 "LockScreenContainersContainer", 883 root_window); 884 aura::Window* lock_screen_related_containers = CreateContainer( 885 kShellWindowId_LockScreenRelatedContainersContainer, 886 "LockScreenRelatedContainersContainer", 887 root_window); 888 889 CreateContainer(kShellWindowId_UnparentedControlContainer, 890 "UnparentedControlContainer", 891 non_lock_screen_containers); 892 893 aura::Window* default_container = CreateContainer( 894 kShellWindowId_DefaultContainer, 895 "DefaultContainer", 896 non_lock_screen_containers); 897 ::wm::SetChildWindowVisibilityChangesAnimated(default_container); 898 wm::SetSnapsChildrenToPhysicalPixelBoundary(default_container); 899 SetUsesScreenCoordinates(default_container); 900 SetUsesEasyResizeTargeter(default_container); 901 902 aura::Window* always_on_top_container = CreateContainer( 903 kShellWindowId_AlwaysOnTopContainer, 904 "AlwaysOnTopContainer", 905 non_lock_screen_containers); 906 ::wm::SetChildWindowVisibilityChangesAnimated(always_on_top_container); 907 wm::SetSnapsChildrenToPhysicalPixelBoundary(always_on_top_container); 908 SetUsesScreenCoordinates(always_on_top_container); 909 910 aura::Window* docked_container = CreateContainer( 911 kShellWindowId_DockedContainer, 912 "DockedContainer", 913 non_lock_screen_containers); 914 ::wm::SetChildWindowVisibilityChangesAnimated(docked_container); 915 wm::SetSnapsChildrenToPhysicalPixelBoundary(docked_container); 916 SetUsesScreenCoordinates(docked_container); 917 SetUsesEasyResizeTargeter(docked_container); 918 919 aura::Window* shelf_container = 920 CreateContainer(kShellWindowId_ShelfContainer, 921 "ShelfContainer", 922 non_lock_screen_containers); 923 wm::SetSnapsChildrenToPhysicalPixelBoundary(shelf_container); 924 SetUsesScreenCoordinates(shelf_container); 925 DescendantShouldStayInSameRootWindow(shelf_container); 926 927 aura::Window* panel_container = CreateContainer( 928 kShellWindowId_PanelContainer, 929 "PanelContainer", 930 non_lock_screen_containers); 931 wm::SetSnapsChildrenToPhysicalPixelBoundary(panel_container); 932 SetUsesScreenCoordinates(panel_container); 933 934 aura::Window* shelf_bubble_container = 935 CreateContainer(kShellWindowId_ShelfBubbleContainer, 936 "ShelfBubbleContainer", 937 non_lock_screen_containers); 938 wm::SetSnapsChildrenToPhysicalPixelBoundary(shelf_bubble_container); 939 SetUsesScreenCoordinates(shelf_bubble_container); 940 DescendantShouldStayInSameRootWindow(shelf_bubble_container); 941 942 aura::Window* app_list_container = 943 CreateContainer(kShellWindowId_AppListContainer, 944 "AppListContainer", 945 non_lock_screen_containers); 946 wm::SetSnapsChildrenToPhysicalPixelBoundary(app_list_container); 947 SetUsesScreenCoordinates(app_list_container); 948 949 aura::Window* modal_container = CreateContainer( 950 kShellWindowId_SystemModalContainer, 951 "SystemModalContainer", 952 non_lock_screen_containers); 953 wm::SetSnapsChildrenToPhysicalPixelBoundary(modal_container); 954 modal_container->SetLayoutManager( 955 new SystemModalContainerLayoutManager(modal_container)); 956 ::wm::SetChildWindowVisibilityChangesAnimated(modal_container); 957 SetUsesScreenCoordinates(modal_container); 958 SetUsesEasyResizeTargeter(modal_container); 959 960 // TODO(beng): Figure out if we can make this use 961 // SystemModalContainerEventFilter instead of stops_event_propagation. 962 aura::Window* lock_container = CreateContainer( 963 kShellWindowId_LockScreenContainer, 964 "LockScreenContainer", 965 lock_screen_containers); 966 wm::SetSnapsChildrenToPhysicalPixelBoundary(lock_container); 967 if (CommandLine::ForCurrentProcess()->HasSwitch( 968 switches::kAshDisableLockLayoutManager)) { 969 lock_container->SetLayoutManager( 970 new WorkspaceLayoutManager(lock_container)); 971 } else { 972 lock_container->SetLayoutManager(new LockLayoutManager(lock_container)); 973 } 974 SetUsesScreenCoordinates(lock_container); 975 // TODO(beng): stopsevents 976 977 aura::Window* lock_modal_container = CreateContainer( 978 kShellWindowId_LockSystemModalContainer, 979 "LockSystemModalContainer", 980 lock_screen_containers); 981 wm::SetSnapsChildrenToPhysicalPixelBoundary(lock_modal_container); 982 lock_modal_container->SetLayoutManager( 983 new SystemModalContainerLayoutManager(lock_modal_container)); 984 ::wm::SetChildWindowVisibilityChangesAnimated(lock_modal_container); 985 SetUsesScreenCoordinates(lock_modal_container); 986 SetUsesEasyResizeTargeter(lock_modal_container); 987 988 aura::Window* status_container = 989 CreateContainer(kShellWindowId_StatusContainer, 990 "StatusContainer", 991 lock_screen_related_containers); 992 wm::SetSnapsChildrenToPhysicalPixelBoundary(status_container); 993 SetUsesScreenCoordinates(status_container); 994 DescendantShouldStayInSameRootWindow(status_container); 995 996 aura::Window* settings_bubble_container = CreateContainer( 997 kShellWindowId_SettingBubbleContainer, 998 "SettingBubbleContainer", 999 lock_screen_related_containers); 1000 ::wm::SetChildWindowVisibilityChangesAnimated(settings_bubble_container); 1001 wm::SetSnapsChildrenToPhysicalPixelBoundary(settings_bubble_container); 1002 SetUsesScreenCoordinates(settings_bubble_container); 1003 DescendantShouldStayInSameRootWindow(settings_bubble_container); 1004 1005 aura::Window* virtual_keyboard_parent_container = 1006 CreateContainer(kShellWindowId_VirtualKeyboardParentContainer, 1007 "VirtualKeyboardParentContainer", 1008 lock_screen_related_containers); 1009 wm::SetSnapsChildrenToPhysicalPixelBoundary( 1010 virtual_keyboard_parent_container); 1011 virtual_keyboard_parent_container->SetLayoutManager( 1012 new VirtualKeyboardContainerLayoutManager( 1013 virtual_keyboard_parent_container)); 1014 SetUsesScreenCoordinates(virtual_keyboard_parent_container); 1015 1016 aura::Window* menu_container = CreateContainer( 1017 kShellWindowId_MenuContainer, 1018 "MenuContainer", 1019 lock_screen_related_containers); 1020 ::wm::SetChildWindowVisibilityChangesAnimated(menu_container); 1021 wm::SetSnapsChildrenToPhysicalPixelBoundary(menu_container); 1022 SetUsesScreenCoordinates(menu_container); 1023 1024 aura::Window* drag_drop_container = CreateContainer( 1025 kShellWindowId_DragImageAndTooltipContainer, 1026 "DragImageAndTooltipContainer", 1027 lock_screen_related_containers); 1028 ::wm::SetChildWindowVisibilityChangesAnimated(drag_drop_container); 1029 wm::SetSnapsChildrenToPhysicalPixelBoundary(drag_drop_container); 1030 SetUsesScreenCoordinates(drag_drop_container); 1031 1032 aura::Window* overlay_container = CreateContainer( 1033 kShellWindowId_OverlayContainer, 1034 "OverlayContainer", 1035 lock_screen_related_containers); 1036 wm::SetSnapsChildrenToPhysicalPixelBoundary(overlay_container); 1037 SetUsesScreenCoordinates(overlay_container); 1038 1039 #if defined(OS_CHROMEOS) 1040 aura::Window* mouse_cursor_container = CreateContainer( 1041 kShellWindowId_MouseCursorContainer, 1042 "MouseCursorContainer", 1043 root_window); 1044 SetUsesScreenCoordinates(mouse_cursor_container); 1045 #endif 1046 1047 CreateContainer(kShellWindowId_PowerButtonAnimationContainer, 1048 "PowerButtonAnimationContainer", root_window); 1049 } 1050 1051 void RootWindowController::EnableTouchHudProjection() { 1052 if (touch_hud_projection_) 1053 return; 1054 set_touch_hud_projection(new TouchHudProjection(GetRootWindow())); 1055 } 1056 1057 void RootWindowController::DisableTouchHudProjection() { 1058 if (!touch_hud_projection_) 1059 return; 1060 touch_hud_projection_->Remove(); 1061 } 1062 1063 void RootWindowController::OnLoginStateChanged(user::LoginStatus status) { 1064 shelf_->shelf_layout_manager()->UpdateVisibilityState(); 1065 } 1066 1067 void RootWindowController::OnTouchHudProjectionToggled(bool enabled) { 1068 if (enabled) 1069 EnableTouchHudProjection(); 1070 else 1071 DisableTouchHudProjection(); 1072 } 1073 1074 RootWindowController* GetRootWindowController( 1075 const aura::Window* root_window) { 1076 return root_window ? GetRootWindowSettings(root_window)->controller : NULL; 1077 } 1078 1079 } // namespace ash 1080