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