Chromium Code Reviews| 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) { | |
|
Daniel Erat
2013/01/04 00:19:12
this doesn't match the name from the header, does
| |
| 1393 unsigned long nitems = 0; | |
| 1394 unsigned char *prop = NULL; | |
| 1395 if (!GetEDIDProperty(output, &nitems, &prop)) | |
| 1396 return false; | |
| 1397 | |
| 1398 bool flag = false; | |
| 1399 bool found = ParseOutputOverscanFlag(prop, nitems, &flag); | |
| 1400 XFree(prop); | |
| 1401 return found && flag; | |
| 1402 } | |
| 1403 | |
| 1404 bool ParseOutputOverscanFlag(const unsigned char* prop, | |
| 1405 unsigned long nitems, | |
| 1406 bool *flag) { | |
| 1407 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | |
| 1408 // for the extension format of EDID. Also see | |
| 1409 // http://blogimg.chinaunix.net/blog/upfile2/090903185737.pdf pg.87- | |
| 1410 // for the format of the extensions and how video capability is encoded. | |
| 1411 // - byte 0: tag. should be 02h. | |
| 1412 // - byte 1: revision. only cares revision 3 (03h). | |
| 1413 // - byte 4-: data block. | |
| 1414 const unsigned int kExtensionBase = 128; | |
| 1415 const unsigned int kExtensionSize = 128; | |
| 1416 const unsigned int kNumExtensionsOffset = 126; | |
| 1417 const unsigned int kDataBlockOffset = 4; | |
| 1418 const unsigned char kCEAExtensionTag = '\x02'; | |
| 1419 const unsigned char kExpectedExtensionRevision = '\x03'; | |
| 1420 const unsigned char kExtendedTag = 7; | |
| 1421 const unsigned char kExtendedVideoCapabilityTag = 0; | |
| 1422 const unsigned int kPTOverscan = 4; | |
| 1423 const unsigned int kITOverscan = 2; | |
| 1424 const unsigned int kCEOverscan = 0; | |
| 1425 | |
| 1426 if (nitems <= kNumExtensionsOffset) | |
| 1427 return false; | |
| 1428 | |
| 1429 unsigned char num_extensions = prop[kNumExtensionsOffset]; | |
| 1430 | |
| 1431 for (size_t i = 0; i < num_extensions; ++i) { | |
| 1432 // Skip parsing the whole extension if size is not enough. | |
| 1433 if (nitems <= kExtensionBase + (i + 1) * kExtensionSize) | |
| 1434 break; | |
| 1435 | |
| 1436 const unsigned char* extension = prop + kExtensionBase + i * kExtensionSize; | |
| 1437 unsigned char tag = extension[0]; | |
| 1438 unsigned char revision = extension[1]; | |
| 1439 if (tag != kCEAExtensionTag || revision != kExpectedExtensionRevision) | |
| 1440 continue; | |
| 1441 | |
| 1442 unsigned char timing_descriptors_start = | |
| 1443 std::min(extension[2], static_cast<unsigned char>(kExtensionSize)); | |
| 1444 const unsigned char* data_block = extension + kDataBlockOffset; | |
| 1445 while (data_block < extension + timing_descriptors_start) { | |
| 1446 // A data block is encoded as: | |
| 1447 // - byte 1 high 3 bits: tag. '07' for extended tags. | |
| 1448 // - byte 1 remaining bits: the length of data block. | |
| 1449 // - byte 2: the extended tag. '0' for video capability. | |
| 1450 // - byte 3: the capability. | |
| 1451 unsigned char tag = data_block[0] >> 5; | |
| 1452 unsigned char payload_length = data_block[0] & 0x1f; | |
| 1453 if (static_cast<unsigned long>(data_block + payload_length - prop) > | |
| 1454 nitems) | |
| 1455 break; | |
| 1456 | |
| 1457 if (tag != kExtendedTag && payload_length < 2) { | |
| 1458 data_block += payload_length + 1; | |
| 1459 continue; | |
| 1460 } | |
| 1461 | |
| 1462 unsigned char extended_tag_code = data_block[1]; | |
| 1463 if (extended_tag_code != kExtendedVideoCapabilityTag) { | |
| 1464 data_block += payload_length; | |
| 1465 continue; | |
| 1466 } | |
| 1467 | |
| 1468 // The difference between preferred, IT, and CE video formats | |
| 1469 // doesn't matter. Sets |flag| to true if any of these flags are true. | |
| 1470 if ((data_block[2] & (1 << kPTOverscan)) || | |
| 1471 (data_block[2] & (1 << kITOverscan)) || | |
| 1472 (data_block[2] & (1 << kCEOverscan))) { | |
| 1473 *flag = true; | |
| 1474 } else { | |
| 1475 *flag = false; | |
| 1476 } | |
| 1477 return true; | |
| 1478 } | |
| 1479 } | |
| 1480 | |
| 1481 return false; | |
| 1482 } | |
| 1483 | |
| 1375 std::vector<std::string> GetDisplayNames(const std::vector<XID>& output_ids) { | 1484 std::vector<std::string> GetDisplayNames(const std::vector<XID>& output_ids) { |
| 1376 std::vector<std::string> names; | 1485 std::vector<std::string> names; |
| 1377 for (size_t i = 0; i < output_ids.size(); ++i) { | 1486 for (size_t i = 0; i < output_ids.size(); ++i) { |
| 1378 std::string display_name; | 1487 std::string display_name; |
| 1379 if (GetOutputDeviceData(output_ids[i], NULL, NULL, &display_name)) | 1488 if (GetOutputDeviceData(output_ids[i], NULL, NULL, &display_name)) |
| 1380 names.push_back(display_name); | 1489 names.push_back(display_name); |
| 1381 } | 1490 } |
| 1382 return names; | 1491 return names; |
| 1383 } | 1492 } |
| 1384 | 1493 |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1721 << "request_code " << static_cast<int>(error_event.request_code) << ", " | 1830 << "request_code " << static_cast<int>(error_event.request_code) << ", " |
| 1722 << "minor_code " << static_cast<int>(error_event.minor_code) | 1831 << "minor_code " << static_cast<int>(error_event.minor_code) |
| 1723 << " (" << request_str << ")"; | 1832 << " (" << request_str << ")"; |
| 1724 } | 1833 } |
| 1725 | 1834 |
| 1726 // ---------------------------------------------------------------------------- | 1835 // ---------------------------------------------------------------------------- |
| 1727 // End of x11_util_internal.h | 1836 // End of x11_util_internal.h |
| 1728 | 1837 |
| 1729 | 1838 |
| 1730 } // namespace ui | 1839 } // namespace ui |
| OLD | NEW |