display_controller.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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_manager.h"
13#include "ash/display/display_pref_util.h"
14#include "ash/display/root_window_transformers.h"
15#include "ash/host/root_window_host_factory.h"
16#include "ash/root_window_controller.h"
17#include "ash/screen_ash.h"
18#include "ash/shell.h"
19#include "ash/wm/coordinate_conversion.h"
20#include "ash/wm/property_util.h"
21#include "ash/wm/window_util.h"
22#include "base/command_line.h"
23#include "base/json/json_value_converter.h"
24#include "base/strings/string_number_conversions.h"
25#include "base/strings/string_piece.h"
26#include "base/strings/stringprintf.h"
27#include "base/values.h"
28#include "third_party/skia/include/utils/SkMatrix44.h"
29#include "ui/aura/client/activation_client.h"
30#include "ui/aura/client/capture_client.h"
31#include "ui/aura/client/cursor_client.h"
32#include "ui/aura/client/focus_client.h"
33#include "ui/aura/client/screen_position_client.h"
34#include "ui/aura/env.h"
35#include "ui/aura/root_window.h"
36#include "ui/aura/root_window_transformer.h"
37#include "ui/aura/window.h"
38#include "ui/aura/window_property.h"
39#include "ui/aura/window_tracker.h"
40#include "ui/compositor/compositor.h"
41#include "ui/compositor/dip_util.h"
42#include "ui/gfx/display.h"
43#include "ui/gfx/screen.h"
44
45#if defined(OS_CHROMEOS)
46#include "base/chromeos/chromeos_version.h"
47#include "base/time.h"
48#if defined(USE_X11)
49#include "ash/display/output_configurator_animation.h"
50#include "chromeos/display/output_configurator.h"
51#include "ui/base/x/x11_util.h"
52
53// Including this at the bottom to avoid other
54// potential conflict with chrome headers.
55#include <X11/extensions/Xrandr.h>
56#undef RootWindow
57#endif  // defined(USE_X11)
58#endif  // defined(OS_CHROMEOS)
59
60namespace ash {
61namespace {
62
63// Primary display stored in global object as it can be
64// accessed after Shell is deleted. A separate display instance is created
65// during the shutdown instead of always keeping two display instances
66// (one here and another one in display_manager) in sync, which is error prone.
67int64 primary_display_id = gfx::Display::kInvalidDisplayID;
68gfx::Display* primary_display_for_shutdown = NULL;
69// Keeps the number of displays during the shutdown after
70// ash::Shell:: is deleted.
71int num_displays_for_shutdown = -1;
72
73// The maximum value for 'offset' in DisplayLayout in case of outliers.  Need
74// to change this value in case to support even larger displays.
75const int kMaxValidOffset = 10000;
76
77// The number of pixels to overlap between the primary and secondary displays,
78// in case that the offset value is too large.
79const int kMinimumOverlapForInvalidOffset = 100;
80
81// Specifies how long the display change should have been disabled
82// after each display change operations.
83// |kCycleDisplayThrottleTimeoutMs| is set to be longer to avoid
84// changing the settings while the system is still configurating
85// displays. It will be overriden by |kAfterDisplayChangeThrottleTimeoutMs|
86// when the display change happens, so the actual timeout is much shorter.
87const int64 kAfterDisplayChangeThrottleTimeoutMs = 500;
88const int64 kCycleDisplayThrottleTimeoutMs = 4000;
89const int64 kSwapDisplayThrottleTimeoutMs = 500;
90
91// Persistent key names
92const char kPositionKey[] = "position";
93const char kOffsetKey[] = "offset";
94const char kMirroredKey[] = "mirrored";
95const char kPrimaryIdKey[] = "primary-id";
96
97typedef std::map<DisplayLayout::Position, std::string> PositionToStringMap;
98
99const PositionToStringMap* GetPositionToStringMap() {
100  static const PositionToStringMap* map = CreateToStringMap(
101      DisplayLayout::TOP, "top",
102      DisplayLayout::BOTTOM, "bottom",
103      DisplayLayout::RIGHT, "right",
104      DisplayLayout::LEFT, "left");
105  return map;
106}
107
108bool GetPositionFromString(const base::StringPiece& position,
109                           DisplayLayout::Position* field) {
110  if (ReverseFind(GetPositionToStringMap(), position, field))
111    return true;
112  LOG(ERROR) << "Invalid position value:" << position;
113  return false;
114}
115
116std::string GetStringFromPosition(DisplayLayout::Position position) {
117  const PositionToStringMap* map = GetPositionToStringMap();
118  PositionToStringMap::const_iterator iter = map->find(position);
119  return iter != map->end() ? iter->second : std::string("unknown");
120}
121
122bool GetDisplayIdFromString(const base::StringPiece& position, int64* field) {
123  return base::StringToInt64(position, field);
124}
125
126internal::DisplayManager* GetDisplayManager() {
127  return Shell::GetInstance()->display_manager();
128}
129
130void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root,
131                                      const gfx::Display& display) {
132  internal::DisplayInfo info =
133      GetDisplayManager()->GetDisplayInfo(display.id());
134#if defined(OS_CHROMEOS) && defined(USE_X11)
135  // Native window property (Atom in X11) that specifies the display's
136  // rotation, scale factor and if it's internal display.  They are
137  // read and used by touchpad/mouse driver directly on X (contact
138  // adlr@ for more details on touchpad/mouse driver side). The value
139  // of the rotation is one of 0 (normal), 1 (90 degrees clockwise), 2
140  // (180 degree) or 3 (270 degrees clockwise).  The value of the
141  // scale factor is in percent (100, 140, 200 etc).
142  const char kRotationProp[] = "_CHROME_DISPLAY_ROTATION";
143  const char kScaleFactorProp[] = "_CHROME_DISPLAY_SCALE_FACTOR";
144  const char kInternalProp[] = "_CHROME_DISPLAY_INTERNAL";
145  const char kCARDINAL[] = "CARDINAL";
146  int xrandr_rotation = RR_Rotate_0;
147  switch (info.rotation()) {
148    case gfx::Display::ROTATE_0:
149      xrandr_rotation = RR_Rotate_0;
150      break;
151    case gfx::Display::ROTATE_90:
152      xrandr_rotation = RR_Rotate_90;
153      break;
154    case gfx::Display::ROTATE_180:
155      xrandr_rotation = RR_Rotate_180;
156      break;
157    case gfx::Display::ROTATE_270:
158      xrandr_rotation = RR_Rotate_270;
159      break;
160  }
161
162  int internal = display.IsInternal() ? 1 : 0;
163  gfx::AcceleratedWidget xwindow = root->GetAcceleratedWidget();
164  ui::SetIntProperty(xwindow, kInternalProp, kCARDINAL, internal);
165  ui::SetIntProperty(xwindow, kRotationProp, kCARDINAL, xrandr_rotation);
166  ui::SetIntProperty(xwindow,
167                     kScaleFactorProp,
168                     kCARDINAL,
169                     100 * display.device_scale_factor());
170#endif
171  scoped_ptr<aura::RootWindowTransformer> transformer(
172      internal::CreateRootWindowTransformerForDisplay(root, display));
173  root->SetRootWindowTransformer(transformer.Pass());
174}
175
176}  // namespace
177
178namespace internal {
179
180// A utility class to store/restore focused/active window
181// when the display configuration has changed.
182class FocusActivationStore {
183 public:
184  FocusActivationStore()
185      : activation_client_(NULL),
186        capture_client_(NULL),
187        focus_client_(NULL),
188        focused_(NULL),
189        active_(NULL) {
190  }
191
192  void Store() {
193    if (!activation_client_) {
194      aura::RootWindow* root = Shell::GetPrimaryRootWindow();
195      activation_client_ = aura::client::GetActivationClient(root);
196      capture_client_ = aura::client::GetCaptureClient(root);
197      focus_client_ = aura::client::GetFocusClient(root);
198    }
199    focused_ = focus_client_->GetFocusedWindow();
200    if (focused_)
201      tracker_.Add(focused_);
202    active_ = activation_client_->GetActiveWindow();
203    if (active_ && focused_ != active_)
204      tracker_.Add(active_);
205
206    // Deactivate the window to close menu / bubble windows.
207    activation_client_->DeactivateWindow(active_);
208    // Release capture if any.
209    capture_client_->SetCapture(NULL);
210    // Clear the focused window if any. This is necessary because a
211    // window may be deleted when losing focus (fullscreen flash for
212    // example).  If the focused window is still alive after move, it'll
213    // be re-focused below.
214    focus_client_->FocusWindow(NULL);
215  }
216
217  void Restore() {
218    // Restore focused or active window if it's still alive.
219    if (focused_ && tracker_.Contains(focused_)) {
220      focus_client_->FocusWindow(focused_);
221    } else if (active_ && tracker_.Contains(active_)) {
222      activation_client_->ActivateWindow(active_);
223    }
224    if (focused_)
225      tracker_.Remove(focused_);
226    if (active_)
227      tracker_.Remove(active_);
228    focused_ = NULL;
229    active_ = NULL;
230  }
231
232 private:
233  aura::client::ActivationClient* activation_client_;
234  aura::client::CaptureClient* capture_client_;
235  aura::client::FocusClient* focus_client_;
236  aura::WindowTracker tracker_;
237  aura::Window* focused_;
238  aura::Window* active_;
239
240  DISALLOW_COPY_AND_ASSIGN(FocusActivationStore);
241};
242
243}  // namespace internal
244
245////////////////////////////////////////////////////////////////////////////////
246// DisplayLayout
247
248// static
249DisplayLayout DisplayLayout::FromInts(int position, int offsets) {
250  return DisplayLayout(static_cast<Position>(position), offsets);
251}
252
253DisplayLayout::DisplayLayout()
254    : position(RIGHT),
255      offset(0),
256      mirrored(false),
257      primary_id(gfx::Display::kInvalidDisplayID) {
258}
259
260DisplayLayout::DisplayLayout(DisplayLayout::Position position, int offset)
261    : position(position),
262      offset(offset),
263      mirrored(false),
264      primary_id(gfx::Display::kInvalidDisplayID) {
265  DCHECK_LE(TOP, position);
266  DCHECK_GE(LEFT, position);
267
268  // Set the default value to |position| in case position is invalid.  DCHECKs
269  // above doesn't stop in Release builds.
270  if (TOP > position || LEFT < position)
271    this->position = RIGHT;
272
273  DCHECK_GE(kMaxValidOffset, abs(offset));
274}
275
276DisplayLayout DisplayLayout::Invert() const {
277  Position inverted_position = RIGHT;
278  switch (position) {
279    case TOP:
280      inverted_position = BOTTOM;
281      break;
282    case BOTTOM:
283      inverted_position = TOP;
284      break;
285    case RIGHT:
286      inverted_position = LEFT;
287      break;
288    case LEFT:
289      inverted_position = RIGHT;
290      break;
291  }
292  DisplayLayout ret = DisplayLayout(inverted_position, -offset);
293  ret.primary_id = primary_id;
294  return ret;
295}
296
297// static
298bool DisplayLayout::ConvertFromValue(const base::Value& value,
299                                     DisplayLayout* layout) {
300  base::JSONValueConverter<DisplayLayout> converter;
301  return converter.Convert(value, layout);
302}
303
304// static
305bool DisplayLayout::ConvertToValue(const DisplayLayout& layout,
306                                   base::Value* value) {
307  base::DictionaryValue* dict_value = NULL;
308  if (!value->GetAsDictionary(&dict_value) || dict_value == NULL)
309    return false;
310
311  const std::string position_str = GetStringFromPosition(layout.position);
312  dict_value->SetString(kPositionKey, position_str);
313  dict_value->SetInteger(kOffsetKey, layout.offset);
314  dict_value->SetBoolean(kMirroredKey, layout.mirrored);
315  dict_value->SetString(kPrimaryIdKey, base::Int64ToString(layout.primary_id));
316  return true;
317}
318
319std::string DisplayLayout::ToString() const {
320  const std::string position_str = GetStringFromPosition(position);
321  return base::StringPrintf(
322      "%s, %d%s",
323      position_str.c_str(), offset, mirrored ? ", mirrored" : "");
324}
325
326// static
327void DisplayLayout::RegisterJSONConverter(
328    base::JSONValueConverter<DisplayLayout>* converter) {
329  converter->RegisterCustomField<Position>(
330      kPositionKey, &DisplayLayout::position, &GetPositionFromString);
331  converter->RegisterIntField(kOffsetKey, &DisplayLayout::offset);
332  converter->RegisterBoolField(kMirroredKey, &DisplayLayout::mirrored);
333  converter->RegisterCustomField<int64>(
334      kPrimaryIdKey, &DisplayLayout::primary_id, &GetDisplayIdFromString);
335}
336
337////////////////////////////////////////////////////////////////////////////////
338// DisplayChangeLimiter
339
340DisplayController::DisplayChangeLimiter::DisplayChangeLimiter()
341    : throttle_timeout_(base::Time::Now()) {
342}
343
344void DisplayController::DisplayChangeLimiter::SetThrottleTimeout(
345    int64 throttle_ms) {
346  throttle_timeout_ =
347      base::Time::Now() + base::TimeDelta::FromMilliseconds(throttle_ms);
348}
349
350bool DisplayController::DisplayChangeLimiter::IsThrottled() const {
351  return base::Time::Now() < throttle_timeout_;
352}
353
354////////////////////////////////////////////////////////////////////////////////
355// DisplayController
356
357DisplayController::DisplayController()
358    : primary_root_window_for_replace_(NULL),
359      in_bootstrap_(true),
360      focus_activation_store_(new internal::FocusActivationStore()) {
361  CommandLine* command_line = CommandLine::ForCurrentProcess();
362#if defined(OS_CHROMEOS)
363  if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) &&
364      base::chromeos::IsRunningOnChromeOS())
365    limiter_.reset(new DisplayChangeLimiter);
366#endif
367  if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) {
368    std::string value = command_line->GetSwitchValueASCII(
369        switches::kAshSecondaryDisplayLayout);
370    char layout;
371    int offset = 0;
372    if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) {
373      if (layout == 't')
374        default_display_layout_.position = DisplayLayout::TOP;
375      else if (layout == 'b')
376        default_display_layout_.position = DisplayLayout::BOTTOM;
377      else if (layout == 'r')
378        default_display_layout_.position = DisplayLayout::RIGHT;
379      else if (layout == 'l')
380        default_display_layout_.position = DisplayLayout::LEFT;
381      default_display_layout_.offset = offset;
382    }
383  }
384  // Reset primary display to make sure that tests don't use
385  // stale display info from previous tests.
386  primary_display_id = gfx::Display::kInvalidDisplayID;
387  delete primary_display_for_shutdown;
388  primary_display_for_shutdown = NULL;
389  num_displays_for_shutdown = -1;
390}
391
392DisplayController::~DisplayController() {
393  DCHECK(primary_display_for_shutdown);
394}
395
396void DisplayController::Start() {
397  Shell::GetScreen()->AddObserver(this);
398  in_bootstrap_ = false;
399}
400
401void DisplayController::Shutdown() {
402  DCHECK(!primary_display_for_shutdown);
403  primary_display_for_shutdown = new gfx::Display(
404      GetDisplayManager()->GetDisplayForId(primary_display_id));
405  num_displays_for_shutdown = GetDisplayManager()->GetNumDisplays();
406
407  Shell::GetScreen()->RemoveObserver(this);
408  // Delete all root window controllers, which deletes root window
409  // from the last so that the primary root window gets deleted last.
410  for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it =
411           root_windows_.rbegin(); it != root_windows_.rend(); ++it) {
412    internal::RootWindowController* controller =
413        GetRootWindowController(it->second);
414    DCHECK(controller);
415    delete controller;
416  }
417}
418
419// static
420const gfx::Display& DisplayController::GetPrimaryDisplay() {
421  DCHECK_NE(primary_display_id, gfx::Display::kInvalidDisplayID);
422  if (primary_display_for_shutdown)
423    return *primary_display_for_shutdown;
424  return GetDisplayManager()->GetDisplayForId(primary_display_id);
425}
426
427// static
428int DisplayController::GetNumDisplays() {
429  if (num_displays_for_shutdown >= 0)
430    return num_displays_for_shutdown;
431  return GetDisplayManager()->GetNumDisplays();
432}
433
434// static
435bool DisplayController::HasPrimaryDisplay() {
436  return primary_display_id != gfx::Display::kInvalidDisplayID;
437}
438
439void DisplayController::InitPrimaryDisplay() {
440  const gfx::Display* primary_candidate =
441      GetDisplayManager()->GetPrimaryDisplayCandidate();
442  primary_display_id = primary_candidate->id();
443  AddRootWindowForDisplay(*primary_candidate);
444  UpdateDisplayBoundsForLayout();
445}
446
447void DisplayController::InitSecondaryDisplays() {
448  internal::DisplayManager* display_manager = GetDisplayManager();
449  for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
450    const gfx::Display* display = display_manager->GetDisplayAt(i);
451    if (primary_display_id != display->id()) {
452      aura::RootWindow* root = AddRootWindowForDisplay(*display);
453      Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root);
454    }
455  }
456  if (display_manager->GetNumDisplays() > 1) {
457    UpdateDisplayBoundsForLayout();
458    DisplayIdPair pair = GetCurrentDisplayIdPair();
459    DisplayLayout layout = GetCurrentDisplayLayout();
460    SetPrimaryDisplayId(
461        layout.primary_id == gfx::Display::kInvalidDisplayID ?
462        pair.first : layout.primary_id);
463  }
464}
465
466void DisplayController::AddObserver(Observer* observer) {
467  observers_.AddObserver(observer);
468}
469
470void DisplayController::RemoveObserver(Observer* observer) {
471  observers_.RemoveObserver(observer);
472}
473
474aura::RootWindow* DisplayController::GetPrimaryRootWindow() {
475  DCHECK(!root_windows_.empty());
476  return root_windows_[primary_display_id];
477}
478
479aura::RootWindow* DisplayController::GetRootWindowForDisplayId(int64 id) {
480  return root_windows_[id];
481}
482
483void DisplayController::CloseChildWindows() {
484  for (std::map<int64, aura::RootWindow*>::const_iterator it =
485           root_windows_.begin(); it != root_windows_.end(); ++it) {
486    aura::RootWindow* root_window = it->second;
487    internal::RootWindowController* controller =
488        GetRootWindowController(root_window);
489    if (controller) {
490      controller->CloseChildWindows();
491    } else {
492      while (!root_window->children().empty()) {
493        aura::Window* child = root_window->children()[0];
494        delete child;
495      }
496    }
497  }
498}
499
500std::vector<aura::RootWindow*> DisplayController::GetAllRootWindows() {
501  std::vector<aura::RootWindow*> windows;
502  for (std::map<int64, aura::RootWindow*>::const_iterator it =
503           root_windows_.begin(); it != root_windows_.end(); ++it) {
504    DCHECK(it->second);
505    if (GetRootWindowController(it->second))
506      windows.push_back(it->second);
507  }
508  return windows;
509}
510
511gfx::Insets DisplayController::GetOverscanInsets(int64 display_id) const {
512  return GetDisplayManager()->GetOverscanInsets(display_id);
513}
514
515void DisplayController::SetOverscanInsets(int64 display_id,
516                                          const gfx::Insets& insets_in_dip) {
517  GetDisplayManager()->SetOverscanInsets(display_id, insets_in_dip);
518}
519
520void DisplayController::ClearCustomOverscanInsets(int64 display_id) {
521  GetDisplayManager()->ClearCustomOverscanInsets(display_id);
522}
523
524std::vector<internal::RootWindowController*>
525DisplayController::GetAllRootWindowControllers() {
526  std::vector<internal::RootWindowController*> controllers;
527  for (std::map<int64, aura::RootWindow*>::const_iterator it =
528           root_windows_.begin(); it != root_windows_.end(); ++it) {
529    internal::RootWindowController* controller =
530        GetRootWindowController(it->second);
531    if (controller)
532      controllers.push_back(controller);
533  }
534  return controllers;
535}
536
537void DisplayController::SetDefaultDisplayLayout(const DisplayLayout& layout) {
538  CommandLine* command_line = CommandLine::ForCurrentProcess();
539  if (!command_line->HasSwitch(switches::kAshSecondaryDisplayLayout))
540    default_display_layout_ = layout;
541}
542
543void DisplayController::RegisterLayoutForDisplayIdPair(
544    int64 id1,
545    int64 id2,
546    const DisplayLayout& layout) {
547  RegisterLayoutForDisplayIdPairInternal(id1, id2, layout, true);
548}
549
550void DisplayController::RegisterLayoutForDisplayId(
551    int64 id,
552    const DisplayLayout& layout) {
553  int64 first_id = gfx::Display::InternalDisplayId();
554  if (first_id == gfx::Display::kInvalidDisplayID)
555    first_id = GetDisplayManager()->first_display_id();
556  // Caveat: This doesn't work if the machine booted with
557  // no display.
558  // Ignore if the layout was registered for the internal or
559  // 1st display.
560  if (first_id != id)
561    RegisterLayoutForDisplayIdPairInternal(first_id, id, layout, false);
562}
563
564void DisplayController::SetLayoutForCurrentDisplays(
565    const DisplayLayout& layout_relative_to_primary) {
566  DCHECK_EQ(2U, GetDisplayManager()->GetNumDisplays());
567  if (GetDisplayManager()->GetNumDisplays() < 2)
568    return;
569  const gfx::Display& primary = GetPrimaryDisplay();
570  const DisplayIdPair pair = GetCurrentDisplayIdPair();
571  // Invert if the primary was swapped.
572  DisplayLayout to_set = pair.first == primary.id() ?
573      layout_relative_to_primary : layout_relative_to_primary.Invert();
574
575  const DisplayLayout& current_layout = paired_layouts_[pair];
576  if (to_set.position != current_layout.position ||
577      to_set.offset != current_layout.offset) {
578    to_set.primary_id = primary.id();
579    paired_layouts_[pair] = to_set;
580    NotifyDisplayConfigurationChanging();
581    UpdateDisplayBoundsForLayout();
582    NotifyDisplayConfigurationChanged();
583  }
584}
585
586DisplayLayout DisplayController::GetCurrentDisplayLayout() const {
587  DCHECK_EQ(2U, GetDisplayManager()->num_connected_displays());
588  // Invert if the primary was swapped.
589  if (GetDisplayManager()->num_connected_displays() > 1) {
590    DisplayIdPair pair = GetCurrentDisplayIdPair();
591    DisplayLayout layout = GetRegisteredDisplayLayout(pair);
592    const gfx::Display& primary = GetPrimaryDisplay();
593    // Invert if the primary was swapped. If mirrored, first is always
594    // primary.
595    return pair.first == primary.id() ? layout : layout.Invert();
596  }
597  // On release build, just fallback to default instead of blowing up.
598  return default_display_layout_;
599}
600
601DisplayIdPair DisplayController::GetCurrentDisplayIdPair() const {
602  internal::DisplayManager* display_manager = GetDisplayManager();
603  const gfx::Display& primary = GetPrimaryDisplay();
604  if (display_manager->IsMirrored()) {
605    return std::make_pair(primary.id(),
606                          display_manager->mirrored_display().id());
607  }
608
609  const gfx::Display& secondary = ScreenAsh::GetSecondaryDisplay();
610  if (primary.IsInternal() ||
611      GetDisplayManager()->first_display_id() == primary.id()) {
612    return std::make_pair(primary.id(), secondary.id());
613  } else {
614    // Display has been Swapped.
615    return std::make_pair(secondary.id(), primary.id());
616  }
617}
618
619DisplayLayout DisplayController::GetRegisteredDisplayLayout(
620    const DisplayIdPair& pair) const {
621  std::map<DisplayIdPair, DisplayLayout>::const_iterator iter =
622      paired_layouts_.find(pair);
623  return iter != paired_layouts_.end() ? iter->second : default_display_layout_;
624}
625
626void DisplayController::ToggleMirrorMode() {
627  internal::DisplayManager* display_manager = GetDisplayManager();
628  if (display_manager->num_connected_displays() <= 1)
629    return;
630
631  if (limiter_) {
632    if  (limiter_->IsThrottled())
633      return;
634    limiter_->SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs);
635  }
636#if defined(OS_CHROMEOS) && defined(USE_X11)
637  Shell* shell = Shell::GetInstance();
638  internal::OutputConfiguratorAnimation* animation =
639      shell->output_configurator_animation();
640  animation->StartFadeOutAnimation(base::Bind(
641      base::IgnoreResult(&internal::DisplayManager::SetMirrorMode),
642      base::Unretained(display_manager),
643      !display_manager->IsMirrored()));
644#endif
645}
646
647void DisplayController::SwapPrimaryDisplay() {
648  if (limiter_) {
649    if  (limiter_->IsThrottled())
650      return;
651    limiter_->SetThrottleTimeout(kSwapDisplayThrottleTimeoutMs);
652  }
653
654  if (Shell::GetScreen()->GetNumDisplays() > 1) {
655#if defined(OS_CHROMEOS) && defined(USE_X11)
656    internal::OutputConfiguratorAnimation* animation =
657        Shell::GetInstance()->output_configurator_animation();
658    if (animation) {
659      animation->StartFadeOutAnimation(base::Bind(
660          &DisplayController::OnFadeOutForSwapDisplayFinished,
661          base::Unretained(this)));
662    } else {
663      SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
664    }
665#else
666    SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
667#endif
668  }
669}
670
671void DisplayController::SetPrimaryDisplayId(int64 id) {
672  DCHECK_NE(gfx::Display::kInvalidDisplayID, id);
673  if (id == gfx::Display::kInvalidDisplayID || primary_display_id == id)
674    return;
675
676  const gfx::Display& display = GetDisplayManager()->GetDisplayForId(id);
677  if (display.is_valid())
678    SetPrimaryDisplay(display);
679}
680
681void DisplayController::SetPrimaryDisplay(
682    const gfx::Display& new_primary_display) {
683  internal::DisplayManager* display_manager = GetDisplayManager();
684  DCHECK(new_primary_display.is_valid());
685  DCHECK(display_manager->IsActiveDisplay(new_primary_display));
686
687  if (!new_primary_display.is_valid() ||
688      !display_manager->IsActiveDisplay(new_primary_display)) {
689    LOG(ERROR) << "Invalid or non-existent display is requested:"
690               << new_primary_display.ToString();
691    return;
692  }
693
694  if (primary_display_id == new_primary_display.id() ||
695      root_windows_.size() < 2) {
696    return;
697  }
698
699  aura::RootWindow* non_primary_root = root_windows_[new_primary_display.id()];
700  LOG_IF(ERROR, !non_primary_root)
701      << "Unknown display is requested in SetPrimaryDisplay: id="
702      << new_primary_display.id();
703  if (!non_primary_root)
704    return;
705
706  gfx::Display old_primary_display = GetPrimaryDisplay();
707
708  // Swap root windows between current and new primary display.
709  aura::RootWindow* primary_root = root_windows_[primary_display_id];
710  DCHECK(primary_root);
711  DCHECK_NE(primary_root, non_primary_root);
712
713  root_windows_[new_primary_display.id()] = primary_root;
714  primary_root->SetProperty(internal::kDisplayIdKey, new_primary_display.id());
715
716  root_windows_[old_primary_display.id()] = non_primary_root;
717  non_primary_root->SetProperty(internal::kDisplayIdKey,
718                                old_primary_display.id());
719
720  primary_display_id = new_primary_display.id();
721  paired_layouts_[GetCurrentDisplayIdPair()].primary_id = primary_display_id;
722
723  display_manager->UpdateWorkAreaOfDisplayNearestWindow(
724      primary_root, old_primary_display.GetWorkAreaInsets());
725  display_manager->UpdateWorkAreaOfDisplayNearestWindow(
726      non_primary_root, new_primary_display.GetWorkAreaInsets());
727
728  // Update the dispay manager with new display info.
729  std::vector<internal::DisplayInfo> display_info_list;
730  display_info_list.push_back(display_manager->GetDisplayInfo(
731      primary_display_id));
732  display_info_list.push_back(display_manager->GetDisplayInfo(
733      GetSecondaryDisplay()->id()));
734  GetDisplayManager()->set_force_bounds_changed(true);
735  GetDisplayManager()->UpdateDisplays(display_info_list);
736  GetDisplayManager()->set_force_bounds_changed(false);
737}
738
739gfx::Display* DisplayController::GetSecondaryDisplay() {
740  internal::DisplayManager* display_manager = GetDisplayManager();
741  CHECK_EQ(2U, display_manager->GetNumDisplays());
742  return display_manager->GetDisplayAt(0)->id() == primary_display_id ?
743      display_manager->GetDisplayAt(1) : display_manager->GetDisplayAt(0);
744}
745
746void DisplayController::EnsurePointerInDisplays() {
747  // Don't try to move the pointer during the boot/startup.
748  if (!HasPrimaryDisplay())
749    return;
750  gfx::Point location_in_screen = Shell::GetScreen()->GetCursorScreenPoint();
751  gfx::Point target_location;
752  int64 closest_distance_squared = -1;
753  internal::DisplayManager* display_manager = GetDisplayManager();
754
755  aura::RootWindow* dst_root_window = NULL;
756  for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
757    const gfx::Display* display = display_manager->GetDisplayAt(i);
758    aura::RootWindow* root_window = GetRootWindowForDisplayId(display->id());
759    if (display->bounds().Contains(location_in_screen)) {
760      dst_root_window = root_window;
761      target_location = location_in_screen;
762      break;
763    }
764    gfx::Point center = display->bounds().CenterPoint();
765    // Use the distance squared from the center of the dislay. This is not
766    // exactly "closest" display, but good enough to pick one
767    // appropriate (and there are at most two displays).
768    // We don't care about actual distance, only relative to other displays, so
769    // using the LengthSquared() is cheaper than Length().
770
771    int64 distance_squared = (center - location_in_screen).LengthSquared();
772    if (closest_distance_squared < 0 ||
773        closest_distance_squared > distance_squared) {
774      dst_root_window = root_window;
775      target_location = center;
776      closest_distance_squared = distance_squared;
777    }
778  }
779  DCHECK(dst_root_window);
780  aura::client::ScreenPositionClient* client =
781      aura::client::GetScreenPositionClient(dst_root_window);
782  client->ConvertPointFromScreen(dst_root_window, &target_location);
783  dst_root_window->MoveCursorTo(target_location);
784}
785
786gfx::Point DisplayController::GetNativeMouseCursorLocation() const {
787  if (in_bootstrap())
788    return gfx::Point();
789
790  gfx::Point location = Shell::GetScreen()->GetCursorScreenPoint();
791  const gfx::Display& display =
792      Shell::GetScreen()->GetDisplayNearestPoint(location);
793  const aura::RootWindow* root_window =
794      root_windows_.find(display.id())->second;
795  aura::client::ScreenPositionClient* client =
796      aura::client::GetScreenPositionClient(root_window);
797  client->ConvertPointFromScreen(root_window, &location);
798  root_window->ConvertPointToNativeScreen(&location);
799  return location;
800}
801
802void DisplayController::UpdateMouseCursor(const gfx::Point& point_in_native) {
803  if (in_bootstrap())
804    return;
805
806  std::vector<aura::RootWindow*> root_windows = GetAllRootWindows();
807  for (std::vector<aura::RootWindow*>::iterator iter = root_windows.begin();
808       iter != root_windows.end();
809       ++iter) {
810    aura::RootWindow* root_window = *iter;
811    gfx::Rect bounds_in_native(root_window->GetHostOrigin(),
812                               root_window->GetHostSize());
813    if (bounds_in_native.Contains(point_in_native)) {
814      gfx::Point point(point_in_native);
815      root_window->ConvertPointFromNativeScreen(&point);
816      root_window->MoveCursorTo(point);
817      break;
818    }
819  }
820}
821
822void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) {
823  if (limiter_)
824    limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
825  const internal::DisplayInfo& display_info =
826      GetDisplayManager()->GetDisplayInfo(display.id());
827  DCHECK(!display_info.bounds_in_pixel().IsEmpty());
828
829  UpdateDisplayBoundsForLayout();
830  aura::RootWindow* root = root_windows_[display.id()];
831  SetDisplayPropertiesOnHostWindow(root, display);
832  root->SetHostBounds(display_info.bounds_in_pixel());
833}
834
835void DisplayController::OnDisplayAdded(const gfx::Display& display) {
836  if (limiter_)
837    limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
838
839  if (primary_root_window_for_replace_) {
840    DCHECK(root_windows_.empty());
841    primary_display_id = display.id();
842    root_windows_[display.id()] = primary_root_window_for_replace_;
843    primary_root_window_for_replace_->SetProperty(
844        internal::kDisplayIdKey, display.id());
845    primary_root_window_for_replace_ = NULL;
846    UpdateDisplayBoundsForLayout();
847    const internal::DisplayInfo& display_info =
848        GetDisplayManager()->GetDisplayInfo(display.id());
849    root_windows_[display.id()]->SetHostBounds(
850        display_info.bounds_in_pixel());
851  } else {
852    if (primary_display_id == gfx::Display::kInvalidDisplayID)
853      primary_display_id = display.id();
854    DCHECK(!root_windows_.empty());
855    aura::RootWindow* root = AddRootWindowForDisplay(display);
856    UpdateDisplayBoundsForLayout();
857    Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root);
858  }
859}
860
861void DisplayController::OnDisplayRemoved(const gfx::Display& display) {
862  if (limiter_)
863    limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
864
865  aura::RootWindow* root_to_delete = root_windows_[display.id()];
866  DCHECK(root_to_delete) << display.ToString();
867
868  // Display for root window will be deleted when the Primary RootWindow
869  // is deleted by the Shell.
870  root_windows_.erase(display.id());
871
872  // When the primary root window's display is removed, move the primary
873  // root to the other display.
874  if (primary_display_id == display.id()) {
875    // Temporarily store the primary root window in
876    // |primary_root_window_for_replace_| when replacing the display.
877    if (root_windows_.size() == 0) {
878      primary_display_id = gfx::Display::kInvalidDisplayID;
879      primary_root_window_for_replace_ = root_to_delete;
880      return;
881    }
882    DCHECK_EQ(1U, root_windows_.size());
883    primary_display_id = GetSecondaryDisplay()->id();
884    aura::RootWindow* primary_root = root_to_delete;
885
886    // Delete the other root instead.
887    root_to_delete = root_windows_[primary_display_id];
888    root_to_delete->SetProperty(internal::kDisplayIdKey, display.id());
889
890    // Setup primary root.
891    root_windows_[primary_display_id] = primary_root;
892    primary_root->SetProperty(internal::kDisplayIdKey, primary_display_id);
893
894    OnDisplayBoundsChanged(
895        GetDisplayManager()->GetDisplayForId(primary_display_id));
896  }
897  internal::RootWindowController* controller =
898      GetRootWindowController(root_to_delete);
899  DCHECK(controller);
900  controller->MoveWindowsTo(GetPrimaryRootWindow());
901  // Delete most of root window related objects, but don't delete
902  // root window itself yet because the stack may be using it.
903  controller->Shutdown();
904  base::MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
905}
906
907aura::RootWindow* DisplayController::AddRootWindowForDisplay(
908    const gfx::Display& display) {
909  static int root_window_count = 0;
910  const internal::DisplayInfo& display_info =
911      GetDisplayManager()->GetDisplayInfo(display.id());
912  const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel();
913  aura::RootWindow::CreateParams params(bounds_in_pixel);
914  params.host = Shell::GetInstance()->root_window_host_factory()->
915      CreateRootWindowHost(bounds_in_pixel);
916  aura::RootWindow* root_window = new aura::RootWindow(params);
917  root_window->SetName(
918      base::StringPrintf("RootWindow-%d", root_window_count++));
919  root_window->compositor()->SetBackgroundColor(SK_ColorBLACK);
920  // No need to remove RootWindowObserver because
921  // the DisplayManager object outlives RootWindow objects.
922  root_window->AddRootWindowObserver(GetDisplayManager());
923  root_window->SetProperty(internal::kDisplayIdKey, display.id());
924  root_window->Init();
925
926  root_windows_[display.id()] = root_window;
927  SetDisplayPropertiesOnHostWindow(root_window, display);
928
929#if defined(OS_CHROMEOS)
930  static bool force_constrain_pointer_to_root =
931      CommandLine::ForCurrentProcess()->HasSwitch(
932          switches::kAshConstrainPointerToRoot);
933  if (base::chromeos::IsRunningOnChromeOS() || force_constrain_pointer_to_root)
934    root_window->ConfineCursorToWindow();
935#endif
936  return root_window;
937}
938
939void DisplayController::UpdateDisplayBoundsForLayout() {
940  if (Shell::GetScreen()->GetNumDisplays() < 2 ||
941      GetDisplayManager()->num_connected_displays() < 2) {
942    return;
943  }
944
945  DCHECK_EQ(2, Shell::GetScreen()->GetNumDisplays());
946  const gfx::Rect& primary_bounds = GetPrimaryDisplay().bounds();
947
948  gfx::Display* secondary_display = GetSecondaryDisplay();
949  const gfx::Rect& secondary_bounds = secondary_display->bounds();
950  gfx::Point new_secondary_origin = primary_bounds.origin();
951
952  const DisplayLayout layout = GetCurrentDisplayLayout();
953  DisplayLayout::Position position = layout.position;
954
955  // Ignore the offset in case the secondary display doesn't share edges with
956  // the primary display.
957  int offset = layout.offset;
958  if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
959    offset = std::min(
960        offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
961    offset = std::max(
962        offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
963  } else {
964    offset = std::min(
965        offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
966    offset = std::max(
967        offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
968  }
969  switch (position) {
970    case DisplayLayout::TOP:
971      new_secondary_origin.Offset(offset, -secondary_bounds.height());
972      break;
973    case DisplayLayout::RIGHT:
974      new_secondary_origin.Offset(primary_bounds.width(), offset);
975      break;
976    case DisplayLayout::BOTTOM:
977      new_secondary_origin.Offset(offset, primary_bounds.height());
978      break;
979    case DisplayLayout::LEFT:
980      new_secondary_origin.Offset(-secondary_bounds.width(), offset);
981      break;
982  }
983  gfx::Insets insets = secondary_display->GetWorkAreaInsets();
984  secondary_display->set_bounds(
985      gfx::Rect(new_secondary_origin, secondary_bounds.size()));
986  secondary_display->UpdateWorkAreaFromInsets(insets);
987}
988
989void DisplayController::NotifyDisplayConfigurationChanging() {
990  if (in_bootstrap())
991    return;
992  FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanging());
993  focus_activation_store_->Store();
994}
995
996void DisplayController::NotifyDisplayConfigurationChanged() {
997  if (in_bootstrap())
998    return;
999  focus_activation_store_->Restore();
1000
1001  internal::DisplayManager* display_manager = GetDisplayManager();
1002  if (display_manager->num_connected_displays() > 1) {
1003    DisplayIdPair pair = GetCurrentDisplayIdPair();
1004    if (paired_layouts_.find(pair) == paired_layouts_.end())
1005      paired_layouts_[pair] = default_display_layout_;
1006    paired_layouts_[pair].mirrored = display_manager->IsMirrored();
1007    if (Shell::GetScreen()->GetNumDisplays() > 1 ) {
1008      int64 primary_id = paired_layouts_[pair].primary_id;
1009      SetPrimaryDisplayId(
1010          primary_id == gfx::Display::kInvalidDisplayID ?
1011          pair.first : primary_id);
1012      // Update the primary_id in case the above call is
1013      // ignored. Happens when a) default layout's primary id
1014      // doesn't exist, or b) the primary_id has already been
1015      // set to the same and didn't update it.
1016      paired_layouts_[pair].primary_id = GetPrimaryDisplay().id();
1017    }
1018  }
1019  FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged());
1020}
1021
1022void DisplayController::RegisterLayoutForDisplayIdPairInternal(
1023    int64 id1,
1024    int64 id2,
1025    const DisplayLayout& layout,
1026    bool override) {
1027  DisplayIdPair pair = std::make_pair(id1, id2);
1028  if (override || paired_layouts_.find(pair) == paired_layouts_.end())
1029    paired_layouts_[pair] = layout;
1030}
1031
1032void DisplayController::OnFadeOutForSwapDisplayFinished() {
1033#if defined(OS_CHROMEOS) && defined(USE_X11)
1034  SetPrimaryDisplay(ScreenAsh::GetSecondaryDisplay());
1035  Shell::GetInstance()->output_configurator_animation()->StartFadeInAnimation();
1036#endif
1037}
1038
1039}  // namespace ash
1040