display_manager.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/screen_ash.h"
15#include "ash/shell.h"
16#include "base/auto_reset.h"
17#include "base/command_line.h"
18#include "base/logging.h"
19#include "base/stl_util.h"
20#include "base/stringprintf.h"
21#include "base/strings/string_number_conversions.h"
22#include "base/strings/string_split.h"
23#include "base/utf_string_conversions.h"
24#include "grit/ash_strings.h"
25#include "ui/aura/client/screen_position_client.h"
26#include "ui/aura/env.h"
27#include "ui/aura/root_window.h"
28#include "ui/aura/root_window_host.h"
29#include "ui/aura/window_property.h"
30#include "ui/base/l10n/l10n_util.h"
31#include "ui/gfx/display.h"
32#include "ui/gfx/rect.h"
33#include "ui/gfx/screen.h"
34#include "ui/gfx/size_conversions.h"
35
36#if defined(USE_X11)
37#include "ui/base/x/x11_util.h"
38#endif
39
40#if defined(OS_CHROMEOS)
41#include "base/chromeos/chromeos_version.h"
42#endif
43
44#if defined(OS_WIN)
45#include "base/win/windows_version.h"
46#include "ui/aura/remote_root_window_host_win.h"
47#endif
48
49DECLARE_WINDOW_PROPERTY_TYPE(int64);
50
51namespace ash {
52namespace internal {
53typedef std::vector<gfx::Display> DisplayList;
54typedef std::vector<DisplayInfo> DisplayInfoList;
55
56namespace {
57
58// List of value UI Scale values. Scales for 2x are equivalent to 640,
59// 800, 1024, 1280, 1440, 1600 and 1920 pixel width respectively on
60// 2560 pixel width 2x density display. Please see crbug.com/233375
61// for the full list of resolutions.
62const float kUIScalesFor2x[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f, 1.25f, 1.5f};
63const float kUIScalesFor1280[] = {0.5f, 0.625f, 0.8f, 1.0f, 1.125f };
64const float kUIScalesFor1366[] = {0.5f, 0.6f, 0.75f, 1.0f, 1.125f };
65
66struct DisplaySortFunctor {
67  bool operator()(const gfx::Display& a, const gfx::Display& b) {
68    return a.id() < b.id();
69  }
70};
71
72struct DisplayInfoSortFunctor {
73  bool operator()(const DisplayInfo& a, const DisplayInfo& b) {
74    return a.id() < b.id();
75  }
76};
77
78struct ScaleComparator {
79  ScaleComparator(float s) : scale(s) {}
80
81  bool operator()(float s) const {
82    const float kEpsilon = 0.0001f;
83    return std::abs(scale - s) < kEpsilon;
84  }
85  float scale;
86};
87
88std::vector<float> GetScalesForDisplay(const DisplayInfo& info) {
89  std::vector<float> ret;
90  if (info.device_scale_factor() == 2.0f) {
91    ret.assign(kUIScalesFor2x, kUIScalesFor2x + arraysize(kUIScalesFor2x));
92    return ret;
93  }
94  switch (info.bounds_in_pixel().width()) {
95    case 1280:
96      ret.assign(kUIScalesFor1280,
97                 kUIScalesFor1280 + arraysize(kUIScalesFor1280));
98      break;
99    case 1366:
100      ret.assign(kUIScalesFor1366,
101                 kUIScalesFor1366 + arraysize(kUIScalesFor1366));
102      break;
103    default:
104      ret.assign(kUIScalesFor1280,
105                 kUIScalesFor1280 + arraysize(kUIScalesFor1280));
106#if defined(OS_CHROMEOS)
107      if (base::chromeos::IsRunningOnChromeOS())
108        NOTREACHED() << "Unknown resolution:" << info.ToString();
109#endif
110  }
111  return ret;
112}
113
114gfx::Display& GetInvalidDisplay() {
115  static gfx::Display* invalid_display = new gfx::Display();
116  return *invalid_display;
117}
118
119}  // namespace
120
121using aura::RootWindow;
122using aura::Window;
123using std::string;
124using std::vector;
125
126DEFINE_WINDOW_PROPERTY_KEY(int64, kDisplayIdKey,
127                           gfx::Display::kInvalidDisplayID);
128
129DisplayManager::DisplayManager()
130    : first_display_id_(gfx::Display::kInvalidDisplayID),
131      mirrored_display_id_(gfx::Display::kInvalidDisplayID),
132      num_connected_displays_(0),
133      force_bounds_changed_(false),
134      change_display_upon_host_resize_(false) {
135#if defined(OS_CHROMEOS)
136  change_display_upon_host_resize_ = !base::chromeos::IsRunningOnChromeOS();
137#endif
138  Init();
139}
140
141DisplayManager::~DisplayManager() {
142}
143
144// static
145void DisplayManager::CycleDisplay() {
146  Shell::GetInstance()->display_manager()->CycleDisplayImpl();
147}
148
149// static
150void DisplayManager::ToggleDisplayScaleFactor() {
151  Shell::GetInstance()->display_manager()->ScaleDisplayImpl();
152}
153
154// static
155float DisplayManager::GetNextUIScale(const DisplayInfo& info, bool up) {
156  float scale = info.ui_scale();
157  std::vector<float> scales = GetScalesForDisplay(info);
158  for (size_t i = 0; i < scales.size(); ++i) {
159    if (ScaleComparator(scales[i])(scale)) {
160      if (up && i != scales.size() - 1)
161        return scales[i + 1];
162      if (!up && i != 0)
163        return scales[i - 1];
164      return scales[i];
165    }
166  }
167  // Fallback to 1.0f if the |scale| wasn't in the list.
168  return 1.0f;
169}
170
171bool DisplayManager::IsActiveDisplay(const gfx::Display& display) const {
172  for (DisplayList::const_iterator iter = displays_.begin();
173       iter != displays_.end(); ++iter) {
174    if ((*iter).id() == display.id())
175      return true;
176  }
177  return false;
178}
179
180bool DisplayManager::HasInternalDisplay() const {
181  return gfx::Display::InternalDisplayId() != gfx::Display::kInvalidDisplayID;
182}
183
184bool DisplayManager::IsInternalDisplayId(int64 id) const {
185  return gfx::Display::InternalDisplayId() == id;
186}
187
188bool DisplayManager::UpdateWorkAreaOfDisplayNearestWindow(
189    const aura::Window* window,
190    const gfx::Insets& insets) {
191  const RootWindow* root = window->GetRootWindow();
192  gfx::Display& display = FindDisplayForRootWindow(root);
193  gfx::Rect old_work_area = display.work_area();
194  display.UpdateWorkAreaFromInsets(insets);
195  return old_work_area != display.work_area();
196}
197
198const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
199  return const_cast<DisplayManager*>(this)->FindDisplayForId(id);
200}
201
202const gfx::Display& DisplayManager::FindDisplayContainingPoint(
203    const gfx::Point& point_in_screen) const {
204  for (DisplayList::const_iterator iter = displays_.begin();
205       iter != displays_.end(); ++iter) {
206    const gfx::Display& display = *iter;
207    if (display.bounds().Contains(point_in_screen))
208      return display;
209  }
210  return GetInvalidDisplay();
211}
212
213void DisplayManager::SetOverscanInsets(int64 display_id,
214                                       const gfx::Insets& insets_in_dip) {
215  // TODO(oshima): insets has to be rotated according to the
216  // the current display rotation.
217  display_info_[display_id].SetOverscanInsets(true, insets_in_dip);
218  DisplayInfoList display_info_list;
219  for (DisplayList::const_iterator iter = displays_.begin();
220       iter != displays_.end(); ++iter) {
221    display_info_list.push_back(GetDisplayInfo(iter->id()));
222  }
223  UpdateDisplays(display_info_list);
224}
225
226void DisplayManager::ClearCustomOverscanInsets(int64 display_id) {
227  display_info_[display_id].clear_has_custom_overscan_insets();
228  DisplayInfoList display_info_list;
229  for (DisplayList::const_iterator iter = displays_.begin();
230       iter != displays_.end(); ++iter) {
231    display_info_list.push_back(GetDisplayInfo(iter->id()));
232  }
233  UpdateDisplays(display_info_list);
234}
235
236void DisplayManager::SetDisplayRotation(int64 display_id,
237                                        gfx::Display::Rotation rotation) {
238  if (!IsDisplayRotationEnabled())
239    return;
240  DisplayInfoList display_info_list;
241  for (DisplayList::const_iterator iter = displays_.begin();
242       iter != displays_.end(); ++iter) {
243    DisplayInfo info = GetDisplayInfo(iter->id());
244    if (info.id() == display_id) {
245      if (info.rotation() == rotation)
246        return;
247      info.set_rotation(rotation);
248    }
249    display_info_list.push_back(info);
250  }
251  UpdateDisplays(display_info_list);
252}
253
254void DisplayManager::SetDisplayUIScale(int64 display_id,
255                                       float ui_scale) {
256  if (!IsDisplayUIScalingEnabled() ||
257      gfx::Display::InternalDisplayId() != display_id) {
258    return;
259  }
260
261  DisplayInfoList display_info_list;
262  for (DisplayList::const_iterator iter = displays_.begin();
263       iter != displays_.end(); ++iter) {
264    DisplayInfo info = GetDisplayInfo(iter->id());
265    if (info.id() == display_id) {
266      if (info.ui_scale() == ui_scale)
267        return;
268      std::vector<float> scales = GetScalesForDisplay(info);
269      ScaleComparator comparator(ui_scale);
270      if (std::find_if(scales.begin(), scales.end(), comparator) ==
271          scales.end()) {
272        return;
273      }
274      info.set_ui_scale(ui_scale);
275    }
276    display_info_list.push_back(info);
277  }
278  UpdateDisplays(display_info_list);
279}
280
281void DisplayManager::RegisterDisplayProperty(
282    int64 display_id,
283    gfx::Display::Rotation rotation,
284    float ui_scale,
285    const gfx::Insets* overscan_insets) {
286  if (display_info_.find(display_id) == display_info_.end()) {
287    display_info_[display_id] =
288        DisplayInfo(display_id, std::string(""), false);
289  }
290
291  display_info_[display_id].set_rotation(rotation);
292  // Just in case the preference file was corrupted.
293  if (0.5f <= ui_scale && ui_scale <= 2.0f)
294    display_info_[display_id].set_ui_scale(ui_scale);
295  if (overscan_insets)
296    display_info_[display_id].SetOverscanInsets(true, *overscan_insets);
297}
298
299bool DisplayManager::IsDisplayRotationEnabled() const {
300  static bool enabled = !CommandLine::ForCurrentProcess()->
301      HasSwitch(switches::kAshDisableDisplayRotation);
302  return enabled;
303}
304
305bool DisplayManager::IsDisplayUIScalingEnabled() const {
306  static bool enabled = !CommandLine::ForCurrentProcess()->
307      HasSwitch(switches::kAshDisableUIScaling);
308  if (!enabled)
309    return false;
310  return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
311}
312
313gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
314  std::map<int64, DisplayInfo>::const_iterator it =
315      display_info_.find(display_id);
316  return (it != display_info_.end()) ?
317      it->second.overscan_insets_in_dip() : gfx::Insets();
318}
319
320void DisplayManager::OnNativeDisplaysChanged(
321    const std::vector<DisplayInfo>& updated_displays) {
322  if (updated_displays.empty()) {
323    // Don't update the displays when all displays are disconnected.
324    // This happens when:
325    // - the device is idle and powerd requested to turn off all displays.
326    // - the device is suspended. (kernel turns off all displays)
327    // - the internal display's brightness is set to 0 and no external
328    //   display is connected.
329    // - the internal display's brightness is 0 and external display is
330    //   disconnected.
331    // The display will be updated when one of displays is turned on, and the
332    // display list will be updated correctly.
333    return;
334  }
335  first_display_id_ = updated_displays[0].id();
336  std::set<int> y_coords;
337  if (updated_displays.size() == 1) {
338    VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
339  } else {
340    VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
341            << ") [0]=" << updated_displays[0].ToString()
342            << ", [1]=" << updated_displays[1].ToString();
343  }
344
345  bool internal_display_connected = false;
346  num_connected_displays_ = updated_displays.size();
347  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
348  DisplayInfoList new_display_info_list;
349  for (DisplayInfoList::const_iterator iter = updated_displays.begin();
350       iter != updated_displays.end();
351       ++iter) {
352    if (!internal_display_connected)
353      internal_display_connected = IsInternalDisplayId(iter->id());
354    // Mirrored monitors have the same y coordinates.
355    int y = iter->bounds_in_pixel().y();
356    if (y_coords.find(y) != y_coords.end()) {
357      InsertAndUpdateDisplayInfo(*iter);
358      mirrored_display_id_ = iter->id();
359    } else {
360      y_coords.insert(y);
361      new_display_info_list.push_back(*iter);
362    }
363  }
364  if (HasInternalDisplay() &&
365      !internal_display_connected &&
366      display_info_.find(gfx::Display::InternalDisplayId()) ==
367      display_info_.end()) {
368    DisplayInfo internal_display_info(
369        gfx::Display::InternalDisplayId(),
370        l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
371        false  /*Internal display must not have overscan */);
372    internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
373    display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
374  }
375  UpdateDisplays(new_display_info_list);
376}
377
378void DisplayManager::UpdateDisplays() {
379  DisplayInfoList display_info_list;
380  for (DisplayList::const_iterator iter = displays_.begin();
381       iter != displays_.end(); ++iter) {
382    display_info_list.push_back(GetDisplayInfo(iter->id()));
383  }
384  UpdateDisplays(display_info_list);
385}
386
387void DisplayManager::UpdateDisplays(
388    const std::vector<DisplayInfo>& updated_display_info_list) {
389  DisplayInfoList new_display_info_list = updated_display_info_list;
390  std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
391  std::sort(new_display_info_list.begin(),
392            new_display_info_list.end(),
393            DisplayInfoSortFunctor());
394  DisplayList removed_displays;
395  std::vector<size_t> changed_display_indices;
396  std::vector<size_t> added_display_indices;
397
398  DisplayList::iterator curr_iter = displays_.begin();
399  DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
400
401  DisplayList new_displays;
402  bool update_mouse_location = false;
403
404  while (curr_iter != displays_.end() ||
405         new_info_iter != new_display_info_list.end()) {
406    if (curr_iter == displays_.end()) {
407      // more displays in new list.
408      added_display_indices.push_back(new_displays.size());
409      InsertAndUpdateDisplayInfo(*new_info_iter);
410      new_displays.push_back(
411          CreateDisplayFromDisplayInfoById(new_info_iter->id()));
412      ++new_info_iter;
413    } else if (new_info_iter == new_display_info_list.end()) {
414      // more displays in current list.
415      removed_displays.push_back(*curr_iter);
416      ++curr_iter;
417      update_mouse_location = true;
418    } else if (curr_iter->id() == new_info_iter->id()) {
419      const gfx::Display& current_display = *curr_iter;
420      // Copy the info because |CreateDisplayFromInfo| updates the instance.
421      const DisplayInfo current_display_info =
422          GetDisplayInfo(current_display.id());
423      InsertAndUpdateDisplayInfo(*new_info_iter);
424      gfx::Display new_display =
425          CreateDisplayFromDisplayInfoById(new_info_iter->id());
426      const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
427
428      bool host_window_bounds_changed =
429          current_display_info.bounds_in_pixel() !=
430          new_display_info.bounds_in_pixel();
431
432      // TODO(oshima): Rotating square dislay doesn't work as the size
433      // won't change. This doesn't cause a problem now as there is no
434      // such display. This will be fixed by comparing the rotation as
435      // well when the rotation variable is added to gfx::Display.
436      if (force_bounds_changed_ ||
437          host_window_bounds_changed ||
438          (current_display.device_scale_factor() !=
439           new_display.device_scale_factor()) ||
440          (current_display_info.size_in_pixel() !=
441           new_display.GetSizeInPixel())) {
442
443        // Don't update mouse location if the display size has
444        // changed due to rotation or zooming.
445        if (host_window_bounds_changed)
446          update_mouse_location = true;
447
448        changed_display_indices.push_back(new_displays.size());
449      }
450
451      new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
452      new_displays.push_back(new_display);
453      ++curr_iter;
454      ++new_info_iter;
455    } else if (curr_iter->id() < new_info_iter->id()) {
456      // more displays in current list between ids, which means it is deleted.
457      removed_displays.push_back(*curr_iter);
458      ++curr_iter;
459      update_mouse_location = true;
460    } else {
461      // more displays in new list between ids, which means it is added.
462      added_display_indices.push_back(new_displays.size());
463      InsertAndUpdateDisplayInfo(*new_info_iter);
464      new_displays.push_back(
465          CreateDisplayFromDisplayInfoById(new_info_iter->id()));
466      ++new_info_iter;
467    }
468  }
469
470  // Do not update |displays_| if there's nothing to be updated. Without this,
471  // it will not update the display layout, which causes the bug
472  // http://crbug.com/155948.
473  if (changed_display_indices.empty() && added_display_indices.empty() &&
474      removed_displays.empty()) {
475    return;
476  }
477
478  DisplayController* display_controller =
479      Shell::GetInstance()->display_controller();
480  gfx::Point mouse_location_in_native;
481  display_controller->NotifyDisplayConfigurationChanging();
482  mouse_location_in_native = display_controller->GetNativeMouseCursorLocation();
483
484  displays_ = new_displays;
485
486  base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
487
488  // Temporarily add displays to be removed because display object
489  // being removed are accessed during shutting down the root.
490  displays_.insert(displays_.end(), removed_displays.begin(),
491                   removed_displays.end());
492
493  for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
494       iter != removed_displays.rend(); ++iter) {
495    Shell::GetInstance()->screen()->NotifyDisplayRemoved(displays_.back());
496    displays_.pop_back();
497  }
498  for (std::vector<size_t>::iterator iter = added_display_indices.begin();
499       iter != added_display_indices.end(); ++iter) {
500    Shell::GetInstance()->screen()->NotifyDisplayAdded(displays_[*iter]);
501  }
502  for (std::vector<size_t>::iterator iter = changed_display_indices.begin();
503       iter != changed_display_indices.end(); ++iter) {
504    Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
505  }
506  display_controller->NotifyDisplayConfigurationChanged();
507  if (update_mouse_location)
508    display_controller->EnsurePointerInDisplays();
509  else
510    display_controller->UpdateMouseCursor(mouse_location_in_native);
511
512#if defined(USE_X11) && defined(OS_CHROMEOS)
513  if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS())
514    ui::ClearX11DefaultRootWindow();
515#endif
516}
517
518gfx::Display* DisplayManager::GetDisplayAt(size_t index) {
519  return index < displays_.size() ? &displays_[index] : NULL;
520}
521
522const gfx::Display* DisplayManager::GetPrimaryDisplayCandidate() const {
523  const gfx::Display* primary_candidate = &displays_[0];
524#if defined(OS_CHROMEOS)
525  if (base::chromeos::IsRunningOnChromeOS()) {
526    // On ChromeOS device, root windows are stacked vertically, and
527    // default primary is the one on top.
528    int count = GetNumDisplays();
529    int y = GetDisplayInfo(primary_candidate->id()).bounds_in_pixel().y();
530    for (int i = 1; i < count; ++i) {
531      const gfx::Display* display = &displays_[i];
532      const DisplayInfo& display_info = GetDisplayInfo(display->id());
533      if (display->IsInternal()) {
534        primary_candidate = display;
535        break;
536      } else if (display_info.bounds_in_pixel().y() < y) {
537        primary_candidate = display;
538        y = display_info.bounds_in_pixel().y();
539      }
540    }
541  }
542#endif
543  return primary_candidate;
544}
545
546size_t DisplayManager::GetNumDisplays() const {
547  return displays_.size();
548}
549
550bool DisplayManager::IsMirrored() const {
551  return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
552}
553
554const gfx::Display& DisplayManager::GetDisplayNearestWindow(
555    const Window* window) const {
556  if (!window)
557    return DisplayController::GetPrimaryDisplay();
558  const RootWindow* root = window->GetRootWindow();
559  DisplayManager* manager = const_cast<DisplayManager*>(this);
560  return root ?
561      manager->FindDisplayForRootWindow(root) :
562      DisplayController::GetPrimaryDisplay();
563}
564
565const gfx::Display& DisplayManager::GetDisplayNearestPoint(
566    const gfx::Point& point) const {
567  // Fallback to the primary display if there is no root display containing
568  // the |point|.
569  const gfx::Display& display = FindDisplayContainingPoint(point);
570  return display.is_valid() ? display : DisplayController::GetPrimaryDisplay();
571}
572
573const gfx::Display& DisplayManager::GetDisplayMatching(
574    const gfx::Rect& rect) const {
575  if (rect.IsEmpty())
576    return GetDisplayNearestPoint(rect.origin());
577
578  int max = 0;
579  const gfx::Display* matching = 0;
580  for (std::vector<gfx::Display>::const_iterator iter = displays_.begin();
581       iter != displays_.end(); ++iter) {
582    const gfx::Display& display = *iter;
583    gfx::Rect intersect = gfx::IntersectRects(display.bounds(), rect);
584    int area = intersect.width() * intersect.height();
585    if (area > max) {
586      max = area;
587      matching = &(*iter);
588    }
589  }
590  // Fallback to the primary display if there is no matching display.
591  return matching ? *matching : DisplayController::GetPrimaryDisplay();
592}
593
594const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
595  std::map<int64, DisplayInfo>::const_iterator iter =
596      display_info_.find(display_id);
597  CHECK(iter != display_info_.end());
598  return iter->second;
599}
600
601std::string DisplayManager::GetDisplayNameForId(int64 id) {
602  if (id == gfx::Display::kInvalidDisplayID)
603    return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
604
605  std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
606  if (iter != display_info_.end() && !iter->second.name().empty())
607    return iter->second.name();
608
609  return base::StringPrintf("Display %d", static_cast<int>(id));
610}
611
612void DisplayManager::OnRootWindowResized(const aura::RootWindow* root,
613                                         const gfx::Size& old_size) {
614  if (change_display_upon_host_resize_) {
615    gfx::Display& display = FindDisplayForRootWindow(root);
616    gfx::Size old_display_size_in_pixel = display.GetSizeInPixel();
617    display_info_[display.id()].SetBounds(
618        gfx::Rect(root->GetHostOrigin(), root->GetHostSize()));
619    const gfx::Size& new_root_size = root->bounds().size();
620    if (old_size != new_root_size) {
621      display.SetSize(display_info_[display.id()].size_in_pixel());
622      Shell::GetInstance()->screen()->NotifyBoundsChanged(display);
623    }
624  }
625}
626
627int64 DisplayManager::GetDisplayIdForUIScaling() const {
628  // UI Scaling is effective only on internal display.
629  int64 display_id = gfx::Display::InternalDisplayId();
630#if defined(OS_WIN)
631  display_id = first_display_id();
632#endif
633  return display_id;
634}
635
636void DisplayManager::Init() {
637  // TODO(oshima): Move this logic to DisplayChangeObserver.
638  const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
639      switches::kAshHostWindowBounds);
640  vector<string> parts;
641  base::SplitString(size_str, ',', &parts);
642  for (vector<string>::const_iterator iter = parts.begin();
643       iter != parts.end(); ++iter) {
644    AddDisplayFromSpec(*iter);
645  }
646  if (displays_.empty())
647    AddDisplayFromSpec(std::string() /* default */);
648  first_display_id_ = displays_[0].id();
649  CommandLine* command_line = CommandLine::ForCurrentProcess();
650  if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal))
651    gfx::Display::SetInternalDisplayId(first_display_id_);
652  num_connected_displays_ = displays_.size();
653}
654
655void DisplayManager::CycleDisplayImpl() {
656  DCHECK(!displays_.empty());
657  std::vector<DisplayInfo> new_display_info_list;
658  new_display_info_list.push_back(
659      GetDisplayInfo(DisplayController::GetPrimaryDisplay().id()));
660  // Add if there is only one display.
661  if (displays_.size() == 1) {
662    // Layout the 2nd display below the primary as with the real device.
663    aura::RootWindow* primary = Shell::GetPrimaryRootWindow();
664    gfx::Rect host_bounds =
665        gfx::Rect(primary->GetHostOrigin(),  primary->GetHostSize());
666    new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
667        base::StringPrintf(
668            "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
669  }
670  num_connected_displays_ = new_display_info_list.size();
671  UpdateDisplays(new_display_info_list);
672}
673
674void DisplayManager::ScaleDisplayImpl() {
675  DCHECK(!displays_.empty());
676  std::vector<DisplayInfo> new_display_info_list;
677  for (DisplayList::const_iterator iter = displays_.begin();
678       iter != displays_.end(); ++iter) {
679    DisplayInfo display_info = GetDisplayInfo(iter->id());
680    display_info.set_device_scale_factor(
681        display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
682    new_display_info_list.push_back(display_info);
683  }
684  UpdateDisplays(new_display_info_list);
685}
686
687gfx::Display& DisplayManager::FindDisplayForRootWindow(
688    const aura::RootWindow* root_window) {
689  int64 id = root_window->GetProperty(kDisplayIdKey);
690  // if id is |kInvaildDisplayID|, it's being deleted.
691  DCHECK(id != gfx::Display::kInvalidDisplayID);
692  gfx::Display& display = FindDisplayForId(id);
693  DCHECK(display.is_valid());
694  return display;
695}
696
697gfx::Display& DisplayManager::FindDisplayForId(int64 id) {
698  for (DisplayList::iterator iter = displays_.begin();
699       iter != displays_.end(); ++iter) {
700    if ((*iter).id() == id)
701      return *iter;
702  }
703  DLOG(WARNING) << "Could not find display:" << id;
704  return GetInvalidDisplay();
705}
706
707void DisplayManager::AddDisplayFromSpec(const std::string& spec) {
708  DisplayInfo display_info = DisplayInfo::CreateFromSpec(spec);
709  InsertAndUpdateDisplayInfo(display_info);
710  gfx::Display display = CreateDisplayFromDisplayInfoById(display_info.id());
711  displays_.push_back(display);
712}
713
714void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
715  std::map<int64, DisplayInfo>::iterator info =
716      display_info_.find(new_info.id());
717  if (info != display_info_.end())
718    info->second.Copy(new_info);
719  else {
720    display_info_[new_info.id()] = new_info;
721    display_info_[new_info.id()].set_native(false);
722  }
723  display_info_[new_info.id()].UpdateDisplaySize();
724}
725
726gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
727  DCHECK(display_info_.find(id) != display_info_.end());
728  const DisplayInfo& display_info = display_info_[id];
729
730  gfx::Display new_display(display_info.id());
731  gfx::Rect bounds_in_pixel(display_info.size_in_pixel());
732
733  // Simply set the origin to (0,0).  The primary display's origin is
734  // always (0,0) and the secondary display's bounds will be updated
735  // by |DisplayController::UpdateDisplayBoundsForLayout|.
736  new_display.SetScaleAndBounds(
737      display_info.device_scale_factor(), gfx::Rect(bounds_in_pixel.size()));
738  new_display.set_rotation(display_info.rotation());
739  return new_display;
740}
741
742}  // namespace internal
743}  // namespace ash
744