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