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