OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "chromeos/display/output_util.h" | 5 #include "chromeos/display/output_util.h" |
6 | 6 |
7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/extensions/Xrandr.h> | 8 #include <X11/extensions/Xrandr.h> |
9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
10 | 10 |
11 #include "base/hash.h" | |
11 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
13 #include "base/sys_byteorder.h" | 14 #include "base/sys_byteorder.h" |
14 | 15 |
15 namespace chromeos { | 16 namespace chromeos { |
16 namespace { | 17 namespace { |
17 | 18 |
18 // Prefixes for the built-in displays. | 19 // Prefixes for the built-in displays. |
19 const char kInternal_LVDS[] = "LVDS"; | 20 const char kInternal_LVDS[] = "LVDS"; |
20 const char kInternal_eDP[] = "eDP"; | 21 const char kInternal_eDP[] = "eDP"; |
21 | 22 |
22 // Returns 64-bit persistent ID for the specified manufacturer's ID and | 23 // Returns 64-bit persistent ID for the specified manufacturer's ID and |
23 // product_code, and the index of the output it is connected to. | 24 // product_name, and the index of the output it is connected to. |
oshima
2013/05/21 21:53:31
keep this name consistent in the file, like produc
Jun Mukai
2013/05/22 00:28:05
Done.
| |
24 // |output_index| is used to distinguish the displays of the same type. For | 25 // |output_index| is used to distinguish the displays of the same type. For |
25 // example, swapping two identical display between two outputs will not be | 26 // example, swapping two identical display between two outputs will not be |
26 // treated as swap. The 'serial number' field in EDID isn't used here because | 27 // treated as swap. The 'serial number' field in EDID isn't used here because |
27 // it is not guaranteed to have unique number and it may have the same fixed | 28 // it is not guaranteed to have unique number and it may have the same fixed |
28 // value (like 0). | 29 // value (like 0). |
29 int64 GetID(uint16 manufacturer_id, | 30 int64 GetID(uint16 manufacturer_id, |
30 uint16 product_code, | 31 uint32 product_code, |
oshima
2013/05/21 21:53:31
ditto
Jun Mukai
2013/05/22 00:28:05
Done.
| |
31 uint8 output_index) { | 32 uint8 output_index) { |
32 return ((static_cast<int64>(manufacturer_id) << 24) | | 33 return ((static_cast<int64>(manufacturer_id) << 40) | |
33 (static_cast<int64>(product_code) << 8) | output_index); | 34 (static_cast<int64>(product_code) << 8) | output_index); |
34 } | 35 } |
35 | 36 |
36 bool IsRandRAvailable() { | 37 bool IsRandRAvailable() { |
37 int randr_version_major = 0; | 38 int randr_version_major = 0; |
38 int randr_version_minor = 0; | 39 int randr_version_minor = 0; |
39 static bool is_randr_available = XRRQueryVersion( | 40 static bool is_randr_available = XRRQueryVersion( |
40 base::MessagePumpAuraX11::GetDefaultXDisplay(), | 41 base::MessagePumpAuraX11::GetDefaultXDisplay(), |
41 &randr_version_major, &randr_version_minor); | 42 &randr_version_major, &randr_version_minor); |
42 return is_randr_available; | 43 return is_randr_available; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 | 113 |
113 } // namespace | 114 } // namespace |
114 | 115 |
115 std::string GetDisplayName(XID output_id) { | 116 std::string GetDisplayName(XID output_id) { |
116 std::string display_name; | 117 std::string display_name; |
117 GetOutputDeviceData(output_id, NULL, NULL, &display_name); | 118 GetOutputDeviceData(output_id, NULL, NULL, &display_name); |
118 return display_name; | 119 return display_name; |
119 } | 120 } |
120 | 121 |
121 bool GetDisplayId(XID output_id, size_t output_index, int64* display_id_out) { | 122 bool GetDisplayId(XID output_id, size_t output_index, int64* display_id_out) { |
123 unsigned long nitems = 0; | |
124 unsigned char* prop = NULL; | |
125 if (!GetEDIDProperty(output_id, &nitems, &prop)) | |
126 return false; | |
127 | |
128 bool result = | |
129 GetDisplayIdFromEDID(prop, nitems, output_index, display_id_out); | |
130 XFree(prop); | |
131 return result; | |
132 } | |
133 | |
134 bool GetDisplayIdFromEDID(const unsigned char* prop, | |
135 unsigned long nitems, | |
136 size_t output_index, | |
137 int64* display_id_out) { | |
122 uint16 manufacturer_id = 0; | 138 uint16 manufacturer_id = 0; |
123 uint16 product_code = 0; | 139 uint16 product_code = 0; |
124 if (GetOutputDeviceData( | 140 std::string product_name; |
125 output_id, &manufacturer_id, &product_code, NULL) && | 141 |
126 manufacturer_id != 0) { | 142 // ParseOutputDeviceData fails if it doesn't have product_name. |
143 ParseOutputDeviceData( | |
144 prop, nitems, &manufacturer_id, &product_code, &product_name); | |
145 | |
146 // Generates product specific value from product_name. See crbug.com/240341 | |
147 // for why we use product name string instead of product code in EDID. Use | |
148 // fallback value to 0 instead of product code just in case that the code | |
149 // over-classify a device. | |
150 // TODO(mukai): fix the code when we encounter a vendor which doesn't put | |
151 // display name but distinguish them by product code. | |
oshima
2013/05/21 21:53:31
Actually, we can't use product code because we kno
Jun Mukai
2013/05/22 00:28:05
Done.
| |
152 uint32 product_specific_code = product_name.empty() ? | |
153 0 : base::Hash(product_name); | |
154 if (manufacturer_id != 0) { | |
127 // An ID based on display's index will be assigned later if this call | 155 // An ID based on display's index will be assigned later if this call |
128 // fails. | 156 // fails. |
129 *display_id_out = GetID(manufacturer_id, product_code, output_index); | 157 *display_id_out = GetID( |
158 manufacturer_id, product_specific_code, output_index); | |
130 return true; | 159 return true; |
131 } | 160 } |
132 return false; | 161 return false; |
133 } | 162 } |
134 | 163 |
135 bool ParseOutputDeviceData(const unsigned char* prop, | 164 bool ParseOutputDeviceData(const unsigned char* prop, |
136 unsigned long nitems, | 165 unsigned long nitems, |
137 uint16* manufacturer_id, | 166 uint16* manufacturer_id, |
138 uint16* product_code, | 167 uint16* product_code, |
oshima
2013/05/21 21:53:31
and if that's the case, we no longer need to parse
Jun Mukai
2013/05/22 00:28:05
Done.
| |
139 std::string* human_readable_name) { | 168 std::string* human_readable_name) { |
140 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 169 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
141 // for the details of EDID data format. We use the following data: | 170 // for the details of EDID data format. We use the following data: |
142 // bytes 8-9: manufacturer EISA ID, in big-endian | 171 // bytes 8-9: manufacturer EISA ID, in big-endian |
143 // bytes 10-11: represents product code, in little-endian | 172 // bytes 10-11: represents product code, in little-endian |
144 // bytes 54-125: four descriptors (18-bytes each) which may contain | 173 // bytes 54-125: four descriptors (18-bytes each) which may contain |
145 // the display name. | 174 // the display name. |
146 const unsigned int kManufacturerOffset = 8; | 175 const unsigned int kManufacturerOffset = 8; |
147 const unsigned int kManufacturerLength = 2; | 176 const unsigned int kManufacturerLength = 2; |
148 const unsigned int kProductCodeOffset = 10; | 177 const unsigned int kProductCodeOffset = 10; |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 } | 339 } |
311 | 340 |
312 return false; | 341 return false; |
313 } | 342 } |
314 | 343 |
315 bool IsInternalOutputName(const std::string& name) { | 344 bool IsInternalOutputName(const std::string& name) { |
316 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; | 345 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; |
317 } | 346 } |
318 | 347 |
319 } // namespace chromeos | 348 } // namespace chromeos |
OLD | NEW |