OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/display/display_change_observer_x11.h" | 5 #include "ash/display/display_change_observer_x11.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <set> | 9 #include <set> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include <X11/extensions/Xrandr.h> | 12 #include <X11/extensions/Xrandr.h> |
13 | 13 |
14 #include "ash/ash_switches.h" | 14 #include "ash/ash_switches.h" |
15 #include "ash/display/display_info.h" | 15 #include "ash/display/display_info.h" |
16 #include "ash/display/display_layout_store.h" | 16 #include "ash/display/display_layout_store.h" |
17 #include "ash/display/display_manager.h" | 17 #include "ash/display/display_manager.h" |
| 18 #include "ash/display/display_util_x11.h" |
18 #include "ash/shell.h" | 19 #include "ash/shell.h" |
19 #include "base/command_line.h" | 20 #include "base/command_line.h" |
20 #include "base/message_loop/message_pump_aurax11.h" | 21 #include "base/message_loop/message_pump_aurax11.h" |
21 #include "chromeos/display/output_util.h" | 22 #include "chromeos/display/output_util.h" |
22 #include "grit/ash_strings.h" | 23 #include "grit/ash_strings.h" |
23 #include "ui/base/l10n/l10n_util.h" | 24 #include "ui/base/l10n/l10n_util.h" |
24 #include "ui/compositor/dip_util.h" | 25 #include "ui/compositor/dip_util.h" |
25 #include "ui/gfx/display.h" | 26 #include "ui/gfx/display.h" |
26 | 27 |
27 namespace ash { | 28 namespace ash { |
28 namespace internal { | 29 namespace internal { |
29 | |
30 namespace { | 30 namespace { |
31 | 31 |
32 // The DPI threshold to detect high density screen. | 32 // The DPI threshold to detect high density screen. |
33 // Higher DPI than this will use device_scale_factor=2. | 33 // Higher DPI than this will use device_scale_factor=2. |
34 // Note: This value has to be kept in sync with the mouse/touchpad driver | |
35 // which controls mouse pointer acceleration. If you need to update this value, | |
36 // please update the bug (crosbug.com/31628) first and make sure that the | |
37 // driver will use the same value. | |
38 // This value also has to be kept in sync with the value in | |
39 // chromeos/display/output_configurator.cc. See crbug.com/130188 | |
40 const unsigned int kHighDensityDPIThreshold = 160; | 34 const unsigned int kHighDensityDPIThreshold = 160; |
41 | 35 |
42 // 1 inch in mm. | 36 // 1 inch in mm. |
43 const float kInchInMm = 25.4f; | 37 const float kInchInMm = 25.4f; |
44 | 38 |
45 XRRModeInfo* FindMode(XRRScreenResources* screen_resources, XID current_mode) { | |
46 for (int m = 0; m < screen_resources->nmode; m++) { | |
47 XRRModeInfo *mode = &screen_resources->modes[m]; | |
48 if (mode->id == current_mode) | |
49 return mode; | |
50 } | |
51 return NULL; | |
52 } | |
53 | |
54 // A list of bogus sizes in mm that X detects and should be ignored. | |
55 // See crbug.com/136533. | |
56 const unsigned long kInvalidDisplaySizeList[][2] = { | |
57 {40, 30}, | |
58 {50, 40}, | |
59 {160, 90}, | |
60 {160, 100}, | |
61 }; | |
62 | |
63 int64 GetDisplayId(XID output, size_t output_index) { | 39 int64 GetDisplayId(XID output, size_t output_index) { |
64 int64 display_id; | 40 int64 display_id; |
65 if (chromeos::GetDisplayId(output, output_index, &display_id)) | 41 if (chromeos::GetDisplayId(output, output_index, &display_id)) |
66 return display_id; | 42 return display_id; |
67 return gfx::Display::kInvalidDisplayID; | 43 return gfx::Display::kInvalidDisplayID; |
68 } | 44 } |
69 | 45 |
70 } // namespace | 46 } // namespace |
71 | 47 |
72 bool ShouldIgnoreSize(unsigned long mm_width, unsigned long mm_height) { | |
73 // Ignore if the reported display is smaller than minimum size. | |
74 if (mm_width <= kInvalidDisplaySizeList[0][0] || | |
75 mm_height <= kInvalidDisplaySizeList[0][1]) { | |
76 LOG(WARNING) << "Smaller than minimum display size"; | |
77 return true; | |
78 } | |
79 for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) { | |
80 const unsigned long* size = kInvalidDisplaySizeList[i]; | |
81 if (mm_width == size[0] && mm_height == size[1]) { | |
82 LOG(WARNING) << "Black listed display size detected:" | |
83 << size[0] << "x" << size[1]; | |
84 return true; | |
85 } | |
86 } | |
87 return false; | |
88 } | |
89 | |
90 DisplayChangeObserverX11::DisplayChangeObserverX11() | 48 DisplayChangeObserverX11::DisplayChangeObserverX11() |
91 : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), | 49 : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), |
92 x_root_window_(DefaultRootWindow(xdisplay_)), | 50 x_root_window_(DefaultRootWindow(xdisplay_)), |
93 xrandr_event_base_(0) { | 51 xrandr_event_base_(0) { |
94 int error_base_ignored; | 52 int error_base_ignored; |
95 XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored); | 53 XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored); |
96 | 54 |
97 Shell::GetInstance()->AddShellObserver(this); | 55 Shell::GetInstance()->AddShellObserver(this); |
98 } | 56 } |
99 | 57 |
100 DisplayChangeObserverX11::~DisplayChangeObserverX11() { | 58 DisplayChangeObserverX11::~DisplayChangeObserverX11() { |
101 Shell::GetInstance()->RemoveShellObserver(this); | 59 Shell::GetInstance()->RemoveShellObserver(this); |
102 } | 60 } |
103 | 61 |
104 chromeos::OutputState DisplayChangeObserverX11::GetStateForDisplayIds( | 62 chromeos::OutputState DisplayChangeObserverX11::GetStateForDisplayIds( |
105 const std::vector<int64>& display_ids) const { | 63 const std::vector<int64>& display_ids) const { |
106 if (CommandLine::ForCurrentProcess()->HasSwitch( | 64 if (CommandLine::ForCurrentProcess()->HasSwitch( |
107 switches::kAshForceMirrorMode)) { | 65 switches::kAshForceMirrorMode)) { |
108 return chromeos::STATE_DUAL_MIRROR; | 66 return chromeos::STATE_DUAL_MIRROR; |
109 } | 67 } |
110 | 68 |
111 CHECK_EQ(2U, display_ids.size()); | 69 CHECK_EQ(2U, display_ids.size()); |
112 DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]); | 70 DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]); |
113 DisplayLayout layout = Shell::GetInstance()->display_manager()-> | 71 DisplayLayout layout = Shell::GetInstance()->display_manager()-> |
114 layout_store()->GetRegisteredDisplayLayout(pair); | 72 layout_store()->GetRegisteredDisplayLayout(pair); |
115 return layout.mirrored ? | 73 return layout.mirrored ? |
116 chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED; | 74 chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED; |
117 } | 75 } |
118 | 76 |
| 77 bool DisplayChangeObserverX11::GetResolutionForDisplayId(int64 display_id, |
| 78 int* width, |
| 79 int* height) const { |
| 80 |
| 81 gfx::Size resolution; |
| 82 if (!Shell::GetInstance()->display_manager()-> |
| 83 GetSelectedResolutionForDisplayId(display_id, &resolution)) { |
| 84 return false; |
| 85 } |
| 86 |
| 87 *width = resolution.width(); |
| 88 *height = resolution.height(); |
| 89 return true; |
| 90 } |
| 91 |
119 void DisplayChangeObserverX11::OnDisplayModeChanged() { | 92 void DisplayChangeObserverX11::OnDisplayModeChanged() { |
120 XRRScreenResources* screen_resources = | 93 XRRScreenResources* screen_resources = |
121 XRRGetScreenResources(xdisplay_, x_root_window_); | 94 XRRGetScreenResources(xdisplay_, x_root_window_); |
122 std::map<XID, XRRCrtcInfo*> crtc_info_map; | 95 std::map<XID, XRRCrtcInfo*> crtc_info_map; |
123 | 96 |
124 for (int c = 0; c < screen_resources->ncrtc; c++) { | 97 for (int c = 0; c < screen_resources->ncrtc; c++) { |
125 XID crtc_id = screen_resources->crtcs[c]; | 98 XID crtc_id = screen_resources->crtcs[c]; |
126 XRRCrtcInfo *crtc_info = | 99 XRRCrtcInfo *crtc_info = |
127 XRRGetCrtcInfo(xdisplay_, screen_resources, crtc_id); | 100 XRRGetCrtcInfo(xdisplay_, screen_resources, crtc_id); |
128 crtc_info_map[crtc_id] = crtc_info; | 101 crtc_info_map[crtc_id] = crtc_info; |
(...skipping 15 matching lines...) Expand all Loading... |
144 int64 id = GetDisplayId(output, output_index); | 117 int64 id = GetDisplayId(output, output_index); |
145 // Fallback to output index. crbug.com/180100 | 118 // Fallback to output index. crbug.com/180100 |
146 gfx::Display::SetInternalDisplayId( | 119 gfx::Display::SetInternalDisplayId( |
147 id == gfx::Display::kInvalidDisplayID ? output_index : id); | 120 id == gfx::Display::kInvalidDisplayID ? output_index : id); |
148 } | 121 } |
149 | 122 |
150 if (output_info->connection != RR_Connected) { | 123 if (output_info->connection != RR_Connected) { |
151 XRRFreeOutputInfo(output_info); | 124 XRRFreeOutputInfo(output_info); |
152 continue; | 125 continue; |
153 } | 126 } |
154 XRRCrtcInfo* crtc_info = crtc_info_map[output_info->crtc]; | 127 const XRRCrtcInfo* crtc_info = crtc_info_map[output_info->crtc]; |
155 if (!crtc_info) { | 128 if (!crtc_info) { |
156 LOG(WARNING) << "Crtc not found for output: output_index=" | 129 LOG(WARNING) << "Crtc not found for output: output_index=" |
157 << output_index; | 130 << output_index; |
158 continue; | 131 continue; |
159 } | 132 } |
160 XRRModeInfo* mode = FindMode(screen_resources, crtc_info->mode); | 133 const XRRModeInfo* mode = |
| 134 chromeos::FindModeInfo(screen_resources, crtc_info->mode); |
161 if (!mode) { | 135 if (!mode) { |
162 LOG(WARNING) << "Could not find a mode for the output: output_index=" | 136 LOG(WARNING) << "Could not find a mode for the output: output_index=" |
163 << output_index; | 137 << output_index; |
164 continue; | 138 continue; |
165 } | 139 } |
166 | 140 |
167 float device_scale_factor = 1.0f; | 141 float device_scale_factor = 1.0f; |
168 if (!ShouldIgnoreSize(output_info->mm_width, output_info->mm_height) && | 142 if (!ShouldIgnoreSize(output_info->mm_width, output_info->mm_height) && |
169 (kInchInMm * mode->width / output_info->mm_width) > | 143 (kInchInMm * mode->width / output_info->mm_width) > |
170 kHighDensityDPIThreshold) { | 144 kHighDensityDPIThreshold) { |
171 device_scale_factor = 2.0f; | 145 device_scale_factor = 2.0f; |
172 } | 146 } |
173 gfx::Rect display_bounds( | 147 gfx::Rect display_bounds( |
174 crtc_info->x, crtc_info->y, mode->width, mode->height); | 148 crtc_info->x, crtc_info->y, mode->width, mode->height); |
175 | 149 |
| 150 std::vector<Resolution> resolutions; |
| 151 if (!is_internal) |
| 152 resolutions = GetResolutionList(screen_resources, output_info); |
| 153 |
176 XRRFreeOutputInfo(output_info); | 154 XRRFreeOutputInfo(output_info); |
177 | 155 |
178 std::string name = is_internal ? | 156 std::string name = is_internal ? |
179 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) : | 157 l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) : |
180 chromeos::GetDisplayName(output); | 158 chromeos::GetDisplayName(output); |
181 if (name.empty()) | 159 if (name.empty()) |
182 name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); | 160 name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME); |
183 | 161 |
184 bool has_overscan = false; | 162 bool has_overscan = false; |
185 chromeos::GetOutputOverscanFlag(output, &has_overscan); | 163 chromeos::GetOutputOverscanFlag(output, &has_overscan); |
186 | 164 |
187 int64 id = GetDisplayId(output, output_index); | 165 int64 id = GetDisplayId(output, output_index); |
188 | 166 |
189 // If ID is invalid or there is an duplicate, just use output index. | 167 // If ID is invalid or there is an duplicate, just use output index. |
190 if (id == gfx::Display::kInvalidDisplayID || ids.find(id) != ids.end()) | 168 if (id == gfx::Display::kInvalidDisplayID || ids.find(id) != ids.end()) |
191 id = output_index; | 169 id = output_index; |
192 ids.insert(id); | 170 ids.insert(id); |
193 | 171 |
194 displays.push_back(DisplayInfo(id, name, has_overscan)); | 172 displays.push_back(DisplayInfo(id, name, has_overscan)); |
195 displays.back().set_device_scale_factor(device_scale_factor); | 173 displays.back().set_device_scale_factor(device_scale_factor); |
196 displays.back().SetBounds(display_bounds); | 174 displays.back().SetBounds(display_bounds); |
197 displays.back().set_native(true); | 175 displays.back().set_native(true); |
| 176 displays.back().set_resolutions(resolutions); |
198 } | 177 } |
199 | 178 |
200 // Free all allocated resources. | 179 // Free all allocated resources. |
201 for (std::map<XID, XRRCrtcInfo*>::const_iterator iter = crtc_info_map.begin(); | 180 for (std::map<XID, XRRCrtcInfo*>::const_iterator iter = crtc_info_map.begin(); |
202 iter != crtc_info_map.end(); ++iter) { | 181 iter != crtc_info_map.end(); ++iter) { |
203 XRRFreeCrtcInfo(iter->second); | 182 XRRFreeCrtcInfo(iter->second); |
204 } | 183 } |
205 XRRFreeScreenResources(screen_resources); | 184 XRRFreeScreenResources(screen_resources); |
206 | 185 |
207 // DisplayManager can be null during the boot. | 186 // DisplayManager can be null during the boot. |
208 Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays); | 187 Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays); |
209 } | 188 } |
210 | 189 |
211 void DisplayChangeObserverX11::OnAppTerminating() { | 190 void DisplayChangeObserverX11::OnAppTerminating() { |
212 #if defined(USE_ASH) | 191 #if defined(USE_ASH) |
213 // Stop handling display configuration events once the shutdown | 192 // Stop handling display configuration events once the shutdown |
214 // process starts. crbug.com/177014. | 193 // process starts. crbug.com/177014. |
215 Shell::GetInstance()->output_configurator()->Stop(); | 194 Shell::GetInstance()->output_configurator()->Stop(); |
216 #endif | 195 #endif |
217 } | 196 } |
218 | 197 |
219 } // namespace internal | 198 } // namespace internal |
220 } // namespace ash | 199 } // namespace ash |
OLD | NEW |