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