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 |