display_manager.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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_manager.h"
6
7#include <cmath>
8#include <set>
9#include <string>
10#include <vector>
11
12#include "ash/ash_switches.h"
13#include "ash/display/display_controller.h"
14#include "ash/display/mirror_window_controller.h"
15#include "ash/screen_ash.h"
16#include "ash/shell.h"
17#include "base/auto_reset.h"
18#include "base/command_line.h"
19#include "base/logging.h"
20#include "base/stl_util.h"
21#include "base/strings/string_number_conversions.h"
22#include "base/strings/string_split.h"
23#include "base/strings/stringprintf.h"
24#include "base/strings/utf_string_conversions.h"
25#include "grit/ash_strings.h"
26#include "ui/aura/client/screen_position_client.h"
27#include "ui/aura/env.h"
28#include "ui/aura/root_window.h"
29#include "ui/aura/root_window_host.h"
30#include "ui/aura/window_property.h"
31#include "ui/base/l10n/l10n_util.h"
32#include "ui/gfx/display.h"
33#include "ui/gfx/rect.h"
34#include "ui/gfx/screen.h"
35#include "ui/gfx/size_conversions.h"
36
37#if defined(USE_X11)
38#include "ui/base/x/x11_util.h"
39#endif
40
41#if defined(OS_CHROMEOS)
42#include "ash/display/output_configurator_animation.h"
43#include "base/chromeos/chromeos_version.h"
44#include "chromeos/display/output_configurator.h"
45#endif
46
47#if defined(OS_WIN)
48#include "base/win/windows_version.h"
49#include "ui/aura/remote_root_window_host_win.h"
50#endif
51
52DECLARE_WINDOW_PROPERTY_TYPE(int64);
53
54namespace ash {
55namespace internal {
56typedef std::vector<gfx::Display> DisplayList;
57typedef std::vector<DisplayInfo> DisplayInfoList;
58
59namespace {
60
61// The number of pixels to overlap between the primary and secondary displays,
62// in case that the offset value is too large.
63const int kMinimumOverlapForInvalidOffset = 100;
64
65// List of value UI Scale values. Scales for 2x are equivalent to 640,
66// 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
67// 2560 pixel width 2x density display. Please see crbug.com/233375
68// for the full list of resolutions.
69const float kUIScalesFor2x[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f};
70const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f };
71const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f };
72
73struct DisplaySortFunctor {
74  bool operator()(const gfx::Display& a, const gfx::Display& b) {
75    return a.id() < b.id();
76  }
77};
78
79struct DisplayInfoSortFunctor {
80  bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
81    return a.id() < b.id();
82  }
83};
84
85struct ScaleComparator {
86  ScaleComparator(float s) : scale(s) {}
87
88  bool operator()(float s) const {
89    const float kEpsilon = 0.0001f;
90    return std::abs(scale - s) < kEpsilon;
91  }
92  float scale;
93};
94
95gfx::Display& GetInvalidDisplay() {
96  static gfx::Display* invalid_display = new gfx::Display();
97  return *invalid_display;
98}
99
100// Scoped objects used to either create or close the mirror window
101// at specific timing.
102class MirrorWindowCreator {
103 public:
104  explicit MirrorWindowCreator(const DisplayInfo& display_info)
105      : display_info_(display_info) {
106  }
107
108  virtual ~MirrorWindowCreator() {
109    Shell::GetInstance()->mirror_window_controller()->
110        UpdateWindow(display_info_);
111  }
112
113 private:
114  const DisplayInfo display_info_;
115  DISALLOW_COPY_AND_ASSIGN(MirrorWindowCreator);
116};
117
118class MirrorWindowCloser {
119 public:
120  MirrorWindowCloser() {}
121  virtual ~MirrorWindowCloser() {
122    Shell::GetInstance()->mirror_window_controller()->Close();
123  }
124
125 private:
126  DISALLOW_COPY_AND_ASSIGN(MirrorWindowCloser);
127};
128
129}  // namespace
130
131using aura::RootWindow;
132using aura::Window;
133using std::string;
134using std::vector;
135
136DEFINE_WINDOW_PROPERTY_KEY(int64, kDisplayIdKey,
137                           gfx::Display::kInvalidDisplayID);
138
139DisplayManager::DisplayManager()
140    : first_display_id_(gfx::Display::kInvalidDisplayID),
141      num_connected_displays_(0),
142      force_bounds_changed_(false),
143      change_display_upon_host_resize_(false),
144      software_mirroring_enabled_(false) {
145#if defined(OS_CHROMEOS)
146  change_display_upon_host_resize_ = !base::chromeos::IsRunningOnChromeOS();
147#endif
148  Init();
149}
150
151DisplayManager::~DisplayManager() {
152}
153
154// static
155std::vector<float> DisplayManager::GetScalesForDisplay(
156    const DisplayInfo& info) {
157  std::vector<float> ret;
158  if (info.device_scale_factor() == 2.0f) {
159    ret.assign(kUIScalesFor2x, kUIScalesFor2x + arraysize(kUIScalesFor2x));
160    return ret;
161  }
162  switch (info.bounds_in_pixel().width()) {
163    case 1280:
164      ret.assign(kUIScalesFor1280,
165                 kUIScalesFor1280 + arraysize(kUIScalesFor1280));
166      break;
167    case 1366:
168      ret.assign(kUIScalesFor1366,
169                 kUIScalesFor1366 + arraysize(kUIScalesFor1366));
170      break;
171    default:
172      ret.assign(kUIScalesFor1280,
173                 kUIScalesFor1280 + arraysize(kUIScalesFor1280));
174#if defined(OS_CHROMEOS)
175      if (base::chromeos::IsRunningOnChromeOS())
176        NOTREACHED() << "Unknown resolution:" << info.ToString();
177#endif
178  }
179  return ret;
180}
181
182// static
183float DisplayManager::GetNextUIScale(const DisplayInfo& info, bool up) {
184  float scale = info.ui_scale();
185  std::vector<float> scales = GetScalesForDisplay(info);
186  for (size_t i = 0; i < scales.size(); ++i) {
187    if (ScaleComparator(scales[i])(scale)) {
188      if (up && i != scales.size() - 1)
189        return scales[i + 1];
190      if (!up && i != 0)
191        return scales[i - 1];
192      return scales[i];
193    }
194  }
195  // Fallback to 1.0f if the |scale| wasn't in the list.
196  return 1.0f;
197}
198
199void DisplayManager::UpdateDisplayBoundsForLayout(
200    const DisplayLayout& layout,
201    const gfx::Display& primary_display,
202    gfx::Display* secondary_display) {
203  DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
204
205  const gfx::Rect& primary_bounds = primary_display.bounds();
206  DisplayController::GetPrimaryDisplay().bounds();
207
208  const gfx::Rect& secondary_bounds = secondary_display->bounds();
209  gfx::Point new_secondary_origin = primary_bounds.origin();
210
211  DisplayLayout::Position position = layout.position;
212
213  // Ignore the offset in case the secondary display doesn't share edges with
214  // the primary display.
215  int offset = layout.offset;
216  if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
217    offset = std::min(
218        offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
219    offset = std::max(
220        offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
221  } else {
222    offset = std::min(
223        offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
224    offset = std::max(
225        offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
226  }
227  switch (position) {
228    case DisplayLayout::TOP:
229      new_secondary_origin.Offset(offset, -secondary_bounds.height());
230      break;
231    case DisplayLayout::RIGHT:
232      new_secondary_origin.Offset(primary_bounds.width(), offset);
233      break;
234    case DisplayLayout::BOTTOM:
235      new_secondary_origin.Offset(offset, primary_bounds.height());
236      break;
237    case DisplayLayout::LEFT:
238      new_secondary_origin.Offset(-secondary_bounds.width(), offset);
239      break;
240  }
241  gfx::Insets insets = secondary_display->GetWorkAreaInsets();
242  secondary_display->set_bounds(
243      gfx::Rect(new_secondary_origin, secondary_bounds.size()));
244  secondary_display->UpdateWorkAreaFromInsets(insets);
245}
246
247bool DisplayManager::IsActiveDisplay(const gfx::Display& display) const {
248  for (DisplayList::const_iterator iter = displays_.begin();
249       iter != displays_.end(); ++iter) {
250    if ((*iter).id() == display.id())
251      return true;
252  }
253  return false;
254}
255
256bool DisplayManager::HasInternalDisplay() const {
257  return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID;
258}
259
260bool DisplayManager::IsInternalDisplayId(int64 id) const {
261  return gfx::Display::InternalDisplayId() == id;
262}
263
264bool DisplayManager::UpdateWorkAreaOfDisplayNearestWindow(
265    const aura::Window* window,
266    const gfx::Insets& insets) {
267  const RootWindow* root = window->GetRootWindow();
268  gfx::Display& display = FindDisplayForRootWindow(root);
269  gfx::Rect old_work_area = display.work_area();
270  display.UpdateWorkAreaFromInsets(insets);
271  return old_work_area != display.work_area();
272}
273
274const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
275  return const_cast<DisplayManager*>(this)->FindDisplayForId(id);
276}
277
278const gfx::Display& DisplayManager::FindDisplayContainingPoint(
279    const gfx::Point& point_in_screen) const {
280  for (DisplayList::const_iterator iter = displays_.begin();
281       iter != displays_.end(); ++iter) {
282    const gfx::Display& display = *iter;
283    if (display.bounds().Contains(point_in_screen))
284      return display;
285  }
286  return GetInvalidDisplay();
287}
288
289void DisplayManager::SetOverscanInsets(int64 display_id,
290                                       const gfx::Insets& insets_in_dip) {
291  display_info_[display_id].SetOverscanInsets(insets_in_dip);
292  DisplayInfoList display_info_list;
293  for (DisplayList::const_iterator iter = displays_.begin();
294       iter != displays_.end(); ++iter) {
295    display_info_list.push_back(GetDisplayInfo(iter->id()));
296  }
297  AddMirrorDisplayInfoIfAny(&display_info_list);
298  UpdateDisplays(display_info_list);
299}
300
301void DisplayManager::SetDisplayRotation(int64 display_id,
302                                        gfx::Display::Rotation rotation) {
303  if (!IsDisplayRotationEnabled())
304    return;
305  DisplayInfoList display_info_list;
306  for (DisplayList::const_iterator iter = displays_.begin();
307       iter != displays_.end(); ++iter) {
308    DisplayInfo info = GetDisplayInfo(iter->id());
309    if (info.id() == display_id) {
310      if (info.rotation() == rotation)
311        return;
312      info.set_rotation(rotation);
313    }
314    display_info_list.push_back(info);
315  }
316  AddMirrorDisplayInfoIfAny(&display_info_list);
317  UpdateDisplays(display_info_list);
318}
319
320void DisplayManager::SetDisplayUIScale(int64 display_id,
321                                       float ui_scale) {
322  if (!IsDisplayUIScalingEnabled() ||
323      gfx::Display::InternalDisplayId() != display_id) {
324    return;
325  }
326
327  DisplayInfoList display_info_list;
328  for (DisplayList::const_iterator iter = displays_.begin();
329       iter != displays_.end(); ++iter) {
330    DisplayInfo info = GetDisplayInfo(iter->id());
331    if (info.id() == display_id) {
332      if (info.ui_scale() == ui_scale)
333        return;
334      std::vector<float> scales = GetScalesForDisplay(info);
335      ScaleComparator comparator(ui_scale);
336      if (std::find_if(scales.begin(), scales.end(), comparator) ==
337          scales.end()) {
338        return;
339      }
340      info.set_ui_scale(ui_scale);
341    }
342    display_info_list.push_back(info);
343  }
344  AddMirrorDisplayInfoIfAny(&display_info_list);
345  UpdateDisplays(display_info_list);
346}
347
348void DisplayManager::RegisterDisplayProperty(
349    int64 display_id,
350    gfx::Display::Rotation rotation,
351    float ui_scale,
352    const gfx::Insets* overscan_insets) {
353  if (display_info_.find(display_id) == display_info_.end()) {
354    display_info_[display_id] =
355        DisplayInfo(display_id, std::string(""), false);
356  }
357
358  display_info_[display_id].set_rotation(rotation);
359  // Just in case the preference file was corrupted.
360  if (0.5f <= ui_scale && ui_scale <= 2.0f)
361    display_info_[display_id].set_ui_scale(ui_scale);
362  if (overscan_insets)
363    display_info_[display_id].SetOverscanInsets(*overscan_insets);
364}
365
366bool DisplayManager::IsDisplayRotationEnabled() const {
367  static bool enabled = !CommandLine::ForCurrentProcess()->
368      HasSwitch(switches::kAshDisableDisplayRotation);
369  return enabled;
370}
371
372bool DisplayManager::IsDisplayUIScalingEnabled() const {
373  static bool enabled = !CommandLine::ForCurrentProcess()->
374      HasSwitch(switches::kAshDisableUIScaling);
375  if (!enabled)
376    return false;
377  return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
378}
379
380gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
381  std::map<int64, DisplayInfo>::const_iterator it =
382      display_info_.find(display_id);
383  return (it != display_info_.end()) ?
384      it->second.overscan_insets_in_dip() : gfx::Insets();
385}
386
387void DisplayManager::OnNativeDisplaysChanged(
388    const std::vector<DisplayInfo>& updated_displays) {
389  if (updated_displays.empty()) {
390    // Don't update the displays when all displays are disconnected.
391    // This happens when:
392    // - the device is idle and powerd requested to turn off all displays.
393    // - the device is suspended. (kernel turns off all displays)
394    // - the internal display's brightness is set to 0 and no external
395    //   display is connected.
396    // - the internal display's brightness is 0 and external display is
397    //   disconnected.
398    // The display will be updated when one of displays is turned on, and the
399    // display list will be updated correctly.
400    return;
401  }
402  first_display_id_ = updated_displays[0].id();
403  std::set<int> y_coords;
404  if (updated_displays.size() == 1) {
405    VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
406  } else {
407    VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
408            << ") [0]=" << updated_displays[0].ToString()
409            << ", [1]=" << updated_displays[1].ToString();
410  }
411
412  bool internal_display_connected = false;
413  num_connected_displays_ = updated_displays.size();
414  mirrored_display_ = gfx::Display();
415  DisplayInfoList new_display_info_list;
416  for (DisplayInfoList::const_iterator iter = updated_displays.begin();
417       iter != updated_displays.end();
418       ++iter) {
419    if (!internal_display_connected)
420      internal_display_connected = IsInternalDisplayId(iter->id());
421    // Mirrored monitors have the same y coordinates.
422    int y = iter->bounds_in_pixel().y();
423    if (y_coords.find(y) != y_coords.end()) {
424      InsertAndUpdateDisplayInfo(*iter);
425      mirrored_display_ = CreateDisplayFromDisplayInfoById(iter->id());
426    } else {
427      y_coords.insert(y);
428      new_display_info_list.push_back(*iter);
429    }
430  }
431  if (HasInternalDisplay() &&
432      !internal_display_connected &&
433      display_info_.find(gfx::Display::InternalDisplayId()) ==
434      display_info_.end()) {
435    DisplayInfo internal_display_info(
436        gfx::Display::InternalDisplayId(),
437        l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
438        false  /*Internal display must not have overscan */);
439    internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
440    display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
441  }
442  UpdateDisplays(new_display_info_list);
443}
444
445void DisplayManager::UpdateDisplays() {
446  DisplayInfoList display_info_list;
447  for (DisplayList::const_iterator iter = displays_.begin();
448       iter != displays_.end(); ++iter) {
449    display_info_list.push_back(GetDisplayInfo(iter->id()));
450  }
451  AddMirrorDisplayInfoIfAny(&display_info_list);
452  UpdateDisplays(display_info_list);
453}
454
455void DisplayManager::UpdateDisplays(
456    const std::vector<DisplayInfo>& updated_display_info_list) {
457#if defined(OS_WIN)
458  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
459    DCHECK_EQ(1u, updated_display_info_list.size()) <<
460        "Multiple display test does not work on Win8 bots. Please "
461        "skip (don't disable) the test using SupportsMultipleDisplays()";
462  }
463#endif
464
465  DisplayInfoList new_display_info_list = updated_display_info_list;
466  std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
467  std::sort(new_display_info_list.begin(),
468            new_display_info_list.end(),
469            DisplayInfoSortFunctor());
470  DisplayList removed_displays;
471  std::vector<size_t> changed_display_indices;
472  std::vector<size_t> added_display_indices;
473
474  DisplayList::iterator curr_iter = displays_.begin();
475  DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
476
477  DisplayList new_displays;
478  bool update_mouse_location = false;
479
480  scoped_ptr<MirrorWindowCreator> mirror_window_creater;
481
482  // Use the internal display or 1st as the mirror source, then scale
483  // the root window so that it matches the external display's
484  // resolution. This is necessary in order for scaling to work while
485  // mirrored.
486  int64 mirrored_display_id = gfx::Display::kInvalidDisplayID;
487  if (software_mirroring_enabled_ && new_display_info_list.size() == 2)
488    mirrored_display_id = new_display_info_list[1].id();
489
490  while (curr_iter != displays_.end() ||
491         new_info_iter != new_display_info_list.end()) {
492    if (new_info_iter != new_display_info_list.end() &&
493        mirrored_display_id == new_info_iter->id()) {
494      DisplayInfo info = *new_info_iter;
495      info.SetOverscanInsets(gfx::Insets());
496      InsertAndUpdateDisplayInfo(info);
497
498      mirrored_display_ = CreateDisplayFromDisplayInfoById(new_info_iter->id());
499      mirror_window_creater.reset(
500          new MirrorWindowCreator(display_info_[new_info_iter->id()]));
501      ++new_info_iter;
502      // Remove existing external dispaly if it is going to be mirrored.
503      if (curr_iter != displays_.end() &&
504          curr_iter->id() == mirrored_display_id) {
505        removed_displays.push_back(*curr_iter);
506        ++curr_iter;
507      }
508      update_mouse_location = true;
509      continue;
510    }
511
512    if (curr_iter == displays_.end()) {
513      // more displays in new list.
514      added_display_indices.push_back(new_displays.size());
515      InsertAndUpdateDisplayInfo(*new_info_iter);
516      new_displays.push_back(
517          CreateDisplayFromDisplayInfoById(new_info_iter->id()));
518      ++new_info_iter;
519    } else if (new_info_iter == new_display_info_list.end()) {
520      // more displays in current list.
521      removed_displays.push_back(*curr_iter);
522      ++curr_iter;
523      update_mouse_location = true;
524    } else if (curr_iter->id() == new_info_iter->id()) {
525      const gfx::Display& current_display = *curr_iter;
526      // Copy the info because |CreateDisplayFromInfo| updates the instance.
527      const DisplayInfo current_display_info =
528          GetDisplayInfo(current_display.id());
529      InsertAndUpdateDisplayInfo(*new_info_iter);
530      gfx::Display new_display =
531          CreateDisplayFromDisplayInfoById(new_info_iter->id());
532      const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
533
534      bool host_window_bounds_changed =
535          current_display_info.bounds_in_pixel() !=
536          new_display_info.bounds_in_pixel();
537
538      if (force_bounds_changed_ ||
539          host_window_bounds_changed ||
540          (current_display.device_scale_factor() !=
541           new_display.device_scale_factor()) ||
542          (current_display_info.size_in_pixel() !=
543           new_display.GetSizeInPixel()) ||
544          (current_display.rotation() != new_display.rotation())) {
545
546        // Don't update mouse location if the display size has
547        // changed due to rotation or zooming.
548        if (host_window_bounds_changed)
549          update_mouse_location = true;
550
551        changed_display_indices.push_back(new_displays.size());
552      }
553
554      new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
555      new_displays.push_back(new_display);
556      ++curr_iter;
557      ++new_info_iter;
558    } else if (curr_iter->id() < new_info_iter->id()) {
559      // more displays in current list between ids, which means it is deleted.
560      removed_displays.push_back(*curr_iter);
561      ++curr_iter;
562      update_mouse_location = true;
563    } else {
564      // more displays in new list between ids, which means it is added.
565      added_display_indices.push_back(new_displays.size());
566      InsertAndUpdateDisplayInfo(*new_info_iter);
567      new_displays.push_back(
568          CreateDisplayFromDisplayInfoById(new_info_iter->id()));
569      ++new_info_iter;
570    }
571  }
572
573  scoped_ptr<MirrorWindowCloser> mirror_window_closer;
574  // Try to close mirror window unless mirror window is necessary.
575  if (!mirror_window_creater.get())
576    mirror_window_closer.reset(new MirrorWindowCloser);
577
578  // Do not update |displays_| if there's nothing to be updated. Without this,
579  // it will not update the display layout, which causes the bug
580  // http://crbug.com/155948.
581  if (changed_display_indices.empty() && added_display_indices.empty() &&
582      removed_displays.empty()) {
583    return;
584  }
585
586  DisplayController* display_controller =
587      Shell::GetInstance()->display_controller();
588  gfx::Point mouse_location_in_native;
589  display_controller->NotifyDisplayConfigurationChanging();
590  mouse_location_in_native = display_controller->GetNativeMouseCursorLocation();
591
592  size_t updated_index;
593  if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
594      std::find(added_display_indices.begin(),
595                added_display_indices.end(),
596                updated_index) == added_display_indices.end() &&
597      std::find(changed_display_indices.begin(),
598                changed_display_indices.end(),
599                updated_index) == changed_display_indices.end()) {
600    changed_display_indices.push_back(updated_index);
601  }
602
603  displays_ = new_displays;
604
605  base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
606
607  // Temporarily add displays to be removed because display object
608  // being removed are accessed during shutting down the root.
609  displays_.insert(displays_.end(), removed_displays.begin(),
610                   removed_displays.end());
611
612  for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
613       iter != removed_displays.rend(); ++iter) {
614    Shell::GetInstance()->screen()->NotifyDisplayRemoved(displays_.back());
615    displays_.pop_back();
616  }
617  // Close the mirror window here to avoid creating two compositor on
618  // one display.
619  mirror_window_closer.reset();
620  for (std::vector<size_t>::iterator iter = added_display_indices.begin();
621       iter != added_display_indices.end(); ++iter) {
622    Shell::GetInstance()->screen()->NotifyDisplayAdded(displays_[*iter]);
623  }
624  // Create the mirror window after all displays are added so that
625  // it can mirror the display newly added. This can happen when switching
626  // from dock mode to software mirror mode.
627  mirror_window_creater.reset();
628  for (std::vector<size_t>::iterator iter = changed_display_indices.begin();
629       iter != changed_display_indices.end(); ++iter) {
630    Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
631  }
632  display_controller->NotifyDisplayConfigurationChanged();
633  if (update_mouse_location)
634    display_controller->EnsurePointerInDisplays();
635  else
636    display_controller->UpdateMouseCursor(mouse_location_in_native);
637
638#if defined(USE_X11) && defined(OS_CHROMEOS)
639  if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS())
640    ui::ClearX11DefaultRootWindow();
641#endif
642}
643
644gfx::Display* DisplayManager::GetDisplayAt(size_t index) {
645  return index < displays_.size() ? &displays_[index] : NULL;
646}
647
648const gfx::Display* DisplayManager::GetPrimaryDisplayCandidate() const {
649  const gfx::Display* primary_candidate = &displays_[0];
650#if defined(OS_CHROMEOS)
651  if (base::chromeos::IsRunningOnChromeOS()) {
652    // On ChromeOS device, root windows are stacked vertically, and
653    // default primary is the one on top.
654    int count = GetNumDisplays();
655    int y = GetDisplayInfo(primary_candidate->id()).bounds_in_pixel().y();
656    for (int i = 1; i < count; ++i) {
657      const gfx::Display* display = &displays_[i];
658      const DisplayInfo& display_info = GetDisplayInfo(display->id());
659      if (display->IsInternal()) {
660        primary_candidate = display;
661        break;
662      } else if (display_info.bounds_in_pixel().y() < y) {
663        primary_candidate = display;
664        y = display_info.bounds_in_pixel().y();
665      }
666    }
667  }
668#endif
669  return primary_candidate;
670}
671
672size_t DisplayManager::GetNumDisplays() const {
673  return displays_.size();
674}
675
676bool DisplayManager::IsMirrored() const {
677  return mirrored_display_.id() != gfx::Display::kInvalidDisplayID;
678}
679
680const gfx::Display& DisplayManager::GetDisplayNearestWindow(
681    const Window* window) const {
682  if (!window)
683    return DisplayController::GetPrimaryDisplay();
684  const RootWindow* root = window->GetRootWindow();
685  DisplayManager* manager = const_cast<DisplayManager*>(this);
686  return root ?
687      manager->FindDisplayForRootWindow(root) :
688      DisplayController::GetPrimaryDisplay();
689}
690
691const gfx::Display& DisplayManager::GetDisplayNearestPoint(
692    const gfx::Point& point) const {
693  // Fallback to the primary display if there is no root display containing
694  // the |point|.
695  const gfx::Display& display = FindDisplayContainingPoint(point);
696  return display.is_valid() ? display : DisplayController::GetPrimaryDisplay();
697}
698
699const gfx::Display& DisplayManager::GetDisplayMatching(
700    const gfx::Rect& rect) const {
701  if (rect.IsEmpty())
702    return GetDisplayNearestPoint(rect.origin());
703
704  int max = 0;
705  const gfx::Display* matching = 0;
706  for (std::vector<gfx::Display>::const_iterator iter = displays_.begin();
707       iter != displays_.end(); ++iter) {
708    const gfx::Display& display = *iter;
709    gfx::Rect intersect = gfx::IntersectRects(display.bounds(), rect);
710    int area = intersect.width() * intersect.height();
711    if (area > max) {
712      max = area;
713      matching = &(*iter);
714    }
715  }
716  // Fallback to the primary display if there is no matching display.
717  return matching ? *matching : DisplayController::GetPrimaryDisplay();
718}
719
720const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
721  std::map<int64, DisplayInfo>::const_iterator iter =
722      display_info_.find(display_id);
723  CHECK(iter != display_info_.end()) << display_id;
724  return iter->second;
725}
726
727std::string DisplayManager::GetDisplayNameForId(int64 id) {
728  if (id == gfx::Display::kInvalidDisplayID)
729    return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
730
731  std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
732  if (iter != display_info_.end() && !iter->second.name().empty())
733    return iter->second.name();
734
735  return base::StringPrintf("Display %d", static_cast<int>(id));
736}
737
738int64 DisplayManager::GetDisplayIdForUIScaling() const {
739  // UI Scaling is effective only on internal display.
740  int64 display_id = gfx::Display::InternalDisplayId();
741#if defined(OS_WIN)
742  display_id = first_display_id();
743#endif
744  return display_id;
745}
746
747void DisplayManager::SetMirrorMode(bool mirrored) {
748  if (num_connected_displays() <= 1)
749    return;
750
751#if defined(OS_CHROMEOS)
752  if (base::chromeos::IsRunningOnChromeOS()) {
753    chromeos::OutputState new_state = mirrored ?
754        chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED;
755    Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state);
756    return;
757  }
758#endif
759  SetSoftwareMirroring(mirrored);
760  DisplayInfoList display_info_list;
761  int count = 0;
762  for (std::map<int64, DisplayInfo>::const_iterator iter =
763           display_info_.begin();
764       count < 2; ++iter, ++count) {
765    display_info_list.push_back(GetDisplayInfo(iter->second.id()));
766  }
767  UpdateDisplays(display_info_list);
768#if defined(OS_CHROMEOS)
769  if (Shell::GetInstance()->output_configurator_animation()) {
770    Shell::GetInstance()->output_configurator_animation()->
771        StartFadeInAnimation();
772  }
773#endif
774}
775
776void DisplayManager::AddRemoveDisplay() {
777  DCHECK(!displays_.empty());
778  std::vector<DisplayInfo> new_display_info_list;
779  new_display_info_list.push_back(
780      GetDisplayInfo(DisplayController::GetPrimaryDisplay().id()));
781  // Add if there is only one display connected.
782  if (num_connected_displays() == 1) {
783    // Layout the 2nd display below the primary as with the real device.
784    aura::RootWindow* primary = Shell::GetPrimaryRootWindow();
785    gfx::Rect host_bounds =
786        gfx::Rect(primary->GetHostOrigin(),  primary->GetHostSize());
787    new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
788        base::StringPrintf(
789            "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
790  }
791  num_connected_displays_ = new_display_info_list.size();
792  mirrored_display_ = gfx::Display();
793  UpdateDisplays(new_display_info_list);
794}
795
796void DisplayManager::ToggleDisplayScaleFactor() {
797  DCHECK(!displays_.empty());
798  std::vector<DisplayInfo> new_display_info_list;
799  for (DisplayList::const_iterator iter = displays_.begin();
800       iter != displays_.end(); ++iter) {
801    DisplayInfo display_info = GetDisplayInfo(iter->id());
802    display_info.set_device_scale_factor(
803        display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
804    new_display_info_list.push_back(display_info);
805  }
806  AddMirrorDisplayInfoIfAny(&new_display_info_list);
807  UpdateDisplays(new_display_info_list);
808}
809
810void DisplayManager::OnRootWindowHostResized(const aura::RootWindow* root) {
811  if (change_display_upon_host_resize_) {
812    gfx::Display& display = FindDisplayForRootWindow(root);
813    gfx::Size old_display_size_in_pixel = display.GetSizeInPixel();
814    display_info_[display.id()].SetBounds(
815        gfx::Rect(root->GetHostOrigin(), root->GetHostSize()));
816    // It's tricky to support resizing mirror window on desktop.
817    if (software_mirroring_enabled_ && mirrored_display_.id() == display.id())
818      return;
819    display.SetSize(display_info_[display.id()].size_in_pixel());
820    Shell::GetInstance()->screen()->NotifyBoundsChanged(display);
821    Shell::GetInstance()->mirror_window_controller()->UpdateWindow();
822  }
823}
824
825void DisplayManager::SetSoftwareMirroring(bool enabled) {
826  software_mirroring_enabled_ = enabled;
827  mirrored_display_ = gfx::Display();
828}
829
830void DisplayManager::Init() {
831  // TODO(oshima): Move this logic to DisplayChangeObserver.
832  const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
833      switches::kAshHostWindowBounds);
834  vector<string> parts;
835  base::SplitString(size_str, ',', &parts);
836  for (vector<string>::const_iterator iter = parts.begin();
837       iter != parts.end(); ++iter) {
838    AddDisplayFromSpec(*iter);
839  }
840  if (displays_.empty())
841    AddDisplayFromSpec(std::string() /* default */);
842  first_display_id_ = displays_[0].id();
843  CommandLine* command_line = CommandLine::ForCurrentProcess();
844  if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal))
845    gfx::Display::SetInternalDisplayId(first_display_id_);
846  num_connected_displays_ = displays_.size();
847}
848
849gfx::Display& DisplayManager::FindDisplayForRootWindow(
850    const aura::RootWindow* root_window) {
851  int64 id = root_window->GetProperty(kDisplayIdKey);
852  // RootWindow needs Display to determine it's device scale factor.
853  // TODO(oshima): We don't need full display info for mirror
854  // window. Refactor so that RootWindow doesn't use it.
855  if (mirrored_display_.id() == id)
856    return mirrored_display_;
857
858  // if id is |kInvaildDisplayID|, it's being deleted.
859  DCHECK(id != gfx::Display::kInvalidDisplayID);
860  gfx::Display& display = FindDisplayForId(id);
861  DCHECK(display.is_valid());
862  return display;
863}
864
865gfx::Display& DisplayManager::FindDisplayForId(int64 id) {
866  for (DisplayList::iterator iter = displays_.begin();
867       iter != displays_.end(); ++iter) {
868    if ((*iter).id() == id)
869      return *iter;
870  }
871  DLOG(WARNING) << "Could not find display:" << id;
872  return GetInvalidDisplay();
873}
874
875void DisplayManager::AddMirrorDisplayInfoIfAny(
876    std::vector<DisplayInfo>* display_info_list) {
877  if (software_mirroring_enabled_ && mirrored_display_.is_valid())
878    display_info_list->push_back(GetDisplayInfo(mirrored_display_.id()));
879}
880
881void DisplayManager::AddDisplayFromSpec(const std::string& spec) {
882  DisplayInfo display_info = DisplayInfo::CreateFromSpec(spec);
883  InsertAndUpdateDisplayInfo(display_info);
884  gfx::Display display = CreateDisplayFromDisplayInfoById(display_info.id());
885  displays_.push_back(display);
886}
887
888void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
889  std::map<int64, DisplayInfo>::iterator info =
890      display_info_.find(new_info.id());
891  if (info != display_info_.end())
892    info->second.Copy(new_info);
893  else {
894    display_info_[new_info.id()] = new_info;
895    display_info_[new_info.id()].set_native(false);
896  }
897  display_info_[new_info.id()].UpdateDisplaySize();
898}
899
900gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
901  DCHECK(display_info_.find(id) != display_info_.end());
902  const DisplayInfo& display_info = display_info_[id];
903
904  gfx::Display new_display(display_info.id());
905  gfx::Rect bounds_in_pixel(display_info.size_in_pixel());
906
907  // Simply set the origin to (0,0).  The primary display's origin is
908  // always (0,0) and the secondary display's bounds will be updated
909  // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|.
910  new_display.SetScaleAndBounds(
911      display_info.device_scale_factor(), gfx::Rect(bounds_in_pixel.size()));
912  new_display.set_rotation(display_info.rotation());
913  return new_display;
914}
915
916bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
917    DisplayList* displays,
918    size_t* updated_index) const {
919  if (displays->size() != 2U)
920    return false;
921
922  DisplayController* controller = Shell::GetInstance()->display_controller();
923  int64 id_at_zero = displays->at(0).id();
924  DisplayIdPair pair =
925      (id_at_zero == first_display_id_ ||
926       id_at_zero == gfx::Display::InternalDisplayId()) ?
927      std::make_pair(id_at_zero, displays->at(1).id()) :
928      std::make_pair(displays->at(1).id(), id_at_zero) ;
929  DisplayLayout layout =
930      controller->ComputeDisplayLayoutForDisplayIdPair(pair);
931
932  // Ignore if a user has a old format (should be extremely rare)
933  // and this will be replaced with DCHECK.
934  if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
935    size_t primary_index, secondary_index;
936    if (displays->at(0).id() == layout.primary_id) {
937      primary_index = 0;
938      secondary_index = 1;
939    } else {
940      primary_index = 1;
941      secondary_index = 0;
942    }
943    gfx::Rect bounds =
944        GetDisplayForId(displays->at(secondary_index).id()).bounds();
945    UpdateDisplayBoundsForLayout(
946        layout, displays->at(primary_index), &displays->at(secondary_index));
947    *updated_index = secondary_index;
948    return bounds != displays->at(secondary_index).bounds();
949  }
950  return false;
951}
952
953}  // namespace internal
954}  // namespace ash
955