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 |
| 11 #include <ctype.h> |
11 #include <sys/ipc.h> | 12 #include <sys/ipc.h> |
12 #include <sys/shm.h> | 13 #include <sys/shm.h> |
13 | 14 |
14 #include <list> | 15 #include <list> |
15 #include <map> | 16 #include <map> |
16 #include <vector> | 17 #include <vector> |
17 | 18 |
| 19 #include <X11/extensions/Xrandr.h> |
| 20 #include <X11/extensions/randr.h> |
| 21 |
18 #include "base/bind.h" | 22 #include "base/bind.h" |
19 #include "base/command_line.h" | 23 #include "base/command_line.h" |
20 #include "base/logging.h" | 24 #include "base/logging.h" |
21 #include "base/memory/scoped_ptr.h" | 25 #include "base/memory/scoped_ptr.h" |
22 #include "base/memory/singleton.h" | 26 #include "base/memory/singleton.h" |
23 #include "base/message_loop.h" | 27 #include "base/message_loop.h" |
24 #include "base/string_number_conversions.h" | 28 #include "base/string_number_conversions.h" |
25 #include "base/string_util.h" | 29 #include "base/string_util.h" |
26 #include "base/stringprintf.h" | 30 #include "base/stringprintf.h" |
| 31 #include "base/sys_byteorder.h" |
27 #include "base/threading/thread.h" | 32 #include "base/threading/thread.h" |
28 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | 33 #include "ui/base/keycodes/keyboard_code_conversion_x.h" |
29 #include "ui/base/x/x11_util_internal.h" | 34 #include "ui/base/x/x11_util_internal.h" |
30 #include "ui/gfx/rect.h" | 35 #include "ui/gfx/rect.h" |
31 #include "ui/gfx/size.h" | 36 #include "ui/gfx/size.h" |
32 | 37 |
33 #if defined(OS_FREEBSD) | 38 #if defined(OS_FREEBSD) |
34 #include <sys/sysctl.h> | 39 #include <sys/sysctl.h> |
35 #include <sys/types.h> | 40 #include <sys/types.h> |
36 #endif | 41 #endif |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 } | 300 } |
296 | 301 |
297 ~XButtonMap() {} | 302 ~XButtonMap() {} |
298 | 303 |
299 unsigned char map_[256]; | 304 unsigned char map_[256]; |
300 int count_; | 305 int count_; |
301 | 306 |
302 DISALLOW_COPY_AND_ASSIGN(XButtonMap); | 307 DISALLOW_COPY_AND_ASSIGN(XButtonMap); |
303 }; | 308 }; |
304 | 309 |
| 310 bool IsRandRAvailable() { |
| 311 static bool is_randr_available = false; |
| 312 static bool is_randr_availability_cached = false; |
| 313 if (is_randr_availability_cached) |
| 314 return is_randr_available; |
| 315 |
| 316 int randr_version_major = 0; |
| 317 int randr_version_minor = 0; |
| 318 is_randr_available = XRRQueryVersion( |
| 319 GetXDisplay(), &randr_version_major, &randr_version_minor); |
| 320 is_randr_availability_cached = true; |
| 321 return is_randr_available; |
| 322 } |
| 323 |
305 } // namespace | 324 } // namespace |
306 | 325 |
307 bool XDisplayExists() { | 326 bool XDisplayExists() { |
308 return (GetXDisplay() != NULL); | 327 return (GetXDisplay() != NULL); |
309 } | 328 } |
310 | 329 |
311 Display* GetXDisplay() { | 330 Display* GetXDisplay() { |
312 return base::MessagePumpForUI::GetDefaultXDisplay(); | 331 return base::MessagePumpForUI::GetDefaultXDisplay(); |
313 } | 332 } |
314 | 333 |
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
980 } | 999 } |
981 | 1000 |
982 void FreePicture(Display* display, XID picture) { | 1001 void FreePicture(Display* display, XID picture) { |
983 XRenderFreePicture(display, picture); | 1002 XRenderFreePicture(display, picture); |
984 } | 1003 } |
985 | 1004 |
986 void FreePixmap(Display* display, XID pixmap) { | 1005 void FreePixmap(Display* display, XID pixmap) { |
987 XFreePixmap(display, pixmap); | 1006 XFreePixmap(display, pixmap); |
988 } | 1007 } |
989 | 1008 |
| 1009 bool GetOutputDeviceHandles(std::vector<XID>* outputs) { |
| 1010 DCHECK(outputs); |
| 1011 outputs->clear(); |
| 1012 |
| 1013 if (!IsRandRAvailable()) |
| 1014 return false; |
| 1015 |
| 1016 Display* display = GetXDisplay(); |
| 1017 |
| 1018 Window root_window = DefaultRootWindow(display); |
| 1019 XRRScreenResources* screen_resources = |
| 1020 XRRGetScreenResources(display, root_window); |
| 1021 for (int i = 0; i < screen_resources->noutput; ++i) |
| 1022 outputs->push_back(screen_resources->outputs[i]); |
| 1023 XRRFreeScreenResources(screen_resources); |
| 1024 return true; |
| 1025 } |
| 1026 |
| 1027 bool GetOutputDeviceData(XID output, |
| 1028 uint16* manufacturer_id, |
| 1029 uint32* serial_number, |
| 1030 std::string* human_readable_name) { |
| 1031 if (!IsRandRAvailable()) |
| 1032 return false; |
| 1033 |
| 1034 static Atom edid_property = GetAtom(RR_PROPERTY_RANDR_EDID); |
| 1035 |
| 1036 Display* display = GetXDisplay(); |
| 1037 |
| 1038 bool has_edid_property = false; |
| 1039 int num_properties = 0; |
| 1040 Atom* properties = XRRListOutputProperties(display, output, &num_properties); |
| 1041 for (int i = 0; i < num_properties; ++i) { |
| 1042 if (properties[i] == edid_property) { |
| 1043 has_edid_property = true; |
| 1044 break; |
| 1045 } |
| 1046 } |
| 1047 XFree(properties); |
| 1048 if (!has_edid_property) |
| 1049 return false; |
| 1050 |
| 1051 Atom actual_type; |
| 1052 int actual_format; |
| 1053 unsigned long nitems; |
| 1054 unsigned long bytes_after; |
| 1055 unsigned char *prop; |
| 1056 XRRGetOutputProperty(display, |
| 1057 output, |
| 1058 edid_property, |
| 1059 0, // offset |
| 1060 128, // length |
| 1061 false, // _delete |
| 1062 false, // pending |
| 1063 AnyPropertyType, // req_type |
| 1064 &actual_type, |
| 1065 &actual_format, |
| 1066 &nitems, |
| 1067 &bytes_after, |
| 1068 &prop); |
| 1069 DCHECK_EQ(XA_INTEGER, actual_type); |
| 1070 DCHECK_EQ(8, actual_format); |
| 1071 |
| 1072 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
| 1073 // for the details of EDID data format. We use the following data: |
| 1074 // bytes 8-9: manufacturer EISA ID, in big-endian |
| 1075 // bytes 12-15: represents serial number, in little-endian |
| 1076 // bytes 54-125: four descriptors (18-bytes each) which may contain |
| 1077 // the display name. |
| 1078 const unsigned int kManufacturerOffset = 8; |
| 1079 const unsigned int kManufacturerLength = 2; |
| 1080 const unsigned int kSerialNumberOffset = 12; |
| 1081 const unsigned int kSerialNumberLength = 4; |
| 1082 const unsigned int kDescriptorOffset = 54; |
| 1083 const unsigned int kNumDescriptors = 4; |
| 1084 const unsigned int kDescriptorLength = 18; |
| 1085 // The specifier types. |
| 1086 const unsigned char kMonitorNameDescriptor = 0xfc; |
| 1087 const unsigned char kUnspecifiedTextDescriptor = 0xfe; |
| 1088 |
| 1089 if (manufacturer_id) { |
| 1090 if (nitems < kManufacturerOffset + kManufacturerLength) { |
| 1091 XFree(prop); |
| 1092 return false; |
| 1093 } |
| 1094 *manufacturer_id = *reinterpret_cast<uint16*>(prop + kManufacturerOffset); |
| 1095 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 1096 *manufacturer_id = base::ByteSwap(*manufacturer_id); |
| 1097 #endif |
| 1098 } |
| 1099 |
| 1100 if (serial_number) { |
| 1101 if (nitems < kSerialNumberOffset + kSerialNumberLength) { |
| 1102 XFree(prop); |
| 1103 return false; |
| 1104 } |
| 1105 *serial_number = base::ByteSwapToLE32( |
| 1106 *reinterpret_cast<uint32*>(prop + kSerialNumberOffset)); |
| 1107 } |
| 1108 |
| 1109 if (!human_readable_name) { |
| 1110 XFree(prop); |
| 1111 return true; |
| 1112 } |
| 1113 |
| 1114 std::string name_candidate; |
| 1115 human_readable_name->clear(); |
| 1116 for (unsigned int i = 0; i < kNumDescriptors; ++i) { |
| 1117 if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength) { |
| 1118 break; |
| 1119 } |
| 1120 |
| 1121 unsigned char* desc_buf = prop + kDescriptorOffset + i * kDescriptorLength; |
| 1122 // If the descriptor contains the display name, it has the following |
| 1123 // structure: |
| 1124 // bytes 0-2, 4: \0 |
| 1125 // byte 3: descriptor type, defined above. |
| 1126 // bytes 5-17: text data, ending with \r, padding with spaces |
| 1127 // we should check bytes 0-2 and 4, since it may have other values in |
| 1128 // case that the descriptor contains other type of data. |
| 1129 if (desc_buf[0] == 0 && desc_buf[1] == 0 && desc_buf[2] == 0 && |
| 1130 desc_buf[4] == 0) { |
| 1131 if (desc_buf[3] == kMonitorNameDescriptor) { |
| 1132 std::string found_name( |
| 1133 reinterpret_cast<char*>(desc_buf + 5), kDescriptorLength - 5); |
| 1134 TrimWhitespaceASCII(found_name, TRIM_TRAILING, human_readable_name); |
| 1135 break; |
| 1136 } else if (desc_buf[3] == kUnspecifiedTextDescriptor && |
| 1137 name_candidate.empty()) { |
| 1138 // Sometimes the default display of a laptop device doesn't have "FC" |
| 1139 // ("Monitor name") descriptor, but has some human readable text with |
| 1140 // "FE" ("Unspecified text"). Thus here use this value as the fallback |
| 1141 // if "FC" is missing. Note that multiple descriptors may have "FE", |
| 1142 // and the first one is the monitor name. |
| 1143 std::string found_name( |
| 1144 reinterpret_cast<char*>(desc_buf + 5), kDescriptorLength - 5); |
| 1145 TrimWhitespaceASCII(found_name, TRIM_TRAILING, &name_candidate); |
| 1146 } |
| 1147 } |
| 1148 } |
| 1149 if (human_readable_name->empty() && !name_candidate.empty()) |
| 1150 *human_readable_name = name_candidate; |
| 1151 |
| 1152 XFree(prop); |
| 1153 |
| 1154 if (human_readable_name->empty()) |
| 1155 return false; |
| 1156 |
| 1157 // Verify if the |human_readable_name| consists of printable characters only. |
| 1158 for (size_t i = 0; i < human_readable_name->size(); ++i) { |
| 1159 char c = (*human_readable_name)[i]; |
| 1160 if (!isascii(c) || !isprint(c)) { |
| 1161 human_readable_name->clear(); |
| 1162 return false; |
| 1163 } |
| 1164 } |
| 1165 |
| 1166 return true; |
| 1167 } |
| 1168 |
| 1169 |
990 bool GetWindowManagerName(std::string* wm_name) { | 1170 bool GetWindowManagerName(std::string* wm_name) { |
991 DCHECK(wm_name); | 1171 DCHECK(wm_name); |
992 int wm_window = 0; | 1172 int wm_window = 0; |
993 if (!GetIntProperty(GetX11RootWindow(), | 1173 if (!GetIntProperty(GetX11RootWindow(), |
994 "_NET_SUPPORTING_WM_CHECK", | 1174 "_NET_SUPPORTING_WM_CHECK", |
995 &wm_window)) { | 1175 &wm_window)) { |
996 return false; | 1176 return false; |
997 } | 1177 } |
998 | 1178 |
999 // It's possible that a window manager started earlier in this X session left | 1179 // It's possible that a window manager started earlier in this X session left |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1278 << "request_code " << static_cast<int>(error_event.request_code) << ", " | 1458 << "request_code " << static_cast<int>(error_event.request_code) << ", " |
1279 << "minor_code " << static_cast<int>(error_event.minor_code) | 1459 << "minor_code " << static_cast<int>(error_event.minor_code) |
1280 << " (" << request_str << ")"; | 1460 << " (" << request_str << ")"; |
1281 } | 1461 } |
1282 | 1462 |
1283 // ---------------------------------------------------------------------------- | 1463 // ---------------------------------------------------------------------------- |
1284 // End of x11_util_internal.h | 1464 // End of x11_util_internal.h |
1285 | 1465 |
1286 | 1466 |
1287 } // namespace ui | 1467 } // namespace ui |
OLD | NEW |