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 // This file defines utility functions for X11 (Linux only). This code has been | 5 // This file defines utility functions for X11 (Linux only). This code has been |
6 // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support | 6 // ported from XCB since we can't use XCB on Ubuntu while its 32-bit support |
7 // remains woefully incomplete. | 7 // remains woefully incomplete. |
8 | 8 |
9 #include "ui/base/x/x11_util.h" | 9 #include "ui/base/x/x11_util.h" |
10 | 10 |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 } | 324 } |
325 | 325 |
326 bool IsShapeAvailable() { | 326 bool IsShapeAvailable() { |
327 int dummy; | 327 int dummy; |
328 static bool is_shape_available = | 328 static bool is_shape_available = |
329 XShapeQueryExtension(ui::GetXDisplay(), &dummy, &dummy); | 329 XShapeQueryExtension(ui::GetXDisplay(), &dummy, &dummy); |
330 return is_shape_available; | 330 return is_shape_available; |
331 | 331 |
332 } | 332 } |
333 | 333 |
| 334 // Get the EDID data from the |output| and stores to |prop|. |nitem| will store |
| 335 // the number of characters |prop| will have. It doesn't take the ownership of |
| 336 // |prop|, so caller must release it by XFree(). |
| 337 // Returns true if EDID property is successfully obtained. Otherwise returns |
| 338 // false and does not touch |prop| and |nitems|. |
| 339 bool GetEDIDProperty(XID output, unsigned long* nitems, unsigned char** prop) { |
| 340 if (!IsRandRAvailable()) |
| 341 return false; |
| 342 |
| 343 static Atom edid_property = GetAtom(RR_PROPERTY_RANDR_EDID); |
| 344 |
| 345 Display* display = GetXDisplay(); |
| 346 |
| 347 bool has_edid_property = false; |
| 348 int num_properties = 0; |
| 349 Atom* properties = XRRListOutputProperties(display, output, &num_properties); |
| 350 for (int i = 0; i < num_properties; ++i) { |
| 351 if (properties[i] == edid_property) { |
| 352 has_edid_property = true; |
| 353 break; |
| 354 } |
| 355 } |
| 356 XFree(properties); |
| 357 if (!has_edid_property) |
| 358 return false; |
| 359 |
| 360 Atom actual_type; |
| 361 int actual_format; |
| 362 unsigned long bytes_after; |
| 363 XRRGetOutputProperty(display, |
| 364 output, |
| 365 edid_property, |
| 366 0, // offset |
| 367 128, // length |
| 368 false, // _delete |
| 369 false, // pending |
| 370 AnyPropertyType, // req_type |
| 371 &actual_type, |
| 372 &actual_format, |
| 373 nitems, |
| 374 &bytes_after, |
| 375 prop); |
| 376 DCHECK_EQ(XA_INTEGER, actual_type); |
| 377 DCHECK_EQ(8, actual_format); |
| 378 return true; |
| 379 } |
| 380 |
334 } // namespace | 381 } // namespace |
335 | 382 |
336 bool XDisplayExists() { | 383 bool XDisplayExists() { |
337 return (GetXDisplay() != NULL); | 384 return (GetXDisplay() != NULL); |
338 } | 385 } |
339 | 386 |
340 Display* GetXDisplay() { | 387 Display* GetXDisplay() { |
341 return base::MessagePumpForUI::GetDefaultXDisplay(); | 388 return base::MessagePumpForUI::GetDefaultXDisplay(); |
342 } | 389 } |
343 | 390 |
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1241 for (int i = 0; i < screen_resources->noutput; ++i) | 1288 for (int i = 0; i < screen_resources->noutput; ++i) |
1242 outputs->push_back(screen_resources->outputs[i]); | 1289 outputs->push_back(screen_resources->outputs[i]); |
1243 XRRFreeScreenResources(screen_resources); | 1290 XRRFreeScreenResources(screen_resources); |
1244 return true; | 1291 return true; |
1245 } | 1292 } |
1246 | 1293 |
1247 bool GetOutputDeviceData(XID output, | 1294 bool GetOutputDeviceData(XID output, |
1248 uint16* manufacturer_id, | 1295 uint16* manufacturer_id, |
1249 uint32* serial_number, | 1296 uint32* serial_number, |
1250 std::string* human_readable_name) { | 1297 std::string* human_readable_name) { |
1251 if (!IsRandRAvailable()) | 1298 unsigned long nitems = 0; |
| 1299 unsigned char *prop = NULL; |
| 1300 if (!GetEDIDProperty(output, &nitems, &prop)) |
1252 return false; | 1301 return false; |
1253 | 1302 |
1254 static Atom edid_property = GetAtom(RR_PROPERTY_RANDR_EDID); | 1303 bool result = ParseOutputDeviceData( |
| 1304 prop, nitems, manufacturer_id, serial_number, human_readable_name); |
| 1305 XFree(prop); |
| 1306 return result; |
| 1307 } |
1255 | 1308 |
1256 Display* display = GetXDisplay(); | 1309 bool ParseOutputDeviceData(const unsigned char* prop, |
1257 | 1310 unsigned long nitems, |
1258 bool has_edid_property = false; | 1311 uint16* manufacturer_id, |
1259 int num_properties = 0; | 1312 uint32* serial_number, |
1260 Atom* properties = XRRListOutputProperties(display, output, &num_properties); | 1313 std::string* human_readable_name) { |
1261 for (int i = 0; i < num_properties; ++i) { | |
1262 if (properties[i] == edid_property) { | |
1263 has_edid_property = true; | |
1264 break; | |
1265 } | |
1266 } | |
1267 XFree(properties); | |
1268 if (!has_edid_property) | |
1269 return false; | |
1270 | |
1271 Atom actual_type; | |
1272 int actual_format; | |
1273 unsigned long nitems; | |
1274 unsigned long bytes_after; | |
1275 unsigned char *prop; | |
1276 XRRGetOutputProperty(display, | |
1277 output, | |
1278 edid_property, | |
1279 0, // offset | |
1280 128, // length | |
1281 false, // _delete | |
1282 false, // pending | |
1283 AnyPropertyType, // req_type | |
1284 &actual_type, | |
1285 &actual_format, | |
1286 &nitems, | |
1287 &bytes_after, | |
1288 &prop); | |
1289 DCHECK_EQ(XA_INTEGER, actual_type); | |
1290 DCHECK_EQ(8, actual_format); | |
1291 | |
1292 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 1314 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
1293 // for the details of EDID data format. We use the following data: | 1315 // for the details of EDID data format. We use the following data: |
1294 // bytes 8-9: manufacturer EISA ID, in big-endian | 1316 // bytes 8-9: manufacturer EISA ID, in big-endian |
1295 // bytes 12-15: represents serial number, in little-endian | 1317 // bytes 12-15: represents serial number, in little-endian |
1296 // bytes 54-125: four descriptors (18-bytes each) which may contain | 1318 // bytes 54-125: four descriptors (18-bytes each) which may contain |
1297 // the display name. | 1319 // the display name. |
1298 const unsigned int kManufacturerOffset = 8; | 1320 const unsigned int kManufacturerOffset = 8; |
1299 const unsigned int kManufacturerLength = 2; | 1321 const unsigned int kManufacturerLength = 2; |
1300 const unsigned int kSerialNumberOffset = 12; | 1322 const unsigned int kSerialNumberOffset = 12; |
1301 const unsigned int kSerialNumberLength = 4; | 1323 const unsigned int kSerialNumberLength = 4; |
1302 const unsigned int kDescriptorOffset = 54; | 1324 const unsigned int kDescriptorOffset = 54; |
1303 const unsigned int kNumDescriptors = 4; | 1325 const unsigned int kNumDescriptors = 4; |
1304 const unsigned int kDescriptorLength = 18; | 1326 const unsigned int kDescriptorLength = 18; |
1305 // The specifier types. | 1327 // The specifier types. |
1306 const unsigned char kMonitorNameDescriptor = 0xfc; | 1328 const unsigned char kMonitorNameDescriptor = 0xfc; |
1307 | 1329 |
1308 if (manufacturer_id) { | 1330 if (manufacturer_id) { |
1309 if (nitems < kManufacturerOffset + kManufacturerLength) { | 1331 if (nitems < kManufacturerOffset + kManufacturerLength) |
1310 XFree(prop); | |
1311 return false; | 1332 return false; |
1312 } | 1333 |
1313 *manufacturer_id = *reinterpret_cast<uint16*>(prop + kManufacturerOffset); | 1334 *manufacturer_id = |
| 1335 *reinterpret_cast<const uint16*>(prop + kManufacturerOffset); |
1314 #if defined(ARCH_CPU_LITTLE_ENDIAN) | 1336 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
1315 *manufacturer_id = base::ByteSwap(*manufacturer_id); | 1337 *manufacturer_id = base::ByteSwap(*manufacturer_id); |
1316 #endif | 1338 #endif |
1317 } | 1339 } |
1318 | 1340 |
1319 if (serial_number) { | 1341 if (serial_number) { |
1320 if (nitems < kSerialNumberOffset + kSerialNumberLength) { | 1342 if (nitems < kSerialNumberOffset + kSerialNumberLength) |
1321 XFree(prop); | |
1322 return false; | 1343 return false; |
1323 } | 1344 |
1324 *serial_number = base::ByteSwapToLE32( | 1345 *serial_number = base::ByteSwapToLE32( |
1325 *reinterpret_cast<uint32*>(prop + kSerialNumberOffset)); | 1346 *reinterpret_cast<const uint32*>(prop + kSerialNumberOffset)); |
1326 } | 1347 } |
1327 | 1348 |
1328 if (!human_readable_name) { | 1349 if (!human_readable_name) |
1329 XFree(prop); | |
1330 return true; | 1350 return true; |
1331 } | |
1332 | 1351 |
1333 human_readable_name->clear(); | 1352 human_readable_name->clear(); |
1334 for (unsigned int i = 0; i < kNumDescriptors; ++i) { | 1353 for (unsigned int i = 0; i < kNumDescriptors; ++i) { |
1335 if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength) { | 1354 if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength) |
1336 break; | 1355 break; |
1337 } | |
1338 | 1356 |
1339 unsigned char* desc_buf = prop + kDescriptorOffset + i * kDescriptorLength; | 1357 const unsigned char* desc_buf = |
| 1358 prop + kDescriptorOffset + i * kDescriptorLength; |
1340 // If the descriptor contains the display name, it has the following | 1359 // If the descriptor contains the display name, it has the following |
1341 // structure: | 1360 // structure: |
1342 // bytes 0-2, 4: \0 | 1361 // bytes 0-2, 4: \0 |
1343 // byte 3: descriptor type, defined above. | 1362 // byte 3: descriptor type, defined above. |
1344 // bytes 5-17: text data, ending with \r, padding with spaces | 1363 // bytes 5-17: text data, ending with \r, padding with spaces |
1345 // we should check bytes 0-2 and 4, since it may have other values in | 1364 // we should check bytes 0-2 and 4, since it may have other values in |
1346 // case that the descriptor contains other type of data. | 1365 // case that the descriptor contains other type of data. |
1347 if (desc_buf[0] == 0 && desc_buf[1] == 0 && desc_buf[2] == 0 && | 1366 if (desc_buf[0] == 0 && desc_buf[1] == 0 && desc_buf[2] == 0 && |
1348 desc_buf[4] == 0) { | 1367 desc_buf[4] == 0) { |
1349 if (desc_buf[3] == kMonitorNameDescriptor) { | 1368 if (desc_buf[3] == kMonitorNameDescriptor) { |
1350 std::string found_name( | 1369 std::string found_name( |
1351 reinterpret_cast<char*>(desc_buf + 5), kDescriptorLength - 5); | 1370 reinterpret_cast<const char*>(desc_buf + 5), kDescriptorLength - 5); |
1352 TrimWhitespaceASCII(found_name, TRIM_TRAILING, human_readable_name); | 1371 TrimWhitespaceASCII(found_name, TRIM_TRAILING, human_readable_name); |
1353 break; | 1372 break; |
1354 } | 1373 } |
1355 } | 1374 } |
1356 } | 1375 } |
1357 | 1376 |
1358 XFree(prop); | |
1359 | |
1360 if (human_readable_name->empty()) | 1377 if (human_readable_name->empty()) |
1361 return false; | 1378 return false; |
1362 | 1379 |
1363 // Verify if the |human_readable_name| consists of printable characters only. | 1380 // Verify if the |human_readable_name| consists of printable characters only. |
1364 for (size_t i = 0; i < human_readable_name->size(); ++i) { | 1381 for (size_t i = 0; i < human_readable_name->size(); ++i) { |
1365 char c = (*human_readable_name)[i]; | 1382 char c = (*human_readable_name)[i]; |
1366 if (!isascii(c) || !isprint(c)) { | 1383 if (!isascii(c) || !isprint(c)) { |
1367 human_readable_name->clear(); | 1384 human_readable_name->clear(); |
1368 return false; | 1385 return false; |
1369 } | 1386 } |
1370 } | 1387 } |
1371 | 1388 |
1372 return true; | 1389 return true; |
1373 } | 1390 } |
1374 | 1391 |
| 1392 bool GetOutputOverscanFlag(XID output, bool* flag) { |
| 1393 unsigned long nitems = 0; |
| 1394 unsigned char *prop = NULL; |
| 1395 if (!GetEDIDProperty(output, &nitems, &prop)) |
| 1396 return false; |
| 1397 |
| 1398 bool found = ParseOutputOverscanFlag(prop, nitems, flag); |
| 1399 XFree(prop); |
| 1400 return found; |
| 1401 } |
| 1402 |
| 1403 bool ParseOutputOverscanFlag(const unsigned char* prop, |
| 1404 unsigned long nitems, |
| 1405 bool *flag) { |
| 1406 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
| 1407 // for the extension format of EDID. Also see EIA/CEA-861 spec for |
| 1408 // the format of the extensions and how video capability is encoded. |
| 1409 // - byte 0: tag. should be 02h. |
| 1410 // - byte 1: revision. only cares revision 3 (03h). |
| 1411 // - byte 4-: data block. |
| 1412 const unsigned int kExtensionBase = 128; |
| 1413 const unsigned int kExtensionSize = 128; |
| 1414 const unsigned int kNumExtensionsOffset = 126; |
| 1415 const unsigned int kDataBlockOffset = 4; |
| 1416 const unsigned char kCEAExtensionTag = '\x02'; |
| 1417 const unsigned char kExpectedExtensionRevision = '\x03'; |
| 1418 const unsigned char kExtendedTag = 7; |
| 1419 const unsigned char kExtendedVideoCapabilityTag = 0; |
| 1420 const unsigned int kPTOverscan = 4; |
| 1421 const unsigned int kITOverscan = 2; |
| 1422 const unsigned int kCEOverscan = 0; |
| 1423 |
| 1424 if (nitems <= kNumExtensionsOffset) |
| 1425 return false; |
| 1426 |
| 1427 unsigned char num_extensions = prop[kNumExtensionsOffset]; |
| 1428 |
| 1429 for (size_t i = 0; i < num_extensions; ++i) { |
| 1430 // Skip parsing the whole extension if size is not enough. |
| 1431 if (nitems <= kExtensionBase + (i + 1) * kExtensionSize) |
| 1432 break; |
| 1433 |
| 1434 const unsigned char* extension = prop + kExtensionBase + i * kExtensionSize; |
| 1435 unsigned char tag = extension[0]; |
| 1436 unsigned char revision = extension[1]; |
| 1437 if (tag != kCEAExtensionTag || revision != kExpectedExtensionRevision) |
| 1438 continue; |
| 1439 |
| 1440 unsigned char timing_descriptors_start = |
| 1441 std::min(extension[2], static_cast<unsigned char>(kExtensionSize)); |
| 1442 const unsigned char* data_block = extension + kDataBlockOffset; |
| 1443 while (data_block < extension + timing_descriptors_start) { |
| 1444 // A data block is encoded as: |
| 1445 // - byte 1 high 3 bits: tag. '07' for extended tags. |
| 1446 // - byte 1 remaining bits: the length of data block. |
| 1447 // - byte 2: the extended tag. '0' for video capability. |
| 1448 // - byte 3: the capability. |
| 1449 unsigned char tag = data_block[0] >> 5; |
| 1450 unsigned char payload_length = data_block[0] & 0x1f; |
| 1451 if (static_cast<unsigned long>(data_block + payload_length - prop) > |
| 1452 nitems) |
| 1453 break; |
| 1454 |
| 1455 if (tag != kExtendedTag && payload_length < 2) { |
| 1456 data_block += payload_length + 1; |
| 1457 continue; |
| 1458 } |
| 1459 |
| 1460 unsigned char extended_tag_code = data_block[1]; |
| 1461 if (extended_tag_code != kExtendedVideoCapabilityTag) { |
| 1462 data_block += payload_length; |
| 1463 continue; |
| 1464 } |
| 1465 |
| 1466 // The difference between preferred, IT, and CE video formats |
| 1467 // doesn't matter. Sets |flag| to true if any of these flags are true. |
| 1468 if ((data_block[2] & (1 << kPTOverscan)) || |
| 1469 (data_block[2] & (1 << kITOverscan)) || |
| 1470 (data_block[2] & (1 << kCEOverscan))) { |
| 1471 *flag = true; |
| 1472 } else { |
| 1473 *flag = false; |
| 1474 } |
| 1475 return true; |
| 1476 } |
| 1477 } |
| 1478 |
| 1479 return false; |
| 1480 } |
| 1481 |
1375 std::vector<std::string> GetDisplayNames(const std::vector<XID>& output_ids) { | 1482 std::vector<std::string> GetDisplayNames(const std::vector<XID>& output_ids) { |
1376 std::vector<std::string> names; | 1483 std::vector<std::string> names; |
1377 for (size_t i = 0; i < output_ids.size(); ++i) { | 1484 for (size_t i = 0; i < output_ids.size(); ++i) { |
1378 std::string display_name; | 1485 std::string display_name; |
1379 if (GetOutputDeviceData(output_ids[i], NULL, NULL, &display_name)) | 1486 if (GetOutputDeviceData(output_ids[i], NULL, NULL, &display_name)) |
1380 names.push_back(display_name); | 1487 names.push_back(display_name); |
1381 } | 1488 } |
1382 return names; | 1489 return names; |
1383 } | 1490 } |
1384 | 1491 |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1721 << "request_code " << static_cast<int>(error_event.request_code) << ", " | 1828 << "request_code " << static_cast<int>(error_event.request_code) << ", " |
1722 << "minor_code " << static_cast<int>(error_event.minor_code) | 1829 << "minor_code " << static_cast<int>(error_event.minor_code) |
1723 << " (" << request_str << ")"; | 1830 << " (" << request_str << ")"; |
1724 } | 1831 } |
1725 | 1832 |
1726 // ---------------------------------------------------------------------------- | 1833 // ---------------------------------------------------------------------------- |
1727 // End of x11_util_internal.h | 1834 // End of x11_util_internal.h |
1728 | 1835 |
1729 | 1836 |
1730 } // namespace ui | 1837 } // namespace ui |
OLD | NEW |