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