[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / ash / display / display_change_observer_x11.cc
blobed96094c57052a43958cddbf3ca1cb7460bfdc3c
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.
5 #include "ash/display/display_change_observer_x11.h"
7 #include <algorithm>
8 #include <map>
9 #include <set>
10 #include <vector>
12 #include <X11/extensions/Xrandr.h>
14 #include "ash/display/display_manager.h"
15 #include "ash/shell.h"
16 #include "base/message_pump_aurax11.h"
17 #include "ui/base/x/x11_util.h"
18 #include "ui/compositor/dip_util.h"
19 #include "ui/gfx/display.h"
21 namespace ash {
22 namespace internal {
24 namespace {
26 // The DPI threshold to detect high density screen.
27 // Higher DPI than this will use device_scale_factor=2.
28 // Note: This value has to be kept in sync with the mouse/touchpad driver
29 // which controls mouse pointer acceleration. If you need to update this value,
30 // please update the bug (crosbug.com/31628) first and make sure that the
31 // driver will use the same value.
32 // This value also has to be kept in sync with the value in
33 // chromeos/display/output_configurator.cc. See crbug.com/130188
34 const unsigned int kHighDensityDIPThreshold = 160;
36 // 1 inch in mm.
37 const float kInchInMm = 25.4f;
39 XRRModeInfo* FindMode(XRRScreenResources* screen_resources, XID current_mode) {
40 for (int m = 0; m < screen_resources->nmode; m++) {
41 XRRModeInfo *mode = &screen_resources->modes[m];
42 if (mode->id == current_mode)
43 return mode;
45 return NULL;
48 bool CompareDisplayY(const gfx::Display& lhs, const gfx::Display& rhs) {
49 return lhs.bounds_in_pixel().y() < rhs.bounds_in_pixel().y();
52 // A list of bogus sizes in mm that X detects and should be ignored.
53 // See crbug.com/136533.
54 const unsigned long kInvalidDisplaySizeList[][2] = {
55 {160, 100},
56 {160, 90},
57 {50, 40},
58 {40, 30},
61 // Returns true if the size nifo in the output_info isn't valid
62 // and should be ignored.
63 bool ShouldIgnoreSize(XRROutputInfo *output_info) {
64 if (output_info->mm_width == 0 || output_info->mm_height == 0) {
65 LOG(WARNING) << "No display size available";
66 return true;
68 for (unsigned long i = 0 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
69 const unsigned long* size = kInvalidDisplaySizeList[i];
70 if (output_info->mm_width == size[0] && output_info->mm_height == size[1]) {
71 LOG(WARNING) << "Black listed display size detected:"
72 << size[0] << "x" << size[1];
73 return true;
76 return false;
79 } // namespace
81 DisplayChangeObserverX11::DisplayChangeObserverX11()
82 : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
83 x_root_window_(DefaultRootWindow(xdisplay_)),
84 xrandr_event_base_(0) {
85 int error_base_ignored;
86 XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
87 base::MessagePumpAuraX11::Current()->AddDispatcherForRootWindow(this);
90 DisplayChangeObserverX11::~DisplayChangeObserverX11() {
91 base::MessagePumpAuraX11::Current()->RemoveDispatcherForRootWindow(this);
94 bool DisplayChangeObserverX11::Dispatch(const base::NativeEvent& event) {
95 if (event->type - xrandr_event_base_ == RRScreenChangeNotify) {
96 NotifyDisplayChange();
98 return true;
101 void DisplayChangeObserverX11::NotifyDisplayChange() {
102 XRRScreenResources* screen_resources =
103 XRRGetScreenResources(xdisplay_, x_root_window_);
104 std::map<XID, XRRCrtcInfo*> crtc_info_map;
106 for (int c = 0; c < screen_resources->ncrtc; c++) {
107 XID crtc_id = screen_resources->crtcs[c];
108 XRRCrtcInfo *crtc_info =
109 XRRGetCrtcInfo(xdisplay_, screen_resources, crtc_id);
110 crtc_info_map[crtc_id] = crtc_info;
113 std::vector<gfx::Display> displays;
114 std::set<int> y_coords;
115 std::set<int64> ids;
116 for (int o = 0; o < screen_resources->noutput; o++) {
117 XRROutputInfo *output_info =
118 XRRGetOutputInfo(xdisplay_,
119 screen_resources,
120 screen_resources->outputs[o]);
121 if (output_info->connection != RR_Connected) {
122 XRRFreeOutputInfo(output_info);
123 continue;
125 XRRCrtcInfo* crtc_info = crtc_info_map[output_info->crtc];
126 if (!crtc_info) {
127 LOG(WARNING) << "Crtc not found for output: output=" << o;
128 continue;
130 XRRModeInfo* mode = FindMode(screen_resources, crtc_info->mode);
131 if (!mode) {
132 LOG(WARNING) << "Could not find a mode for the output: output=" << o;
133 continue;
135 // Mirrored monitors have the same y coordinates.
136 if (y_coords.find(crtc_info->y) != y_coords.end())
137 continue;
138 displays.push_back(gfx::Display());
140 float device_scale_factor = 1.0f;
141 if (!ShouldIgnoreSize(output_info) &&
142 (kInchInMm * mode->width / output_info->mm_width) >
143 kHighDensityDIPThreshold) {
144 device_scale_factor = 2.0f;
146 displays.back().SetScaleAndBounds(
147 device_scale_factor,
148 gfx::Rect(crtc_info->x, crtc_info->y, mode->width, mode->height));
150 uint16 manufacturer_id = 0;
151 uint32 serial_number = 0;
152 if (ui::GetOutputDeviceData(screen_resources->outputs[o], &manufacturer_id,
153 &serial_number, NULL) && manufacturer_id != 0) {
154 // An ID based on display's index will be assigned later if this call
155 // fails.
156 int64 new_id = gfx::Display::GetID(manufacturer_id, serial_number);
157 if (ids.find(new_id) == ids.end()) {
158 displays.back().set_id(new_id);
159 ids.insert(new_id);
163 y_coords.insert(crtc_info->y);
164 XRRFreeOutputInfo(output_info);
167 // Free all allocated resources.
168 for (std::map<XID, XRRCrtcInfo*>::const_iterator iter = crtc_info_map.begin();
169 iter != crtc_info_map.end(); ++iter) {
170 XRRFreeCrtcInfo(iter->second);
172 XRRFreeScreenResources(screen_resources);
174 // PowerManager lays out the outputs vertically. Sort them by Y
175 // coordinates.
176 std::sort(displays.begin(), displays.end(), CompareDisplayY);
177 int64 id = 0;
178 for (std::vector<gfx::Display>::iterator iter = displays.begin();
179 iter != displays.end(); ++iter) {
180 if (iter->id() == gfx::Display::kInvalidDisplayID) {
181 iter->set_id(id);
182 ++id;
185 // DisplayManager can be null during the boot.
186 Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays);
189 } // namespace internal
190 } // namespace ash