display_change_observer_chromeos.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
1// Copyright 2013 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_change_observer_chromeos.h"
6
7#include <algorithm>
8#include <map>
9#include <set>
10#include <vector>
11
12#include "ash/ash_switches.h"
13#include "ash/display/display_info.h"
14#include "ash/display/display_layout_store.h"
15#include "ash/display/display_manager.h"
16#include "ash/shell.h"
17#include "base/command_line.h"
18#include "base/logging.h"
19#include "grit/ash_strings.h"
20#include "ui/base/l10n/l10n_util.h"
21#include "ui/base/x/x11_util.h"
22#include "ui/compositor/dip_util.h"
23#include "ui/display/chromeos/display_mode.h"
24#include "ui/display/chromeos/display_snapshot.h"
25#include "ui/gfx/display.h"
26
27namespace ash {
28namespace internal {
29
30using ui::OutputConfigurator;
31
32namespace {
33
34// The DPI threshold to detect high density screen.
35// Higher DPI than this will use device_scale_factor=2.
36const unsigned int kHighDensityDPIThreshold = 170;
37
38// 1 inch in mm.
39const float kInchInMm = 25.4f;
40
41// Display mode list is sorted by (in descending priority):
42//  * the area in pixels.
43//  * refresh rate.
44struct DisplayModeSorter {
45  bool operator()(const DisplayMode& a, const DisplayMode& b) {
46    if (a.size.GetArea() == b.size.GetArea())
47      return (a.refresh_rate > b.refresh_rate);
48    return (a.size.GetArea() > b.size.GetArea());
49  }
50};
51
52}  // namespace
53
54// static
55std::vector<DisplayMode> DisplayChangeObserver::GetDisplayModeList(
56    const OutputConfigurator::DisplayState& output) {
57  typedef std::map<std::pair<int, int>, DisplayMode> DisplayModeMap;
58  DisplayModeMap display_mode_map;
59
60  for (std::vector<const ui::DisplayMode*>::const_iterator it =
61           output.display->modes().begin();
62       it != output.display->modes().end();
63       ++it) {
64    const ui::DisplayMode& mode_info = **it;
65    const std::pair<int, int> size(mode_info.size().width(),
66                                   mode_info.size().height());
67    const DisplayMode display_mode(mode_info.size(),
68                                   mode_info.refresh_rate(),
69                                   mode_info.is_interlaced(),
70                                   output.display->native_mode() == *it);
71
72    // Add the display mode if it isn't already present and override interlaced
73    // display modes with non-interlaced ones.
74    DisplayModeMap::iterator display_mode_it = display_mode_map.find(size);
75    if (display_mode_it == display_mode_map.end())
76      display_mode_map.insert(std::make_pair(size, display_mode));
77    else if (display_mode_it->second.interlaced && !display_mode.interlaced)
78      display_mode_it->second = display_mode;
79  }
80
81  std::vector<DisplayMode> display_mode_list;
82  for (DisplayModeMap::const_iterator iter = display_mode_map.begin();
83       iter != display_mode_map.end();
84       ++iter) {
85    display_mode_list.push_back(iter->second);
86  }
87  std::sort(
88      display_mode_list.begin(), display_mode_list.end(), DisplayModeSorter());
89  return display_mode_list;
90}
91
92DisplayChangeObserver::DisplayChangeObserver() {
93  Shell::GetInstance()->AddShellObserver(this);
94}
95
96DisplayChangeObserver::~DisplayChangeObserver() {
97  Shell::GetInstance()->RemoveShellObserver(this);
98}
99
100ui::OutputState DisplayChangeObserver::GetStateForDisplayIds(
101    const std::vector<int64>& display_ids) const {
102  CHECK_EQ(2U, display_ids.size());
103  DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]);
104  DisplayLayout layout = Shell::GetInstance()->display_manager()->
105      layout_store()->GetRegisteredDisplayLayout(pair);
106  return layout.mirrored ? ui::OUTPUT_STATE_DUAL_MIRROR :
107                           ui::OUTPUT_STATE_DUAL_EXTENDED;
108}
109
110bool DisplayChangeObserver::GetResolutionForDisplayId(int64 display_id,
111                                                      gfx::Size* size) const {
112  DisplayMode mode;
113  if (!Shell::GetInstance()->display_manager()->GetSelectedModeForDisplayId(
114           display_id, &mode))
115    return false;
116
117  *size = mode.size;
118  return true;
119}
120
121void DisplayChangeObserver::OnDisplayModeChanged(
122    const std::vector<OutputConfigurator::DisplayState>& outputs) {
123  std::vector<DisplayInfo> displays;
124  std::set<int64> ids;
125  for (size_t i = 0; i < outputs.size(); ++i) {
126    const OutputConfigurator::DisplayState& output = outputs[i];
127
128    if (output.display->type() == ui::OUTPUT_TYPE_INTERNAL &&
129        gfx::Display::InternalDisplayId() == gfx::Display::kInvalidDisplayID) {
130      gfx::Display::SetInternalDisplayId(output.display->display_id());
131    }
132
133    const ui::DisplayMode* mode_info = output.display->current_mode();
134    if (!mode_info)
135      continue;
136
137    float device_scale_factor = 1.0f;
138    if (!ui::IsXDisplaySizeBlackListed(
139            output.display->physical_size().width(),
140            output.display->physical_size().height()) &&
141        (kInchInMm * mode_info->size().width() /
142         output.display->physical_size().width()) > kHighDensityDPIThreshold) {
143      device_scale_factor = 2.0f;
144    }
145    gfx::Rect display_bounds(output.display->origin(), mode_info->size());
146
147    std::vector<DisplayMode> display_modes = GetDisplayModeList(output);
148
149    std::string name =
150        output.display->type() == ui::OUTPUT_TYPE_INTERNAL
151            ? l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) :
152              output.display->GetDisplayName();
153    if (name.empty())
154      name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
155
156    bool has_overscan = output.display->GetOverscanFlag();
157    int64 id = output.display->display_id();
158    ids.insert(id);
159
160    displays.push_back(DisplayInfo(id, name, has_overscan));
161    displays.back().set_device_scale_factor(device_scale_factor);
162    displays.back().SetBounds(display_bounds);
163    displays.back().set_native(true);
164    displays.back().set_display_modes(display_modes);
165    displays.back().set_touch_support(
166        output.touch_device_id == 0 ? gfx::Display::TOUCH_SUPPORT_UNAVAILABLE :
167                                      gfx::Display::TOUCH_SUPPORT_AVAILABLE);
168  }
169
170  // DisplayManager can be null during the boot.
171  Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays);
172}
173
174void DisplayChangeObserver::OnAppTerminating() {
175#if defined(USE_ASH)
176  // Stop handling display configuration events once the shutdown
177  // process starts. crbug.com/177014.
178  Shell::GetInstance()->output_configurator()->PrepareForExit();
179#endif
180}
181
182}  // namespace internal
183}  // namespace ash
184