display_controller.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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/display/display_controller.h"
6
7#include <algorithm>
8#include <cmath>
9#include <map>
10
11#include "ash/ash_switches.h"
12#include "ash/display/display_layout_store.h"
13#include "ash/display/display_manager.h"
14#include "ash/display/mirror_window_controller.h"
15#include "ash/display/root_window_transformers.h"
16#include "ash/host/root_window_host_factory.h"
17#include "ash/root_window_controller.h"
18#include "ash/root_window_settings.h"
19#include "ash/screen_ash.h"
20#include "ash/shell.h"
21#include "ash/wm/coordinate_conversion.h"
22#include "base/command_line.h"
23#include "base/strings/stringprintf.h"
24#include "third_party/skia/include/utils/SkMatrix44.h"
25#include "ui/aura/client/activation_client.h"
26#include "ui/aura/client/capture_client.h"
27#include "ui/aura/client/cursor_client.h"
28#include "ui/aura/client/focus_client.h"
29#include "ui/aura/client/screen_position_client.h"
30#include "ui/aura/root_window.h"
31#include "ui/aura/root_window_transformer.h"
32#include "ui/aura/window.h"
33#include "ui/aura/window_property.h"
34#include "ui/aura/window_tracker.h"
35#include "ui/compositor/compositor.h"
36#include "ui/compositor/dip_util.h"
37#include "ui/gfx/display.h"
38#include "ui/gfx/screen.h"
39
40#if defined(OS_CHROMEOS)
41#include "base/sys_info.h"
42#include "base/time/time.h"
43#if defined(USE_X11)
44#include "ash/display/output_configurator_animation.h"
45#include "chromeos/display/output_configurator.h"
46#include "ui/base/x/x11_util.h"
47#include "ui/gfx/x/x11_types.h"
48
49// Including this at the bottom to avoid other
50// potential conflict with chrome headers.
51#include <X11/extensions/Xrandr.h>
52#undef RootWindow
53#endif  // defined(USE_X11)
54#endif  // defined(OS_CHROMEOS)
55
56namespace ash {
57namespace {
58
59// Primary display stored in global object as it can be
60// accessed after Shell is deleted. A separate display instance is created
61// during the shutdown instead of always keeping two display instances
62// (one here and another one in display_manager) in sync, which is error prone.
63int64 primary_display_id = gfx::Display::kInvalidDisplayID;
64gfx::Display* primary_display_for_shutdown = NULL;
65// Keeps the number of displays during the shutdown after
66// ash::Shell:: is deleted.
67int num_displays_for_shutdown = -1;
68
69// Specifies how long the display change should have been disabled
70// after each display change operations.
71// |kCycleDisplayThrottleTimeoutMs| is set to be longer to avoid
72// changing the settings while the system is still configurating
73// displays. It will be overriden by |kAfterDisplayChangeThrottleTimeoutMs|
74// when the display change happens, so the actual timeout is much shorter.
75const int64 kAfterDisplayChangeThrottleTimeoutMs = 500;
76const int64 kCycleDisplayThrottleTimeoutMs = 4000;
77const int64 kSwapDisplayThrottleTimeoutMs = 500;
78
79internal::DisplayManager* GetDisplayManager() {
80  return Shell::GetInstance()->display_manager();
81}
82
83void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root,
84                                      const gfx::Display& display) {
85  internal::DisplayInfo info =
86      GetDisplayManager()->GetDisplayInfo(display.id());
87#if defined(OS_CHROMEOS) && defined(USE_X11)
88  // Native window property (Atom in X11) that specifies the display's
89  // rotation, scale factor and if it's internal display.  They are
90  // read and used by touchpad/mouse driver directly on X (contact
91  // adlr@ for more details on touchpad/mouse driver side). The value
92  // of the rotation is one of 0 (normal), 1 (90 degrees clockwise), 2
93  // (180 degree) or 3 (270 degrees clockwise).  The value of the
94  // scale factor is in percent (100, 140, 200 etc).
95  const char kRotationProp[] = "_CHROME_DISPLAY_ROTATION";
96  const char kScaleFactorProp[] = "_CHROME_DISPLAY_SCALE_FACTOR";
97  const char kInternalProp[] = "_CHROME_DISPLAY_INTERNAL";
98  const char kCARDINAL[] = "CARDINAL";
99  int xrandr_rotation = RR_Rotate_0;
100  switch (info.rotation()) {
101    case gfx::Display::ROTATE_0:
102      xrandr_rotation = RR_Rotate_0;
103      break;
104    case gfx::Display::ROTATE_90:
105      xrandr_rotation = RR_Rotate_90;
106      break;
107    case gfx::Display::ROTATE_180:
108      xrandr_rotation = RR_Rotate_180;
109      break;
110    case gfx::Display::ROTATE_270:
111      xrandr_rotation = RR_Rotate_270;
112      break;
113  }
114
115  int internal = display.IsInternal() ? 1 : 0;
116  gfx::AcceleratedWidget xwindow = root->GetAcceleratedWidget();
117  ui::SetIntProperty(xwindow, kInternalProp, kCARDINAL, internal);
118  ui::SetIntProperty(xwindow, kRotationProp, kCARDINAL, xrandr_rotation);
119  ui::SetIntProperty(xwindow,
120                     kScaleFactorProp,
121                     kCARDINAL,
122                     100 * display.device_scale_factor());
123#endif
124  scoped_ptr<aura::RootWindowTransformer> transformer(
125      internal::CreateRootWindowTransformerForDisplay(root, display));
126  root->SetRootWindowTransformer(transformer.Pass());
127}
128
129}  // namespace
130
131namespace internal {
132
133// A utility class to store/restore focused/active window
134// when the display configuration has changed.
135class FocusActivationStore {
136 public:
137  FocusActivationStore()
138      : activation_client_(NULL),
139        capture_client_(NULL),
140        focus_client_(NULL),
141        focused_(NULL),
142        active_(NULL) {
143  }
144
145  void Store(bool display_removed) {
146    if (!activation_client_) {
147      aura::RootWindow* root = Shell::GetPrimaryRootWindow();
148      activation_client_ = aura::client::GetActivationClient(root);
149      capture_client_ = aura::client::GetCaptureClient(root);
150      focus_client_ = aura::client::GetFocusClient(root);
151    }
152    focused_ = focus_client_->GetFocusedWindow();
153    if (focused_)
154      tracker_.Add(focused_);
155    active_ = activation_client_->GetActiveWindow();
156    if (active_ && focused_ != active_)
157      tracker_.Add(active_);
158
159    // Deactivate the window to close menu / bubble windows.
160    if (display_removed)
161      activation_client_->DeactivateWindow(active_);
162
163    // Release capture if any.
164    capture_client_->SetCapture(NULL);
165    // Clear the focused window if any. This is necessary because a
166    // window may be deleted when losing focus (fullscreen flash for
167    // example).  If the focused window is still alive after move, it'll
168    // be re-focused below.
169    if (display_removed)
170      focus_client_->FocusWindow(NULL);
171  }
172
173  void Restore() {
174    // Restore focused or active window if it's still alive.
175    if (focused_ && tracker_.Contains(focused_)) {
176      focus_client_->FocusWindow(focused_);
177    } else if (active_ && tracker_.Contains(active_)) {
178      activation_client_->ActivateWindow(active_);
179    }
180    if (focused_)
181      tracker_.Remove(focused_);
182    if (active_)
183      tracker_.Remove(active_);
184    focused_ = NULL;
185    active_ = NULL;
186  }
187
188 private:
189  aura::client::ActivationClient* activation_client_;
190  aura::client::CaptureClient* capture_client_;
191  aura::client::FocusClient* focus_client_;
192  aura::WindowTracker tracker_;
193  aura::Window* focused_;
194  aura::Window* active_;
195
196  DISALLOW_COPY_AND_ASSIGN(FocusActivationStore);
197};
198
199}  // namespace internal
200
201////////////////////////////////////////////////////////////////////////////////
202// DisplayChangeLimiter
203
204DisplayController::DisplayChangeLimiter::DisplayChangeLimiter()
205    : throttle_timeout_(base::Time::Now()) {
206}
207
208void DisplayController::DisplayChangeLimiter::SetThrottleTimeout(
209    int64 throttle_ms) {
210  throttle_timeout_ =
211      base::Time::Now() + base::TimeDelta::FromMilliseconds(throttle_ms);
212}
213
214bool DisplayController::DisplayChangeLimiter::IsThrottled() const {
215  return base::Time::Now() < throttle_timeout_;
216}
217
218////////////////////////////////////////////////////////////////////////////////
219// DisplayController
220
221DisplayController::DisplayController()
222    : primary_root_window_for_replace_(NULL),
223      focus_activation_store_(new internal::FocusActivationStore()),
224      mirror_window_controller_(new internal::MirrorWindowController) {
225#if defined(OS_CHROMEOS)
226  CommandLine* command_line = CommandLine::ForCurrentProcess();
227  if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) &&
228      base::SysInfo::IsRunningOnChromeOS())
229    limiter_.reset(new DisplayChangeLimiter);
230#endif
231  // Reset primary display to make sure that tests don't use
232  // stale display info from previous tests.
233  primary_display_id = gfx::Display::kInvalidDisplayID;
234  delete primary_display_for_shutdown;
235  primary_display_for_shutdown = NULL;
236  num_displays_for_shutdown = -1;
237}
238
239DisplayController::~DisplayController() {
240  DCHECK(primary_display_for_shutdown);
241}
242
243void DisplayController::Start() {
244  Shell::GetScreen()->AddObserver(this);
245  Shell::GetInstance()->display_manager()->set_delegate(this);
246}
247
248void DisplayController::Shutdown() {
249  // Unset the display manager's delegate here because
250  // DisplayManager outlives DisplayController.
251  Shell::GetInstance()->display_manager()->set_delegate(NULL);
252
253  mirror_window_controller_.reset();
254
255  DCHECK(!primary_display_for_shutdown);
256  primary_display_for_shutdown = new gfx::Display(
257      GetDisplayManager()->GetDisplayForId(primary_display_id));
258  num_displays_for_shutdown = GetDisplayManager()->GetNumDisplays();
259
260  Shell::GetScreen()->RemoveObserver(this);
261  // Delete all root window controllers, which deletes root window
262  // from the last so that the primary root window gets deleted last.
263  for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it =
264           root_windows_.rbegin(); it != root_windows_.rend(); ++it) {
265    internal::RootWindowController* controller =
266        internal::GetRootWindowController(it->second);
267    DCHECK(controller);
268    delete controller;
269  }
270}
271
272// static
273const gfx::Display& DisplayController::GetPrimaryDisplay() {
274  DCHECK_NE(primary_display_id, gfx::Display::kInvalidDisplayID);
275  if (primary_display_for_shutdown)
276    return *primary_display_for_shutdown;
277  return GetDisplayManager()->GetDisplayForId(primary_display_id);
278}
279
280// static
281int DisplayController::GetNumDisplays() {
282  if (num_displays_for_shutdown >= 0)
283    return num_displays_for_shutdown;
284  return GetDisplayManager()->GetNumDisplays();
285}
286
287void DisplayController::InitPrimaryDisplay() {
288  const gfx::Display& primary_candidate =
289      GetDisplayManager()->GetPrimaryDisplayCandidate();
290  primary_display_id = primary_candidate.id();
291  AddRootWindowForDisplay(primary_candidate);
292}
293
294void DisplayController::InitSecondaryDisplays() {
295  internal::DisplayManager* display_manager = GetDisplayManager();
296  for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
297    const gfx::Display& display = display_manager->GetDisplayAt(i);
298    if (primary_display_id != display.id()) {
299      aura::RootWindow* root = AddRootWindowForDisplay(display);
300      internal::RootWindowController::CreateForSecondaryDisplay(root);
301    }
302  }
303  UpdateHostWindowNames();
304}
305
306void DisplayController::AddObserver(Observer* observer) {
307  observers_.AddObserver(observer);
308}
309
310void DisplayController::RemoveObserver(Observer* observer) {
311  observers_.RemoveObserver(observer);
312}
313
314aura::RootWindow* DisplayController::GetPrimaryRootWindow() {
315  DCHECK(!root_windows_.empty());
316  return root_windows_[primary_display_id];
317}
318
319aura::RootWindow* DisplayController::GetRootWindowForDisplayId(int64 id) {
320  return root_windows_[id];
321}
322
323void DisplayController::CloseChildWindows() {
324  for (std::map<int64, aura::RootWindow*>::const_iterator it =
325           root_windows_.begin(); it != root_windows_.end(); ++it) {
326    aura::RootWindow* root_window = it->second;
327    internal::RootWindowController* controller =
328        internal::GetRootWindowController(root_window);
329    if (controller) {
330      controller->CloseChildWindows();
331    } else {
332      while (!root_window->children().empty()) {
333        aura::Window* child = root_window->children()[0];
334        delete child;
335      }
336    }
337  }
338}
339
340std::vector<aura::RootWindow*> DisplayController::GetAllRootWindows() {
341  std::vector<aura::RootWindow*> windows;
342  for (std::map<int64, aura::RootWindow*>::const_iterator it =
343           root_windows_.begin(); it != root_windows_.end(); ++it) {
344    DCHECK(it->second);
345    if (internal::GetRootWindowController(it->second))
346      windows.push_back(it->second);
347  }
348  return windows;
349}
350
351gfx::Insets DisplayController::GetOverscanInsets(int64 display_id) const {
352  return GetDisplayManager()->GetOverscanInsets(display_id);
353}
354
355void DisplayController::SetOverscanInsets(int64 display_id,
356                                          const gfx::Insets& insets_in_dip) {
357  GetDisplayManager()->SetOverscanInsets(display_id, insets_in_dip);
358}
359
360std::vector<internal::RootWindowController*>
361DisplayController::GetAllRootWindowControllers() {
362  std::vector<internal::RootWindowController*> controllers;
363  for (std::map<int64, aura::RootWindow*>::const_iterator it =
364           root_windows_.begin(); it != root_windows_.end(); ++it) {
365    internal::RootWindowController* controller =
366        internal::GetRootWindowController(it->second);
367    if (controller)
368      controllers.push_back(controller);
369  }
370  return controllers;
371}
372
373void DisplayController::ToggleMirrorMode() {
374  internal::DisplayManager* display_manager = GetDisplayManager();
375  if (display_manager->num_connected_displays() <= 1)
376    return;
377
378  if (limiter_) {
379    if  (limiter_->IsThrottled())
380      return;
381    limiter_->SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs);
382  }
383#if defined(OS_CHROMEOS) && defined(USE_X11)
384  Shell* shell = Shell::GetInstance();
385  internal::OutputConfiguratorAnimation* animation =
386      shell->output_configurator_animation();
387  animation->StartFadeOutAnimation(base::Bind(
388      base::IgnoreResult(&internal::DisplayManager::SetMirrorMode),
389      base::Unretained(display_manager),
390      !display_manager->IsMirrored()));
391#endif
392}
393
394void DisplayController::SwapPrimaryDisplay() {
395  if (limiter_) {
396    if  (limiter_->IsThrottled())
397      return;
398    limiter_->SetThrottleTimeout(kSwapDisplayThrottleTimeoutMs);
399  }
400
401  if (Shell::GetScreen()->GetNumDisplays() > 1) {
402#if defined(OS_CHROMEOS) && defined(USE_X11)
403    internal::OutputConfiguratorAnimation* animation =
404        Shell::GetInstance()->output_configurator_animation();
405    if (animation) {
406      animation->StartFadeOutAnimation(base::Bind(
407          &DisplayController::OnFadeOutForSwapDisplayFinished,
408          base::Unretained(this)));
409    } else {
410      SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
411    }
412#else
413    SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
414#endif
415  }
416}
417
418void DisplayController::SetPrimaryDisplayId(int64 id) {
419  DCHECK_NE(gfx::Display::kInvalidDisplayID, id);
420  if (id == gfx::Display::kInvalidDisplayID || primary_display_id == id)
421    return;
422
423  const gfx::Display& display = GetDisplayManager()->GetDisplayForId(id);
424  if (display.is_valid())
425    SetPrimaryDisplay(display);
426}
427
428void DisplayController::SetPrimaryDisplay(
429    const gfx::Display& new_primary_display) {
430  internal::DisplayManager* display_manager = GetDisplayManager();
431  DCHECK(new_primary_display.is_valid());
432  DCHECK(display_manager->IsActiveDisplay(new_primary_display));
433
434  if (!new_primary_display.is_valid() ||
435      !display_manager->IsActiveDisplay(new_primary_display)) {
436    LOG(ERROR) << "Invalid or non-existent display is requested:"
437               << new_primary_display.ToString();
438    return;
439  }
440
441  if (primary_display_id == new_primary_display.id() ||
442      root_windows_.size() < 2) {
443    return;
444  }
445
446  aura::RootWindow* non_primary_root = root_windows_[new_primary_display.id()];
447  LOG_IF(ERROR, !non_primary_root)
448      << "Unknown display is requested in SetPrimaryDisplay: id="
449      << new_primary_display.id();
450  if (!non_primary_root)
451    return;
452
453  gfx::Display old_primary_display = GetPrimaryDisplay();
454
455  // Swap root windows between current and new primary display.
456  aura::RootWindow* primary_root = root_windows_[primary_display_id];
457  DCHECK(primary_root);
458  DCHECK_NE(primary_root, non_primary_root);
459
460  root_windows_[new_primary_display.id()] = primary_root;
461  internal::GetRootWindowSettings(primary_root)->display_id =
462      new_primary_display.id();
463
464  root_windows_[old_primary_display.id()] = non_primary_root;
465  internal::GetRootWindowSettings(non_primary_root)->display_id =
466      old_primary_display.id();
467
468  primary_display_id = new_primary_display.id();
469  GetDisplayManager()->layout_store()->UpdatePrimaryDisplayId(
470      display_manager->GetCurrentDisplayIdPair(), primary_display_id);
471
472  UpdateWorkAreaOfDisplayNearestWindow(
473      primary_root, old_primary_display.GetWorkAreaInsets());
474  UpdateWorkAreaOfDisplayNearestWindow(
475      non_primary_root, new_primary_display.GetWorkAreaInsets());
476
477  // Update the dispay manager with new display info.
478  std::vector<internal::DisplayInfo> display_info_list;
479  display_info_list.push_back(display_manager->GetDisplayInfo(
480      primary_display_id));
481  display_info_list.push_back(display_manager->GetDisplayInfo(
482      ScreenAsh::GetSecondaryDisplay().id()));
483  GetDisplayManager()->set_force_bounds_changed(true);
484  GetDisplayManager()->UpdateDisplays(display_info_list);
485  GetDisplayManager()->set_force_bounds_changed(false);
486}
487
488void DisplayController::EnsurePointerInDisplays() {
489  // If the mouse is currently on a display in native location,
490  // use the same native location. Otherwise find the display closest
491  // to the current cursor location in screen coordinates.
492
493  gfx::Point point_in_screen = Shell::GetScreen()->GetCursorScreenPoint();
494  gfx::Point target_location_in_native;
495  int64 closest_distance_squared = -1;
496  internal::DisplayManager* display_manager = GetDisplayManager();
497
498  aura::RootWindow* dst_root_window = NULL;
499  for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
500    const gfx::Display& display = display_manager->GetDisplayAt(i);
501    const internal::DisplayInfo display_info =
502        display_manager->GetDisplayInfo(display.id());
503    aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id());
504    if (display_info.bounds_in_native().Contains(
505            cursor_location_in_native_coords_for_restore_)) {
506      dst_root_window = root_window;
507      target_location_in_native = cursor_location_in_native_coords_for_restore_;
508      break;
509    }
510    gfx::Point center = display.bounds().CenterPoint();
511    // Use the distance squared from the center of the dislay. This is not
512    // exactly "closest" display, but good enough to pick one
513    // appropriate (and there are at most two displays).
514    // We don't care about actual distance, only relative to other displays, so
515    // using the LengthSquared() is cheaper than Length().
516
517    int64 distance_squared = (center - point_in_screen).LengthSquared();
518    if (closest_distance_squared < 0 ||
519        closest_distance_squared > distance_squared) {
520      aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id());
521      aura::client::ScreenPositionClient* client =
522          aura::client::GetScreenPositionClient(root_window);
523      client->ConvertPointFromScreen(root_window, &center);
524      root_window->ConvertPointToNativeScreen(&center);
525      dst_root_window = root_window;
526      target_location_in_native = center;
527      closest_distance_squared = distance_squared;
528    }
529  }
530  dst_root_window->ConvertPointFromNativeScreen(&target_location_in_native);
531  dst_root_window->MoveCursorTo(target_location_in_native);
532}
533
534bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow(
535    const aura::Window* window,
536    const gfx::Insets& insets) {
537  const aura::RootWindow* root_window = window->GetRootWindow();
538  int64 id = internal::GetRootWindowSettings(root_window)->display_id;
539  // if id is |kInvaildDisplayID|, it's being deleted.
540  DCHECK(id != gfx::Display::kInvalidDisplayID);
541  return GetDisplayManager()->UpdateWorkAreaOfDisplay(id, insets);
542}
543
544const gfx::Display& DisplayController::GetDisplayNearestWindow(
545    const aura::Window* window) const {
546  if (!window)
547    return GetPrimaryDisplay();
548  const aura::RootWindow* root_window = window->GetRootWindow();
549  if (!root_window)
550    return GetPrimaryDisplay();
551  int64 id = internal::GetRootWindowSettings(root_window)->display_id;
552  // if id is |kInvaildDisplayID|, it's being deleted.
553  DCHECK(id != gfx::Display::kInvalidDisplayID);
554
555  internal::DisplayManager* display_manager = GetDisplayManager();
556  // RootWindow needs Display to determine its device scale factor.
557  // TODO(oshima): We don't need full display info for mirror
558  // window. Refactor so that RootWindow doesn't use it.
559  if (display_manager->mirrored_display().id() == id)
560    return display_manager->mirrored_display();
561
562  return display_manager->GetDisplayForId(id);
563}
564
565const gfx::Display& DisplayController::GetDisplayNearestPoint(
566    const gfx::Point& point) const {
567  // Fallback to the primary display if there is no root display containing
568  // the |point|.
569  const gfx::Display& display =
570      GetDisplayManager()->FindDisplayContainingPoint(point);
571  return display.is_valid() ? display : GetPrimaryDisplay();
572}
573
574const gfx::Display& DisplayController::GetDisplayMatching(
575    const gfx::Rect& rect) const {
576  if (rect.IsEmpty())
577    return GetDisplayNearestPoint(rect.origin());
578
579  int max_area = 0;
580  const gfx::Display* matching = NULL;
581  for (size_t i = 0; i < GetDisplayManager()->GetNumDisplays(); ++i) {
582    const gfx::Display& display = GetDisplayManager()->GetDisplayAt(i);
583    gfx::Rect intersect = gfx::IntersectRects(display.bounds(), rect);
584    int area = intersect.width() * intersect.height();
585    if (area > max_area) {
586      max_area = area;
587      matching = &display;
588    }
589  }
590  // Fallback to the primary display if there is no matching display.
591  return matching ? *matching : GetPrimaryDisplay();
592}
593
594void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) {
595  const internal::DisplayInfo& display_info =
596      GetDisplayManager()->GetDisplayInfo(display.id());
597  DCHECK(!display_info.bounds_in_native().IsEmpty());
598  aura::RootWindow* root = root_windows_[display.id()];
599  root->SetHostBounds(display_info.bounds_in_native());
600  SetDisplayPropertiesOnHostWindow(root, display);
601}
602
603void DisplayController::OnDisplayAdded(const gfx::Display& display) {
604  if (primary_root_window_for_replace_) {
605    DCHECK(root_windows_.empty());
606    primary_display_id = display.id();
607    root_windows_[display.id()] = primary_root_window_for_replace_;
608    internal::GetRootWindowSettings(primary_root_window_for_replace_)->
609        display_id = display.id();
610    primary_root_window_for_replace_ = NULL;
611    const internal::DisplayInfo& display_info =
612        GetDisplayManager()->GetDisplayInfo(display.id());
613    root_windows_[display.id()]->SetHostBounds(
614        display_info.bounds_in_native());
615  } else {
616    if (primary_display_id == gfx::Display::kInvalidDisplayID)
617      primary_display_id = display.id();
618    DCHECK(!root_windows_.empty());
619    aura::RootWindow* root = AddRootWindowForDisplay(display);
620    internal::RootWindowController::CreateForSecondaryDisplay(root);
621  }
622}
623
624void DisplayController::OnDisplayRemoved(const gfx::Display& display) {
625  aura::RootWindow* root_to_delete = root_windows_[display.id()];
626  DCHECK(root_to_delete) << display.ToString();
627
628  // Display for root window will be deleted when the Primary RootWindow
629  // is deleted by the Shell.
630  root_windows_.erase(display.id());
631
632  // When the primary root window's display is removed, move the primary
633  // root to the other display.
634  if (primary_display_id == display.id()) {
635    // Temporarily store the primary root window in
636    // |primary_root_window_for_replace_| when replacing the display.
637    if (root_windows_.size() == 0) {
638      primary_display_id = gfx::Display::kInvalidDisplayID;
639      primary_root_window_for_replace_ = root_to_delete;
640      return;
641    }
642    DCHECK_EQ(1U, root_windows_.size());
643    primary_display_id = ScreenAsh::GetSecondaryDisplay().id();
644    aura::RootWindow* primary_root = root_to_delete;
645
646    // Delete the other root instead.
647    root_to_delete = root_windows_[primary_display_id];
648    internal::GetRootWindowSettings(root_to_delete)->display_id = display.id();
649
650    // Setup primary root.
651    root_windows_[primary_display_id] = primary_root;
652    internal::GetRootWindowSettings(primary_root)->display_id =
653        primary_display_id;
654
655    OnDisplayBoundsChanged(
656        GetDisplayManager()->GetDisplayForId(primary_display_id));
657  }
658  internal::RootWindowController* controller =
659      internal::GetRootWindowController(root_to_delete);
660  DCHECK(controller);
661  controller->MoveWindowsTo(GetPrimaryRootWindow());
662  // Delete most of root window related objects, but don't delete
663  // root window itself yet because the stack may be using it.
664  controller->Shutdown();
665  base::MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
666}
667
668void DisplayController::OnRootWindowHostResized(const aura::RootWindow* root) {
669  internal::DisplayManager* display_manager = GetDisplayManager();
670  gfx::Display display = GetDisplayNearestWindow(root);
671  if (display_manager->UpdateDisplayBounds(
672          display.id(),
673          gfx::Rect(root->GetHostOrigin(), root->GetHostSize()))) {
674    mirror_window_controller_->UpdateWindow();
675  }
676}
677
678void DisplayController::CreateOrUpdateMirrorWindow(
679    const internal::DisplayInfo& info) {
680  mirror_window_controller_->UpdateWindow(info);
681}
682
683void DisplayController::CloseMirrorWindow() {
684  mirror_window_controller_->Close();
685}
686
687void DisplayController::PreDisplayConfigurationChange(bool display_removed) {
688  FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanging());
689  focus_activation_store_->Store(display_removed);
690
691  gfx::Point point_in_screen = Shell::GetScreen()->GetCursorScreenPoint();
692  gfx::Display display =
693      Shell::GetScreen()->GetDisplayNearestPoint(point_in_screen);
694  aura::RootWindow* root_window = GetRootWindowForDisplayId(display.id());
695
696  aura::client::ScreenPositionClient* client =
697      aura::client::GetScreenPositionClient(root_window);
698  client->ConvertPointFromScreen(root_window, &point_in_screen);
699  root_window->ConvertPointToNativeScreen(&point_in_screen);
700  cursor_location_in_native_coords_for_restore_ = point_in_screen;
701}
702
703void DisplayController::PostDisplayConfigurationChange() {
704  if (limiter_)
705    limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
706
707  focus_activation_store_->Restore();
708
709  internal::DisplayManager* display_manager = GetDisplayManager();
710  internal::DisplayLayoutStore* layout_store = display_manager->layout_store();
711  if (display_manager->num_connected_displays() > 1) {
712    DisplayIdPair pair = display_manager->GetCurrentDisplayIdPair();
713    layout_store->UpdateMirrorStatus(pair, display_manager->IsMirrored());
714    DisplayLayout layout = layout_store->GetRegisteredDisplayLayout(pair);
715
716    if (Shell::GetScreen()->GetNumDisplays() > 1 ) {
717      int64 primary_id = layout.primary_id;
718      SetPrimaryDisplayId(
719          primary_id == gfx::Display::kInvalidDisplayID ?
720          pair.first : primary_id);
721      // Update the primary_id in case the above call is
722      // ignored. Happens when a) default layout's primary id
723      // doesn't exist, or b) the primary_id has already been
724      // set to the same and didn't update it.
725      layout_store->UpdatePrimaryDisplayId(pair, GetPrimaryDisplay().id());
726    }
727  }
728  FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged());
729  UpdateHostWindowNames();
730  EnsurePointerInDisplays();
731}
732
733aura::RootWindow* DisplayController::AddRootWindowForDisplay(
734    const gfx::Display& display) {
735  static int root_window_count = 0;
736  const internal::DisplayInfo& display_info =
737      GetDisplayManager()->GetDisplayInfo(display.id());
738  const gfx::Rect& bounds_in_native = display_info.bounds_in_native();
739  aura::RootWindow::CreateParams params(bounds_in_native);
740  params.host = Shell::GetInstance()->root_window_host_factory()->
741      CreateRootWindowHost(bounds_in_native);
742  aura::RootWindow* root_window = new aura::RootWindow(params);
743  root_window->SetName(
744      base::StringPrintf("RootWindow-%d", root_window_count++));
745  root_window->compositor()->SetBackgroundColor(SK_ColorBLACK);
746  // No need to remove RootWindowObserver because
747  // the DisplayController object outlives RootWindow objects.
748  root_window->AddRootWindowObserver(this);
749  internal::InitRootWindowSettings(root_window)->display_id = display.id();
750  root_window->Init();
751
752  root_windows_[display.id()] = root_window;
753  SetDisplayPropertiesOnHostWindow(root_window, display);
754
755#if defined(OS_CHROMEOS)
756  static bool force_constrain_pointer_to_root =
757      CommandLine::ForCurrentProcess()->HasSwitch(
758          switches::kAshConstrainPointerToRoot);
759  if (base::SysInfo::IsRunningOnChromeOS() || force_constrain_pointer_to_root)
760    root_window->ConfineCursorToWindow();
761#endif
762  return root_window;
763}
764
765void DisplayController::OnFadeOutForSwapDisplayFinished() {
766#if defined(OS_CHROMEOS) && defined(USE_X11)
767  SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
768  Shell::GetInstance()->output_configurator_animation()->StartFadeInAnimation();
769#endif
770}
771
772void DisplayController::UpdateHostWindowNames() {
773#if defined(USE_X11)
774  // crbug.com/120229 - set the window title for the primary dislpay
775  // to "aura_root_0" so gtalk can find the primary root window to broadcast.
776  // TODO(jhorwich) Remove this once Chrome supports window-based broadcasting.
777  aura::RootWindow* primary = Shell::GetPrimaryRootWindow();
778  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
779  for (size_t i = 0; i < root_windows.size(); ++i) {
780    std::string name =
781        root_windows[i] == primary ? "aura_root_0" : "aura_root_x";
782    gfx::AcceleratedWidget xwindow = root_windows[i]->GetAcceleratedWidget();
783    XStoreName(gfx::GetXDisplay(), xwindow, name.c_str());
784  }
785#endif
786}
787
788}  // namespace ash
789