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
85namespace ash {
86namespace {
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.
93const int kBootSplashScreenHideDurationMs = 500;
94#endif
95
96// Creates a new window for use as a container.
97aura::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
110float ToRelativeValue(int value, int src, int dst) {
111  return static_cast<float>(value) / static_cast<float>(src) * dst;
112}
113
114void 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|.
124void 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|.
156void 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.
189void 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.
195void DescendantShouldStayInSameRootWindow(aura::Window* container) {
196  container->SetProperty(kStayInSameRootWindowKey, true);
197}
198
199void 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.
213class 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
267void RootWindowController::CreateForPrimaryDisplay(AshWindowTreeHost* host) {
268  RootWindowController* controller = new RootWindowController(host);
269  controller->Init(RootWindowController::PRIMARY,
270                   Shell::GetInstance()->delegate()->IsFirstRunAfterBoot());
271}
272
273void RootWindowController::CreateForSecondaryDisplay(AshWindowTreeHost* host) {
274  RootWindowController* controller = new RootWindowController(host);
275  controller->Init(RootWindowController::SECONDARY, false /* first run */);
276}
277
278// static
279RootWindowController* RootWindowController::ForShelf(
280    const aura::Window* window) {
281  CHECK(Shell::HasInstance());
282  return GetRootWindowController(window->GetRootWindow());
283}
284
285// static
286RootWindowController* RootWindowController::ForWindow(
287    const aura::Window* window) {
288  CHECK(Shell::HasInstance());
289  return GetRootWindowController(window->GetRootWindow());
290}
291
292// static
293RootWindowController* RootWindowController::ForTargetRootWindow() {
294  CHECK(Shell::HasInstance());
295  return GetRootWindowController(Shell::GetTargetRootWindow());
296}
297
298// static
299aura::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
307RootWindowController::~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
315aura::WindowTreeHost* RootWindowController::GetHost() {
316  return ash_host_->AsWindowTreeHost();
317}
318
319const aura::WindowTreeHost* RootWindowController::GetHost() const {
320  return ash_host_->AsWindowTreeHost();
321}
322
323aura::Window* RootWindowController::GetRootWindow() {
324  return GetHost()->window();
325}
326
327const aura::Window* RootWindowController::GetRootWindow() const {
328  return GetHost()->window();
329}
330
331void RootWindowController::SetWallpaperController(
332    DesktopBackgroundWidgetController* controller) {
333  wallpaper_controller_.reset(controller);
334}
335
336void RootWindowController::SetAnimatingWallpaperController(
337    AnimatingDesktopController* controller) {
338  if (animating_wallpaper_controller_.get())
339    animating_wallpaper_controller_->StopAnimating();
340  animating_wallpaper_controller_.reset(controller);
341}
342
343void 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
383SystemModalContainerLayoutManager*
384RootWindowController::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
404aura::Window* RootWindowController::GetContainer(int container_id) {
405  return GetRootWindow()->GetChildById(container_id);
406}
407
408const aura::Window* RootWindowController::GetContainer(int container_id) const {
409  return ash_host_->AsWindowTreeHost()->window()->GetChildById(container_id);
410}
411
412void RootWindowController::ShowShelf() {
413  if (!shelf_->shelf())
414    return;
415  shelf_->shelf()->SetVisible(true);
416  shelf_->status_area_widget()->Show();
417}
418
419void 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
432void 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
440void 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
453void 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
477void 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
550void 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
557ShelfLayoutManager* RootWindowController::GetShelfLayoutManager() {
558  return shelf_->shelf_layout_manager();
559}
560
561SystemTray* 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
568void 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
595void RootWindowController::UpdateShelfVisibility() {
596  shelf_->shelf_layout_manager()->UpdateVisibilityState();
597}
598
599const 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
633void 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
657void 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
682bool 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
691RootWindowController::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
707void 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
751void 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
821void 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
829void 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
851void 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
1051void RootWindowController::EnableTouchHudProjection() {
1052  if (touch_hud_projection_)
1053    return;
1054  set_touch_hud_projection(new TouchHudProjection(GetRootWindow()));
1055}
1056
1057void RootWindowController::DisableTouchHudProjection() {
1058  if (!touch_hud_projection_)
1059    return;
1060  touch_hud_projection_->Remove();
1061}
1062
1063void RootWindowController::OnLoginStateChanged(user::LoginStatus status) {
1064  shelf_->shelf_layout_manager()->UpdateVisibilityState();
1065}
1066
1067void RootWindowController::OnTouchHudProjectionToggled(bool enabled) {
1068  if (enabled)
1069    EnableTouchHudProjection();
1070  else
1071    DisableTouchHudProjection();
1072}
1073
1074RootWindowController* GetRootWindowController(
1075    const aura::Window* root_window) {
1076  return root_window ? GetRootWindowSettings(root_window)->controller : NULL;
1077}
1078
1079}  // namespace ash
1080