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