display_manager.cc revision f2477e01787aa58f445919b809d89e252beef54f
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    DCHECK_LE(2u, num_connected_displays());
282    return std::make_pair(displays_[0].id(), mirrored_display_id_);
283  } else {
284    CHECK_GE(2u, displays_.size());
285    int64 id_at_zero = displays_[0].id();
286    if (id_at_zero == gfx::Display::InternalDisplayId() ||
287        id_at_zero == first_display_id()) {
288      return std::make_pair(id_at_zero, displays_[1].id());
289    } else {
290      return std::make_pair(displays_[1].id(), id_at_zero);
291    }
292  }
293}
294
295void DisplayManager::SetLayoutForCurrentDisplays(
296    const DisplayLayout& layout_relative_to_primary) {
297  DCHECK_EQ(2U, GetNumDisplays());
298  if (GetNumDisplays() < 2)
299    return;
300  const gfx::Display& primary = Shell::GetScreen()->GetPrimaryDisplay();
301  const DisplayIdPair pair = GetCurrentDisplayIdPair();
302  // Invert if the primary was swapped.
303  DisplayLayout to_set = pair.first == primary.id() ?
304      layout_relative_to_primary : layout_relative_to_primary.Invert();
305
306  DisplayLayout current_layout =
307      layout_store_->GetRegisteredDisplayLayout(pair);
308  if (to_set.position != current_layout.position ||
309      to_set.offset != current_layout.offset) {
310    to_set.primary_id = primary.id();
311    layout_store_->RegisterLayoutForDisplayIdPair(
312        pair.first, pair.second, to_set);
313    if (delegate_)
314      delegate_->PreDisplayConfigurationChange(false);
315    // PreDisplayConfigurationChange(false);
316    // TODO(oshima): Call UpdateDisplays instead.
317    const DisplayLayout layout = GetCurrentDisplayLayout();
318    UpdateDisplayBoundsForLayoutById(
319        layout, primary,
320        ScreenAsh::GetSecondaryDisplay().id());
321
322    //UpdateCurrentDisplayBoundsForLayout();
323    // Primary's bounds stay the same. Just notify bounds change
324    // on the secondary.
325    Shell::GetInstance()->screen()->NotifyBoundsChanged(
326        ScreenAsh::GetSecondaryDisplay());
327    if (delegate_)
328      delegate_->PostDisplayConfigurationChange();
329  }
330}
331
332const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
333  gfx::Display* display =
334      const_cast<DisplayManager*>(this)->FindDisplayForId(id);
335  return display ? *display : GetInvalidDisplay();
336}
337
338const gfx::Display& DisplayManager::FindDisplayContainingPoint(
339    const gfx::Point& point_in_screen) const {
340  for (DisplayList::const_iterator iter = displays_.begin();
341       iter != displays_.end(); ++iter) {
342    const gfx::Display& display = *iter;
343    if (display.bounds().Contains(point_in_screen))
344      return display;
345  }
346  return GetInvalidDisplay();
347}
348
349bool DisplayManager::UpdateWorkAreaOfDisplay(int64 display_id,
350                                             const gfx::Insets& insets) {
351  gfx::Display* display = FindDisplayForId(display_id);
352  DCHECK(display);
353  gfx::Rect old_work_area = display->work_area();
354  display->UpdateWorkAreaFromInsets(insets);
355  return old_work_area != display->work_area();
356}
357
358void DisplayManager::SetOverscanInsets(int64 display_id,
359                                       const gfx::Insets& insets_in_dip) {
360  display_info_[display_id].SetOverscanInsets(insets_in_dip);
361  DisplayInfoList display_info_list;
362  for (DisplayList::const_iterator iter = displays_.begin();
363       iter != displays_.end(); ++iter) {
364    display_info_list.push_back(GetDisplayInfo(iter->id()));
365  }
366  AddMirrorDisplayInfoIfAny(&display_info_list);
367  UpdateDisplays(display_info_list);
368}
369
370void DisplayManager::SetDisplayRotation(int64 display_id,
371                                        gfx::Display::Rotation rotation) {
372  DisplayInfoList display_info_list;
373  for (DisplayList::const_iterator iter = displays_.begin();
374       iter != displays_.end(); ++iter) {
375    DisplayInfo info = GetDisplayInfo(iter->id());
376    if (info.id() == display_id) {
377      if (info.rotation() == rotation)
378        return;
379      info.set_rotation(rotation);
380    }
381    display_info_list.push_back(info);
382  }
383  AddMirrorDisplayInfoIfAny(&display_info_list);
384  if (virtual_keyboard_root_window_enabled() &&
385      display_id == non_desktop_display_.id()) {
386    DisplayInfo info = GetDisplayInfo(display_id);
387    info.set_rotation(rotation);
388    display_info_list.push_back(info);
389  }
390  UpdateDisplays(display_info_list);
391}
392
393void DisplayManager::SetDisplayUIScale(int64 display_id,
394                                       float ui_scale) {
395  if (!IsDisplayUIScalingEnabled() ||
396      gfx::Display::InternalDisplayId() != display_id) {
397    return;
398  }
399
400  DisplayInfoList display_info_list;
401  for (DisplayList::const_iterator iter = displays_.begin();
402       iter != displays_.end(); ++iter) {
403    DisplayInfo info = GetDisplayInfo(iter->id());
404    if (info.id() == display_id) {
405      if (info.configured_ui_scale() == ui_scale)
406        return;
407      std::vector<float> scales = GetScalesForDisplay(info);
408      ScaleComparator comparator(ui_scale);
409      if (std::find_if(scales.begin(), scales.end(), comparator) ==
410          scales.end()) {
411        return;
412      }
413      info.set_configured_ui_scale(ui_scale);
414    }
415    display_info_list.push_back(info);
416  }
417  AddMirrorDisplayInfoIfAny(&display_info_list);
418  UpdateDisplays(display_info_list);
419}
420
421void DisplayManager::SetDisplayResolution(int64 display_id,
422                                          const gfx::Size& resolution) {
423  DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
424  if (gfx::Display::InternalDisplayId() == display_id)
425    return;
426  const DisplayInfo& display_info = GetDisplayInfo(display_id);
427  const std::vector<Resolution>& resolutions = display_info.resolutions();
428  DCHECK_NE(0u, resolutions.size());
429  std::vector<Resolution>::const_iterator iter =
430      std::find_if(resolutions.begin(),
431                   resolutions.end(),
432                   ResolutionMatcher(resolution));
433  if (iter == resolutions.end()) {
434    LOG(WARNING) << "Unsupported resolution was requested:"
435                 << resolution.ToString();
436    return;
437  } else if (iter == resolutions.begin()) {
438    // The best resolution was set, so forget it.
439    resolutions_.erase(display_id);
440  } else {
441    resolutions_[display_id] = resolution;
442  }
443#if defined(OS_CHROMEOS) && defined(USE_X11)
444  if (base::SysInfo::IsRunningOnChromeOS())
445    Shell::GetInstance()->output_configurator()->ScheduleConfigureOutputs();
446#endif
447}
448
449void DisplayManager::RegisterDisplayProperty(
450    int64 display_id,
451    gfx::Display::Rotation rotation,
452    float ui_scale,
453    const gfx::Insets* overscan_insets,
454    const gfx::Size& resolution_in_pixels) {
455  if (display_info_.find(display_id) == display_info_.end()) {
456    display_info_[display_id] =
457        DisplayInfo(display_id, std::string(""), false);
458  }
459
460  display_info_[display_id].set_rotation(rotation);
461  // Just in case the preference file was corrupted.
462  if (0.5f <= ui_scale && ui_scale <= 2.0f)
463    display_info_[display_id].set_configured_ui_scale(ui_scale);
464  if (overscan_insets)
465    display_info_[display_id].SetOverscanInsets(*overscan_insets);
466  if (!resolution_in_pixels.IsEmpty())
467    resolutions_[display_id] = resolution_in_pixels;
468}
469
470bool DisplayManager::GetSelectedResolutionForDisplayId(
471    int64 id,
472    gfx::Size* resolution_out) const {
473  std::map<int64, gfx::Size>::const_iterator iter =
474      resolutions_.find(id);
475  if (iter == resolutions_.end())
476    return false;
477  *resolution_out = iter->second;
478  return true;
479}
480
481bool DisplayManager::IsDisplayUIScalingEnabled() const {
482  return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
483}
484
485gfx::Insets DisplayManager::GetOverscanInsets(int64 display_id) const {
486  std::map<int64, DisplayInfo>::const_iterator it =
487      display_info_.find(display_id);
488  return (it != display_info_.end()) ?
489      it->second.overscan_insets_in_dip() : gfx::Insets();
490}
491
492void DisplayManager::OnNativeDisplaysChanged(
493    const std::vector<DisplayInfo>& updated_displays) {
494  if (updated_displays.empty()) {
495    VLOG(1) << "OnNativeDisplayChanged(0): # of current displays="
496            << displays_.size();
497    // If the device is booted without display, or chrome is started
498    // without --ash-host-window-bounds on linux desktop, use the
499    // default display.
500    if (displays_.empty()) {
501      std::vector<DisplayInfo> init_displays;
502      init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
503      MaybeInitInternalDisplay(init_displays[0].id());
504      OnNativeDisplaysChanged(init_displays);
505    } else {
506      // Otherwise don't update the displays when all displays are disconnected.
507      // This happens when:
508      // - the device is idle and powerd requested to turn off all displays.
509      // - the device is suspended. (kernel turns off all displays)
510      // - the internal display's brightness is set to 0 and no external
511      //   display is connected.
512      // - the internal display's brightness is 0 and external display is
513      //   disconnected.
514      // The display will be updated when one of displays is turned on, and the
515      // display list will be updated correctly.
516    }
517    return;
518  }
519  first_display_id_ = updated_displays[0].id();
520  std::set<gfx::Point> origins;
521
522  if (updated_displays.size() == 1) {
523    VLOG(1) << "OnNativeDisplaysChanged(1):" << updated_displays[0].ToString();
524  } else {
525    VLOG(1) << "OnNativeDisplaysChanged(" << updated_displays.size()
526            << ") [0]=" << updated_displays[0].ToString()
527            << ", [1]=" << updated_displays[1].ToString();
528  }
529
530  bool internal_display_connected = false;
531  num_connected_displays_ = updated_displays.size();
532  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
533  non_desktop_display_ = gfx::Display();
534  DisplayInfoList new_display_info_list;
535  for (DisplayInfoList::const_iterator iter = updated_displays.begin();
536       iter != updated_displays.end();
537       ++iter) {
538    if (!internal_display_connected)
539      internal_display_connected = IsInternalDisplayId(iter->id());
540    // Mirrored monitors have the same origins.
541    gfx::Point origin = iter->bounds_in_native().origin();
542    if (origins.find(origin) != origins.end()) {
543      InsertAndUpdateDisplayInfo(*iter);
544      mirrored_display_id_ = iter->id();
545    } else {
546      origins.insert(origin);
547      new_display_info_list.push_back(*iter);
548    }
549  }
550  if (HasInternalDisplay() &&
551      !internal_display_connected &&
552      display_info_.find(gfx::Display::InternalDisplayId()) ==
553      display_info_.end()) {
554    DisplayInfo internal_display_info(
555        gfx::Display::InternalDisplayId(),
556        l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME),
557        false  /*Internal display must not have overscan */);
558    internal_display_info.SetBounds(gfx::Rect(0, 0, 800, 600));
559    display_info_[gfx::Display::InternalDisplayId()] = internal_display_info;
560  }
561  UpdateDisplays(new_display_info_list);
562}
563
564void DisplayManager::UpdateDisplays() {
565  DisplayInfoList display_info_list;
566  for (DisplayList::const_iterator iter = displays_.begin();
567       iter != displays_.end(); ++iter) {
568    display_info_list.push_back(GetDisplayInfo(iter->id()));
569  }
570  AddMirrorDisplayInfoIfAny(&display_info_list);
571  UpdateDisplays(display_info_list);
572}
573
574void DisplayManager::UpdateDisplays(
575    const std::vector<DisplayInfo>& updated_display_info_list) {
576#if defined(OS_WIN)
577  if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
578    DCHECK_EQ(1u, updated_display_info_list.size()) <<
579        "Multiple display test does not work on Win8 bots. Please "
580        "skip (don't disable) the test using SupportsMultipleDisplays()";
581  }
582#endif
583
584  DisplayInfoList new_display_info_list = updated_display_info_list;
585  std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor());
586  std::sort(new_display_info_list.begin(),
587            new_display_info_list.end(),
588            DisplayInfoSortFunctor());
589  DisplayList removed_displays;
590  std::vector<size_t> changed_display_indices;
591  std::vector<size_t> added_display_indices;
592
593  DisplayList::iterator curr_iter = displays_.begin();
594  DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
595
596  DisplayList new_displays;
597
598  // Use the internal display or 1st as the mirror source, then scale
599  // the root window so that it matches the external display's
600  // resolution. This is necessary in order for scaling to work while
601  // mirrored.
602  int64 non_desktop_display_id = gfx::Display::kInvalidDisplayID;
603
604  if (second_display_mode_ != EXTENDED && new_display_info_list.size() == 2) {
605    bool zero_is_source =
606        first_display_id_ == new_display_info_list[0].id() ||
607        gfx::Display::InternalDisplayId() == new_display_info_list[0].id();
608    if (second_display_mode_ == MIRRORING) {
609      mirrored_display_id_ = new_display_info_list[zero_is_source ? 1 : 0].id();
610      non_desktop_display_id = mirrored_display_id_;
611    } else {
612      // TODO(oshima|bshe): The virtual keyboard is currently assigned to
613      // the 1st display.
614      non_desktop_display_id =
615          new_display_info_list[zero_is_source ? 0 : 1].id();
616    }
617  }
618
619  while (curr_iter != displays_.end() ||
620         new_info_iter != new_display_info_list.end()) {
621    if (new_info_iter != new_display_info_list.end() &&
622        non_desktop_display_id == new_info_iter->id()) {
623      DisplayInfo info = *new_info_iter;
624      info.SetOverscanInsets(gfx::Insets());
625      InsertAndUpdateDisplayInfo(info);
626      non_desktop_display_ =
627          CreateDisplayFromDisplayInfoById(non_desktop_display_id);
628      ++new_info_iter;
629      // Remove existing external dispaly if it is going to be used as
630      // non desktop.
631      if (curr_iter != displays_.end() &&
632          curr_iter->id() == non_desktop_display_id) {
633        removed_displays.push_back(*curr_iter);
634        ++curr_iter;
635      }
636      continue;
637    }
638
639    if (curr_iter == displays_.end()) {
640      // more displays in new list.
641      added_display_indices.push_back(new_displays.size());
642      InsertAndUpdateDisplayInfo(*new_info_iter);
643      new_displays.push_back(
644          CreateDisplayFromDisplayInfoById(new_info_iter->id()));
645      ++new_info_iter;
646    } else if (new_info_iter == new_display_info_list.end()) {
647      // more displays in current list.
648      removed_displays.push_back(*curr_iter);
649      ++curr_iter;
650    } else if (curr_iter->id() == new_info_iter->id()) {
651      const gfx::Display& current_display = *curr_iter;
652      // Copy the info because |CreateDisplayFromInfo| updates the instance.
653      const DisplayInfo current_display_info =
654          GetDisplayInfo(current_display.id());
655      InsertAndUpdateDisplayInfo(*new_info_iter);
656      gfx::Display new_display =
657          CreateDisplayFromDisplayInfoById(new_info_iter->id());
658      const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
659
660      bool host_window_bounds_changed =
661          current_display_info.bounds_in_native() !=
662          new_display_info.bounds_in_native();
663
664      if (force_bounds_changed_ ||
665          host_window_bounds_changed ||
666          (current_display.device_scale_factor() !=
667           new_display.device_scale_factor()) ||
668          (current_display_info.size_in_pixel() !=
669           new_display.GetSizeInPixel()) ||
670          (current_display.rotation() != new_display.rotation())) {
671
672        changed_display_indices.push_back(new_displays.size());
673      }
674
675      new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets());
676      new_displays.push_back(new_display);
677      ++curr_iter;
678      ++new_info_iter;
679    } else if (curr_iter->id() < new_info_iter->id()) {
680      // more displays in current list between ids, which means it is deleted.
681      removed_displays.push_back(*curr_iter);
682      ++curr_iter;
683    } else {
684      // more displays in new list between ids, which means it is added.
685      added_display_indices.push_back(new_displays.size());
686      InsertAndUpdateDisplayInfo(*new_info_iter);
687      new_displays.push_back(
688          CreateDisplayFromDisplayInfoById(new_info_iter->id()));
689      ++new_info_iter;
690    }
691  }
692
693  scoped_ptr<NonDesktopDisplayUpdater> non_desktop_display_updater(
694      new NonDesktopDisplayUpdater(this, delegate_));
695
696  // Do not update |displays_| if there's nothing to be updated. Without this,
697  // it will not update the display layout, which causes the bug
698  // http://crbug.com/155948.
699  if (changed_display_indices.empty() && added_display_indices.empty() &&
700      removed_displays.empty()) {
701    return;
702  }
703  // Clear focus if the display has been removed, but don't clear focus if
704  // the destkop has been moved from one display to another
705  // (mirror -> docked, docked -> single internal).
706  bool clear_focus =
707      !removed_displays.empty() &&
708      !(removed_displays.size() == 1 && added_display_indices.size() == 1);
709  if (delegate_)
710    delegate_->PreDisplayConfigurationChange(clear_focus);
711
712  size_t updated_index;
713  if (UpdateSecondaryDisplayBoundsForLayout(&new_displays, &updated_index) &&
714      std::find(added_display_indices.begin(),
715                added_display_indices.end(),
716                updated_index) == added_display_indices.end() &&
717      std::find(changed_display_indices.begin(),
718                changed_display_indices.end(),
719                updated_index) == changed_display_indices.end()) {
720    changed_display_indices.push_back(updated_index);
721  }
722
723  displays_ = new_displays;
724
725  base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
726
727  // Temporarily add displays to be removed because display object
728  // being removed are accessed during shutting down the root.
729  displays_.insert(displays_.end(), removed_displays.begin(),
730                   removed_displays.end());
731
732  for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
733       iter != removed_displays.rend(); ++iter) {
734    Shell::GetInstance()->screen()->NotifyDisplayRemoved(displays_.back());
735    displays_.pop_back();
736  }
737  // Close the non desktop window here to avoid creating two compositor on
738  // one display.
739  if (!non_desktop_display_updater->enabled())
740    non_desktop_display_updater.reset();
741  for (std::vector<size_t>::iterator iter = added_display_indices.begin();
742       iter != added_display_indices.end(); ++iter) {
743    Shell::GetInstance()->screen()->NotifyDisplayAdded(displays_[*iter]);
744  }
745  // Create the non destkop window after all displays are added so that
746  // it can mirror the display newly added. This can happen when switching
747  // from dock mode to software mirror mode.
748  non_desktop_display_updater.reset();
749  for (std::vector<size_t>::iterator iter = changed_display_indices.begin();
750       iter != changed_display_indices.end(); ++iter) {
751    Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
752  }
753  if (delegate_)
754    delegate_->PostDisplayConfigurationChange();
755
756#if defined(USE_X11) && defined(OS_CHROMEOS)
757  if (!changed_display_indices.empty() && base::SysInfo::IsRunningOnChromeOS())
758    ui::ClearX11DefaultRootWindow();
759#endif
760}
761
762const gfx::Display& DisplayManager::GetDisplayAt(size_t index) const {
763  DCHECK_LT(index, displays_.size());
764  return displays_[index];
765}
766
767const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
768  if (GetNumDisplays() == 1)
769    return displays_[0];
770  DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
771      GetCurrentDisplayIdPair());
772  return GetDisplayForId(layout.primary_id);
773}
774
775size_t DisplayManager::GetNumDisplays() const {
776  return displays_.size();
777}
778
779bool DisplayManager::IsMirrored() const {
780  return mirrored_display_id_ != gfx::Display::kInvalidDisplayID;
781}
782
783const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
784  std::map<int64, DisplayInfo>::const_iterator iter =
785      display_info_.find(display_id);
786  CHECK(iter != display_info_.end()) << display_id;
787  return iter->second;
788}
789
790std::string DisplayManager::GetDisplayNameForId(int64 id) {
791  if (id == gfx::Display::kInvalidDisplayID)
792    return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
793
794  std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(id);
795  if (iter != display_info_.end() && !iter->second.name().empty())
796    return iter->second.name();
797
798  return base::StringPrintf("Display %d", static_cast<int>(id));
799}
800
801int64 DisplayManager::GetDisplayIdForUIScaling() const {
802  // UI Scaling is effective only on internal display.
803  int64 display_id = gfx::Display::InternalDisplayId();
804#if defined(OS_WIN)
805  display_id = first_display_id();
806#endif
807  return display_id;
808}
809
810void DisplayManager::SetMirrorMode(bool mirrored) {
811  if (num_connected_displays() <= 1)
812    return;
813
814#if defined(OS_CHROMEOS)
815  if (base::SysInfo::IsRunningOnChromeOS()) {
816    chromeos::OutputState new_state = mirrored ?
817        chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED;
818    Shell::GetInstance()->output_configurator()->SetDisplayMode(new_state);
819    return;
820  }
821#endif
822  // This is fallback path to emulate mirroroing on desktop.
823  SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
824  DisplayInfoList display_info_list;
825  int count = 0;
826  for (std::map<int64, DisplayInfo>::const_iterator iter =
827           display_info_.begin();
828       count < 2; ++iter, ++count) {
829    display_info_list.push_back(GetDisplayInfo(iter->second.id()));
830  }
831  UpdateDisplays(display_info_list);
832#if defined(OS_CHROMEOS)
833  if (Shell::GetInstance()->output_configurator_animation()) {
834    Shell::GetInstance()->output_configurator_animation()->
835        StartFadeInAnimation();
836  }
837#endif
838}
839
840void DisplayManager::AddRemoveDisplay() {
841  DCHECK(!displays_.empty());
842  std::vector<DisplayInfo> new_display_info_list;
843  const DisplayInfo& first_display = GetDisplayInfo(displays_[0].id());
844  new_display_info_list.push_back(first_display);
845  // Add if there is only one display connected.
846  if (num_connected_displays() == 1) {
847    // Layout the 2nd display below the primary as with the real device.
848    gfx::Rect host_bounds = first_display.bounds_in_native();
849    new_display_info_list.push_back(DisplayInfo::CreateFromSpec(
850        base::StringPrintf(
851            "%d+%d-500x400", host_bounds.x(), host_bounds.bottom())));
852  }
853  num_connected_displays_ = new_display_info_list.size();
854  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
855  non_desktop_display_ = gfx::Display();
856  UpdateDisplays(new_display_info_list);
857}
858
859void DisplayManager::ToggleDisplayScaleFactor() {
860  DCHECK(!displays_.empty());
861  std::vector<DisplayInfo> new_display_info_list;
862  for (DisplayList::const_iterator iter = displays_.begin();
863       iter != displays_.end(); ++iter) {
864    DisplayInfo display_info = GetDisplayInfo(iter->id());
865    display_info.set_device_scale_factor(
866        display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f);
867    new_display_info_list.push_back(display_info);
868  }
869  AddMirrorDisplayInfoIfAny(&new_display_info_list);
870  UpdateDisplays(new_display_info_list);
871}
872
873#if defined(OS_CHROMEOS)
874void DisplayManager::SetSoftwareMirroring(bool enabled) {
875  // TODO(oshima|bshe): Support external display on the system
876  // that has virtual keyboard display.
877  if (second_display_mode_ == VIRTUAL_KEYBOARD)
878    return;
879  SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
880}
881#endif
882
883void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
884  second_display_mode_ = mode;
885  mirrored_display_id_ = gfx::Display::kInvalidDisplayID;
886  non_desktop_display_ = gfx::Display();
887}
888
889bool DisplayManager::UpdateDisplayBounds(int64 display_id,
890                                         const gfx::Rect& new_bounds) {
891  if (change_display_upon_host_resize_) {
892    display_info_[display_id].SetBounds(new_bounds);
893    // Don't notify observers if the mirrored window has changed.
894    if (software_mirroring_enabled() && mirrored_display_id_ == display_id)
895      return false;
896    gfx::Display* display = FindDisplayForId(display_id);
897    display->SetSize(display_info_[display_id].size_in_pixel());
898    Shell::GetInstance()->screen()->NotifyBoundsChanged(*display);
899    return true;
900  }
901  return false;
902}
903
904void DisplayManager::CreateMirrorWindowIfAny() {
905  NonDesktopDisplayUpdater updater(this, delegate_);
906}
907
908gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
909  for (DisplayList::iterator iter = displays_.begin();
910       iter != displays_.end(); ++iter) {
911    if ((*iter).id() == id)
912      return &(*iter);
913  }
914  DLOG(WARNING) << "Could not find display:" << id;
915  return NULL;
916}
917
918void DisplayManager::AddMirrorDisplayInfoIfAny(
919    std::vector<DisplayInfo>* display_info_list) {
920  if (software_mirroring_enabled() && IsMirrored())
921    display_info_list->push_back(GetDisplayInfo(mirrored_display_id_));
922}
923
924void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
925  std::map<int64, DisplayInfo>::iterator info =
926      display_info_.find(new_info.id());
927  if (info != display_info_.end())
928    info->second.Copy(new_info);
929  else {
930    display_info_[new_info.id()] = new_info;
931    display_info_[new_info.id()].set_native(false);
932  }
933  display_info_[new_info.id()].UpdateDisplaySize();
934}
935
936gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
937  DCHECK(display_info_.find(id) != display_info_.end());
938  const DisplayInfo& display_info = display_info_[id];
939
940  gfx::Display new_display(display_info.id());
941  gfx::Rect bounds_in_native(display_info.size_in_pixel());
942  float device_scale_factor = display_info.device_scale_factor();
943  if (device_scale_factor == 2.0f && display_info.configured_ui_scale() == 2.0f)
944    device_scale_factor = 1.0f;
945
946  // Simply set the origin to (0,0).  The primary display's origin is
947  // always (0,0) and the secondary display's bounds will be updated
948  // in |UpdateSecondaryDisplayBoundsForLayout| called in |UpdateDisplay|.
949  new_display.SetScaleAndBounds(
950      device_scale_factor, gfx::Rect(bounds_in_native.size()));
951  new_display.set_rotation(display_info.rotation());
952  new_display.set_touch_support(display_info.touch_support());
953  return new_display;
954}
955
956bool DisplayManager::UpdateSecondaryDisplayBoundsForLayout(
957    DisplayList* displays,
958    size_t* updated_index) const {
959  if (displays->size() != 2U)
960    return false;
961
962  int64 id_at_zero = displays->at(0).id();
963  DisplayIdPair pair =
964      (id_at_zero == first_display_id_ ||
965       id_at_zero == gfx::Display::InternalDisplayId()) ?
966      std::make_pair(id_at_zero, displays->at(1).id()) :
967      std::make_pair(displays->at(1).id(), id_at_zero) ;
968  DisplayLayout layout =
969      layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
970
971  // Ignore if a user has a old format (should be extremely rare)
972  // and this will be replaced with DCHECK.
973  if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
974    size_t primary_index, secondary_index;
975    if (displays->at(0).id() == layout.primary_id) {
976      primary_index = 0;
977      secondary_index = 1;
978    } else {
979      primary_index = 1;
980      secondary_index = 0;
981    }
982    // This function may be called before the secondary display is
983    // registered. The bounds is empty in that case and will
984    // return true.
985    gfx::Rect bounds =
986        GetDisplayForId(displays->at(secondary_index).id()).bounds();
987    UpdateDisplayBoundsForLayout(
988        layout, displays->at(primary_index), &displays->at(secondary_index));
989    *updated_index = secondary_index;
990    return bounds != displays->at(secondary_index).bounds();
991  }
992  return false;
993}
994
995// static
996void DisplayManager::UpdateDisplayBoundsForLayout(
997    const DisplayLayout& layout,
998    const gfx::Display& primary_display,
999    gfx::Display* secondary_display) {
1000  DCHECK_EQ("0,0", primary_display.bounds().origin().ToString());
1001
1002  const gfx::Rect& primary_bounds = primary_display.bounds();
1003  const gfx::Rect& secondary_bounds = secondary_display->bounds();
1004  gfx::Point new_secondary_origin = primary_bounds.origin();
1005
1006  DisplayLayout::Position position = layout.position;
1007
1008  // Ignore the offset in case the secondary display doesn't share edges with
1009  // the primary display.
1010  int offset = layout.offset;
1011  if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
1012    offset = std::min(
1013        offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
1014    offset = std::max(
1015        offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset);
1016  } else {
1017    offset = std::min(
1018        offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset);
1019    offset = std::max(
1020        offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset);
1021  }
1022  switch (position) {
1023    case DisplayLayout::TOP:
1024      new_secondary_origin.Offset(offset, -secondary_bounds.height());
1025      break;
1026    case DisplayLayout::RIGHT:
1027      new_secondary_origin.Offset(primary_bounds.width(), offset);
1028      break;
1029    case DisplayLayout::BOTTOM:
1030      new_secondary_origin.Offset(offset, primary_bounds.height());
1031      break;
1032    case DisplayLayout::LEFT:
1033      new_secondary_origin.Offset(-secondary_bounds.width(), offset);
1034      break;
1035  }
1036  gfx::Insets insets = secondary_display->GetWorkAreaInsets();
1037  secondary_display->set_bounds(
1038      gfx::Rect(new_secondary_origin, secondary_bounds.size()));
1039  secondary_display->UpdateWorkAreaFromInsets(insets);
1040}
1041
1042}  // namespace internal
1043}  // namespace ash
1044