Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/events/platform/x11/x11_hotplug_event_handler.h" | 5 #include "ui/events/platform/x11/x11_hotplug_event_handler.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | |
| 7 #include <X11/extensions/XInput.h> | 8 #include <X11/extensions/XInput.h> |
| 8 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
| 9 | 10 |
| 10 #include <algorithm> | 11 #include <algorithm> |
| 11 #include <cmath> | 12 #include <cmath> |
| 12 #include <set> | 13 #include <set> |
| 13 #include <string> | 14 #include <string> |
| 14 #include <vector> | 15 #include <vector> |
| 15 | 16 |
| 17 #include "base/bind.h" | |
| 16 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 19 #include "base/location.h" | |
| 17 #include "base/logging.h" | 20 #include "base/logging.h" |
| 18 #include "base/process/launch.h" | 21 #include "base/process/launch.h" |
| 22 #include "base/single_thread_task_runner.h" | |
| 19 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 20 #include "base/sys_info.h" | 24 #include "base/sys_info.h" |
| 25 #include "base/thread_task_runner_handle.h" | |
| 26 #include "base/threading/worker_pool.h" | |
| 27 #include "ui/events/devices/device_data_manager.h" | |
| 21 #include "ui/events/devices/device_hotplug_event_observer.h" | 28 #include "ui/events/devices/device_hotplug_event_observer.h" |
| 22 #include "ui/events/devices/device_util_linux.h" | 29 #include "ui/events/devices/device_util_linux.h" |
| 23 #include "ui/events/devices/input_device.h" | 30 #include "ui/events/devices/input_device.h" |
| 24 #include "ui/events/devices/keyboard_device.h" | 31 #include "ui/events/devices/keyboard_device.h" |
| 25 #include "ui/events/devices/touchscreen_device.h" | 32 #include "ui/events/devices/touchscreen_device.h" |
| 26 #include "ui/gfx/x/x11_types.h" | 33 #include "ui/gfx/x/x11_types.h" |
| 27 | 34 |
| 28 namespace ui { | 35 namespace ui { |
| 29 | 36 |
| 30 namespace { | 37 namespace { |
| 31 | 38 |
| 32 // The name of the xinput device corresponding to the AT internal keyboard. | 39 // The name of the xinput device corresponding to the AT internal keyboard. |
| 33 const char kATKeyboardName[] = "AT Translated Set 2 keyboard"; | 40 const char kATKeyboardName[] = "AT Translated Set 2 keyboard"; |
| 34 | 41 |
| 35 // The prefix of xinput devices corresponding to CrOS EC internal keyboards. | 42 // The prefix of xinput devices corresponding to CrOS EC internal keyboards. |
| 36 const char kCrosEcKeyboardPrefix[] = "cros-ec"; | 43 const char kCrosEcKeyboardPrefix[] = "cros-ec"; |
| 37 | 44 |
| 45 const char* kCachedAtomList[] = { | |
| 46 "Abs MT Position X", | |
| 47 "Abs MT Position Y", | |
|
sadrul
2014/11/12 19:29:43
Ooops. Looks like this needs a NULL at the end.
dnicoara
2014/11/12 19:46:10
Done.
Ooops, good catch!
| |
| 48 }; | |
| 49 | |
| 50 typedef base::Callback<void(const std::vector<KeyboardDevice>&)> | |
| 51 KeyboardDeviceCallback; | |
| 52 | |
| 53 typedef base::Callback<void(const std::vector<TouchscreenDevice>&)> | |
| 54 TouchscreenDeviceCallback; | |
| 55 | |
| 56 // Used for updating the state on the UI thread once device information is | |
| 57 // parsed on helper threads. | |
| 58 struct UiCallbacks { | |
| 59 KeyboardDeviceCallback keyboard_callback; | |
| 60 TouchscreenDeviceCallback touchscreen_callback; | |
| 61 }; | |
| 62 | |
| 63 // Stores a copy of the XIValuatorClassInfo values so X11 device processing can | |
| 64 // happen on a worker thread. This is needed since X11 structs are not copyable. | |
| 65 struct ValuatorClassInfo { | |
| 66 ValuatorClassInfo(const XIValuatorClassInfo& info) | |
| 67 : label(info.label), | |
| 68 max(info.max), | |
| 69 min(info.min), | |
| 70 mode(info.mode), | |
| 71 number(info.number) {} | |
| 72 | |
| 73 Atom label; | |
| 74 double max; | |
| 75 double min; | |
| 76 int mode; | |
| 77 int number; | |
| 78 }; | |
| 79 | |
| 80 // Stores a copy of the XITouchClassInfo values so X11 device processing can | |
| 81 // happen on a worker thread. This is needed since X11 structs are not copyable. | |
| 82 struct TouchClassInfo { | |
| 83 TouchClassInfo(const XITouchClassInfo& info) | |
| 84 : mode(info.mode) {} | |
| 85 | |
| 86 int mode; | |
| 87 }; | |
| 88 | |
| 89 struct DeviceInfo { | |
| 90 DeviceInfo(const XIDeviceInfo& device, const base::FilePath& path) | |
| 91 : id(device.deviceid), | |
| 92 name(device.name), | |
| 93 use(device.use), | |
| 94 enabled(device.enabled), | |
| 95 path(path) { | |
| 96 for (int i = 0; i < device.num_classes; ++i) { | |
| 97 switch (device.classes[i]->type) { | |
| 98 case XIValuatorClass: | |
| 99 valuator_class_infos.push_back(ValuatorClassInfo( | |
| 100 *reinterpret_cast<XIValuatorClassInfo*>(device.classes[i]))); | |
| 101 break; | |
| 102 #if defined(USE_XI2_MT) | |
| 103 case XITouchClass: | |
| 104 touch_class_infos.push_back(TouchClassInfo( | |
| 105 *reinterpret_cast<XITouchClassInfo*>(device.classes[i]))); | |
| 106 break; | |
| 107 #endif | |
| 108 default: | |
| 109 break; | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 // Unique device identifier. | |
| 115 int id; | |
| 116 | |
| 117 // Internal device name. | |
| 118 std::string name; | |
| 119 | |
| 120 // Device type (ie: XIMasterPointer) | |
| 121 int use; | |
| 122 | |
| 123 // Specifies if the device is enabled and can send events. | |
| 124 bool enabled; | |
| 125 | |
| 126 // Path to the actual device (ie: /dev/input/eventXX) | |
| 127 base::FilePath path; | |
| 128 | |
| 129 std::vector<ValuatorClassInfo> valuator_class_infos; | |
| 130 | |
| 131 #if defined(USE_XI2_MT) | |
| 132 std::vector<TouchClassInfo> touch_class_infos; | |
| 133 #endif | |
| 134 }; | |
| 135 | |
| 136 // X11 display cache used on worker threads. This is filled on the UI thread and | |
| 137 // passed in to the worker threads. | |
| 138 struct DisplayState { | |
| 139 Atom mt_position_x; | |
| 140 Atom mt_position_y; | |
| 141 }; | |
| 142 | |
| 38 // Returns true if |name| is the name of a known keyboard device. Note, this may | 143 // Returns true if |name| is the name of a known keyboard device. Note, this may |
| 39 // return false negatives. | 144 // return false negatives. |
| 40 bool IsKnownKeyboard(const std::string& name) { | 145 bool IsKnownKeyboard(const std::string& name) { |
| 41 std::string lower = base::StringToLowerASCII(name); | 146 std::string lower = base::StringToLowerASCII(name); |
| 42 return lower.find("keyboard") != std::string::npos; | 147 return lower.find("keyboard") != std::string::npos; |
| 43 } | 148 } |
| 44 | 149 |
| 45 // Returns true if |name| is the name of a known internal keyboard device. Note, | 150 // Returns true if |name| is the name of a known internal keyboard device. Note, |
| 46 // this may return false negatives. | 151 // this may return false negatives. |
| 47 bool IsInternalKeyboard(const std::string& name) { | 152 bool IsInternalKeyboard(const std::string& name) { |
| 48 // TODO(rsadam@): Come up with a more generic way of identifying internal | 153 // TODO(rsadam@): Come up with a more generic way of identifying internal |
| 49 // keyboards. See crbug.com/420728. | 154 // keyboards. See crbug.com/420728. |
| 50 if (name == kATKeyboardName) | 155 if (name == kATKeyboardName) |
| 51 return true; | 156 return true; |
| 52 return name.compare( | 157 return name.compare( |
| 53 0u, strlen(kCrosEcKeyboardPrefix), kCrosEcKeyboardPrefix) == 0; | 158 0u, strlen(kCrosEcKeyboardPrefix), kCrosEcKeyboardPrefix) == 0; |
| 54 } | 159 } |
| 55 | 160 |
| 56 // Returns true if |name| is the name of a known XTEST device. Note, this may | 161 // Returns true if |name| is the name of a known XTEST device. Note, this may |
| 57 // return false negatives. | 162 // return false negatives. |
| 58 bool IsTestKeyboard(const std::string& name) { | 163 bool IsTestKeyboard(const std::string& name) { |
| 59 return name.find("XTEST") != std::string::npos; | 164 return name.find("XTEST") != std::string::npos; |
| 60 } | 165 } |
| 61 | 166 |
| 62 // We consider the touchscreen to be internal if it is an I2c device. | 167 base::FilePath GetDevicePath(XDisplay* dpy, int device_id) { |
| 63 // With the device id, we can query X to get the device's dev input | 168 #if !defined(OS_CHROMEOS) |
| 64 // node eventXXX. Then we search all the dev input nodes registered | 169 return base::FilePath(); |
| 65 // by I2C devices to see if we can find eventXXX. | |
| 66 bool IsTouchscreenInternal(XDisplay* dpy, int device_id) { | |
| 67 #if !defined(CHROMEOS) | |
| 68 return false; | |
| 69 #else | 170 #else |
| 70 if (!base::SysInfo::IsRunningOnChromeOS()) | 171 if (!base::SysInfo::IsRunningOnChromeOS()) |
| 71 return false; | 172 return base::FilePath(); |
| 72 #endif | 173 #endif |
| 73 | 174 |
| 74 // Input device has a property "Device Node" pointing to its dev input node, | 175 // Input device has a property "Device Node" pointing to its dev input node, |
| 75 // e.g. Device Node (250): "/dev/input/event8" | 176 // e.g. Device Node (250): "/dev/input/event8" |
| 76 Atom device_node = XInternAtom(dpy, "Device Node", False); | 177 Atom device_node = XInternAtom(dpy, "Device Node", False); |
| 77 if (device_node == None) | 178 if (device_node == None) |
| 78 return false; | 179 return base::FilePath(); |
| 79 | 180 |
| 80 Atom actual_type; | 181 Atom actual_type; |
| 81 int actual_format; | 182 int actual_format; |
| 82 unsigned long nitems, bytes_after; | 183 unsigned long nitems, bytes_after; |
| 83 unsigned char* data; | 184 unsigned char* data; |
| 84 XDevice* dev = XOpenDevice(dpy, device_id); | 185 XDevice* dev = XOpenDevice(dpy, device_id); |
| 85 if (!dev) | 186 if (!dev) |
| 86 return false; | 187 return base::FilePath(); |
| 87 | 188 |
| 88 if (XGetDeviceProperty(dpy, | 189 if (XGetDeviceProperty(dpy, |
| 89 dev, | 190 dev, |
| 90 device_node, | 191 device_node, |
| 91 0, | 192 0, |
| 92 1000, | 193 1000, |
| 93 False, | 194 False, |
| 94 AnyPropertyType, | 195 AnyPropertyType, |
| 95 &actual_type, | 196 &actual_type, |
| 96 &actual_format, | 197 &actual_format, |
| 97 &nitems, | 198 &nitems, |
| 98 &bytes_after, | 199 &bytes_after, |
| 99 &data) != Success) { | 200 &data) != Success) { |
| 100 XCloseDevice(dpy, dev); | 201 XCloseDevice(dpy, dev); |
| 101 return false; | 202 return base::FilePath(); |
| 102 } | 203 } |
| 103 base::FilePath dev_node_path(reinterpret_cast<char*>(data)); | 204 |
| 205 std::string path; | |
| 206 // Make sure the returned value is a string. | |
| 207 if (actual_type == XA_STRING && actual_format == 8) | |
| 208 path = reinterpret_cast<char*>(data); | |
| 209 | |
| 104 XFree(data); | 210 XFree(data); |
| 105 XCloseDevice(dpy, dev); | 211 XCloseDevice(dpy, dev); |
| 106 | 212 |
| 107 return ui::IsTouchscreenInternal(dev_node_path); | 213 return base::FilePath(path); |
| 108 } | 214 } |
| 109 | 215 |
| 110 } // namespace | 216 // Helper used to parse keyboard information. When it is done it uses |
| 111 | 217 // |reply_runner| and |callback| to update the state on the UI thread. |
| 112 X11HotplugEventHandler::X11HotplugEventHandler( | 218 void HandleKeyboardDevicesInWorker( |
| 113 DeviceHotplugEventObserver* delegate) | 219 const std::vector<DeviceInfo>& device_infos, |
| 114 : delegate_(delegate) { | 220 scoped_refptr<base::TaskRunner> reply_runner, |
| 115 } | 221 const KeyboardDeviceCallback& callback) { |
| 116 | |
| 117 X11HotplugEventHandler::~X11HotplugEventHandler() { | |
| 118 } | |
| 119 | |
| 120 void X11HotplugEventHandler::OnHotplugEvent() { | |
| 121 const XIDeviceList& device_list = | |
| 122 DeviceListCacheX11::GetInstance()->GetXI2DeviceList(gfx::GetXDisplay()); | |
| 123 HandleTouchscreenDevices(device_list); | |
| 124 HandleKeyboardDevices(device_list); | |
| 125 } | |
| 126 | |
| 127 void X11HotplugEventHandler::HandleKeyboardDevices( | |
| 128 const XIDeviceList& x11_devices) { | |
| 129 std::vector<KeyboardDevice> devices; | 222 std::vector<KeyboardDevice> devices; |
| 130 | 223 |
| 131 for (int i = 0; i < x11_devices.count; i++) { | 224 for (const DeviceInfo& device_info : device_infos) { |
| 132 if (!x11_devices[i].enabled || x11_devices[i].use != XISlaveKeyboard) | 225 if (!device_info.enabled || device_info.use != XISlaveKeyboard) |
| 133 continue; // Assume all keyboards are keyboard slaves | 226 continue; // Assume all keyboards are keyboard slaves |
| 134 std::string device_name(x11_devices[i].name); | 227 std::string device_name(device_info.name); |
| 135 base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name); | 228 base::TrimWhitespaceASCII(device_name, base::TRIM_TRAILING, &device_name); |
| 136 if (IsTestKeyboard(device_name)) | 229 if (IsTestKeyboard(device_name)) |
| 137 continue; // Skip test devices. | 230 continue; // Skip test devices. |
| 138 InputDeviceType type; | 231 InputDeviceType type; |
| 139 if (IsInternalKeyboard(device_name)) { | 232 if (IsInternalKeyboard(device_name)) { |
| 140 type = InputDeviceType::INPUT_DEVICE_INTERNAL; | 233 type = InputDeviceType::INPUT_DEVICE_INTERNAL; |
| 141 } else if (IsKnownKeyboard(device_name)) { | 234 } else if (IsKnownKeyboard(device_name)) { |
| 142 type = InputDeviceType::INPUT_DEVICE_EXTERNAL; | 235 type = InputDeviceType::INPUT_DEVICE_EXTERNAL; |
| 143 } else { | 236 } else { |
| 144 type = InputDeviceType::INPUT_DEVICE_UNKNOWN; | 237 type = InputDeviceType::INPUT_DEVICE_UNKNOWN; |
| 145 } | 238 } |
| 146 devices.push_back( | 239 devices.push_back( |
| 147 KeyboardDevice(x11_devices[i].deviceid, type, device_name)); | 240 KeyboardDevice(device_info.id, type, device_name)); |
| 148 } | 241 } |
| 149 delegate_->OnKeyboardDevicesUpdated(devices); | 242 |
| 243 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); | |
| 150 } | 244 } |
| 151 | 245 |
| 152 void X11HotplugEventHandler::HandleTouchscreenDevices( | 246 // Helper used to parse touchscreen information. When it is done it uses |
| 153 const XIDeviceList& x11_devices) { | 247 // |reply_runner| and |callback| to update the state on the UI thread. |
| 248 void HandleTouchscreenDevicesInWorker( | |
| 249 const std::vector<DeviceInfo>& device_infos, | |
| 250 const DisplayState& display_state, | |
| 251 scoped_refptr<base::TaskRunner> reply_runner, | |
| 252 const TouchscreenDeviceCallback& callback) { | |
| 154 std::vector<TouchscreenDevice> devices; | 253 std::vector<TouchscreenDevice> devices; |
| 155 Display* display = gfx::GetXDisplay(); | 254 if (display_state.mt_position_x == None || |
| 156 Atom valuator_x = XInternAtom(display, "Abs MT Position X", False); | 255 display_state.mt_position_y == None) |
| 157 Atom valuator_y = XInternAtom(display, "Abs MT Position Y", False); | |
| 158 if (valuator_x == None || valuator_y == None) | |
| 159 return; | 256 return; |
| 160 | 257 |
| 161 std::set<int> no_match_touchscreen; | 258 std::set<int> no_match_touchscreen; |
| 162 for (int i = 0; i < x11_devices.count; i++) { | 259 for (const DeviceInfo& device_info : device_infos) { |
| 163 if (!x11_devices[i].enabled || x11_devices[i].use != XIFloatingSlave) | 260 if (!device_info.enabled || device_info.use != XIFloatingSlave) |
| 164 continue; // Assume all touchscreens are floating slaves | 261 continue; // Assume all touchscreens are floating slaves |
| 165 | 262 |
| 166 double max_x = -1.0; | 263 double max_x = -1.0; |
| 167 double max_y = -1.0; | 264 double max_y = -1.0; |
| 168 bool is_direct_touch = false; | 265 bool is_direct_touch = false; |
| 169 | 266 |
| 170 for (int j = 0; j < x11_devices[i].num_classes; j++) { | 267 for (const ValuatorClassInfo& valuator : device_info.valuator_class_infos) { |
| 171 XIAnyClassInfo* class_info = x11_devices[i].classes[j]; | 268 if (display_state.mt_position_x == valuator.label) { |
| 172 | 269 // Ignore X axis valuator with unexpected properties |
| 173 if (class_info->type == XIValuatorClass) { | 270 if (valuator.number == 0 && valuator.mode == Absolute && |
| 174 XIValuatorClassInfo* valuator_info = | 271 valuator.min == 0.0) { |
| 175 reinterpret_cast<XIValuatorClassInfo*>(class_info); | 272 max_x = valuator.max; |
| 176 | 273 } |
| 177 if (valuator_x == valuator_info->label) { | 274 } else if (display_state.mt_position_y == valuator.label) { |
| 178 // Ignore X axis valuator with unexpected properties | 275 // Ignore Y axis valuator with unexpected properties |
| 179 if (valuator_info->number == 0 && valuator_info->mode == Absolute && | 276 if (valuator.number == 1 && valuator.mode == Absolute && |
| 180 valuator_info->min == 0.0) { | 277 valuator.min == 0.0) { |
| 181 max_x = valuator_info->max; | 278 max_y = valuator.max; |
| 182 } | |
| 183 } else if (valuator_y == valuator_info->label) { | |
| 184 // Ignore Y axis valuator with unexpected properties | |
| 185 if (valuator_info->number == 1 && valuator_info->mode == Absolute && | |
| 186 valuator_info->min == 0.0) { | |
| 187 max_y = valuator_info->max; | |
| 188 } | |
| 189 } | 279 } |
| 190 } | 280 } |
| 281 } | |
| 282 | |
| 191 #if defined(USE_XI2_MT) | 283 #if defined(USE_XI2_MT) |
| 192 if (class_info->type == XITouchClass) { | 284 for (const TouchClassInfo& info : device_info.touch_class_infos) { |
| 193 XITouchClassInfo* touch_info = | 285 is_direct_touch = info.mode == XIDirectTouch; |
| 194 reinterpret_cast<XITouchClassInfo*>(class_info); | 286 } |
| 195 is_direct_touch = touch_info->mode == XIDirectTouch; | |
| 196 } | |
| 197 #endif | 287 #endif |
| 198 } | |
| 199 | 288 |
| 200 // Touchscreens should have absolute X and Y axes, and be direct touch | 289 // Touchscreens should have absolute X and Y axes, and be direct touch |
| 201 // devices. | 290 // devices. |
| 202 if (max_x > 0.0 && max_y > 0.0 && is_direct_touch) { | 291 if (max_x > 0.0 && max_y > 0.0 && is_direct_touch) { |
| 203 InputDeviceType type = | 292 InputDeviceType type = IsTouchscreenInternal(device_info.path) |
| 204 IsTouchscreenInternal(display, x11_devices[i].deviceid) | |
| 205 ? InputDeviceType::INPUT_DEVICE_INTERNAL | 293 ? InputDeviceType::INPUT_DEVICE_INTERNAL |
| 206 : InputDeviceType::INPUT_DEVICE_EXTERNAL; | 294 : InputDeviceType::INPUT_DEVICE_EXTERNAL; |
| 207 std::string name(x11_devices[i].name); | |
| 208 // |max_x| and |max_y| are inclusive values, so we need to add 1 to get | 295 // |max_x| and |max_y| are inclusive values, so we need to add 1 to get |
| 209 // the size. | 296 // the size. |
| 210 devices.push_back(TouchscreenDevice( | 297 devices.push_back(TouchscreenDevice( |
| 211 x11_devices[i].deviceid, | 298 device_info.id, |
| 212 type, | 299 type, |
| 213 name, | 300 device_info.name, |
| 214 gfx::Size(max_x + 1, max_y + 1))); | 301 gfx::Size(max_x + 1, max_y + 1))); |
| 215 } | 302 } |
| 216 } | 303 } |
| 217 | 304 |
| 218 delegate_->OnTouchscreenDevicesUpdated(devices); | 305 reply_runner->PostTask(FROM_HERE, base::Bind(callback, devices)); |
| 306 } | |
| 307 | |
| 308 // Called on a worker thread to parse the device information. | |
| 309 void HandleHotplugEventInWorker( | |
| 310 const std::vector<DeviceInfo>& devices, | |
| 311 const DisplayState& display_state, | |
| 312 scoped_refptr<base::TaskRunner> reply_runner, | |
| 313 const UiCallbacks& callbacks) { | |
| 314 HandleTouchscreenDevicesInWorker( | |
| 315 devices, display_state, reply_runner, callbacks.touchscreen_callback); | |
| 316 HandleKeyboardDevicesInWorker( | |
| 317 devices, reply_runner, callbacks.keyboard_callback); | |
| 318 } | |
| 319 | |
| 320 DeviceHotplugEventObserver* GetHotplugEventObserver() { | |
| 321 return DeviceDataManager::GetInstance(); | |
| 322 } | |
| 323 | |
| 324 void OnKeyboardDevices(const std::vector<KeyboardDevice>& devices) { | |
| 325 GetHotplugEventObserver()->OnKeyboardDevicesUpdated(devices); | |
| 326 } | |
| 327 | |
| 328 void OnTouchscreenDevices(const std::vector<TouchscreenDevice>& devices) { | |
| 329 GetHotplugEventObserver()->OnTouchscreenDevicesUpdated(devices); | |
| 330 } | |
| 331 | |
| 332 } // namespace | |
| 333 | |
| 334 X11HotplugEventHandler::X11HotplugEventHandler() | |
| 335 : atom_cache_(gfx::GetXDisplay(), kCachedAtomList) { | |
| 336 } | |
| 337 | |
| 338 X11HotplugEventHandler::~X11HotplugEventHandler() { | |
| 339 } | |
| 340 | |
| 341 void X11HotplugEventHandler::OnHotplugEvent() { | |
| 342 const XIDeviceList& device_list = | |
| 343 DeviceListCacheX11::GetInstance()->GetXI2DeviceList(gfx::GetXDisplay()); | |
| 344 Display* display = gfx::GetXDisplay(); | |
| 345 | |
| 346 std::vector<DeviceInfo> device_infos; | |
| 347 for (int i = 0; i < device_list.count; ++i) | |
| 348 device_infos.push_back(DeviceInfo( | |
| 349 device_list[i], GetDevicePath(display, device_list[i].deviceid))); | |
| 350 | |
| 351 // X11 is not thread safe, so first get all the required state. | |
| 352 DisplayState display_state; | |
| 353 display_state.mt_position_x = atom_cache_.GetAtom("Abs MT Position X"); | |
| 354 display_state.mt_position_y = atom_cache_.GetAtom("Abs MT Position Y"); | |
| 355 | |
| 356 UiCallbacks callbacks; | |
| 357 callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices); | |
| 358 callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices); | |
| 359 | |
| 360 // Parsing the device information may block, so delegate the operation to a | |
| 361 // worker thread. Once the device information is extracted the parsed devices | |
| 362 // will be returned via the callbacks. | |
| 363 base::WorkerPool::PostTask(FROM_HERE, | |
| 364 base::Bind(&HandleHotplugEventInWorker, | |
| 365 device_infos, | |
| 366 display_state, | |
| 367 base::ThreadTaskRunnerHandle::Get(), | |
| 368 callbacks), | |
| 369 true /* task_is_slow */); | |
| 219 } | 370 } |
| 220 | 371 |
| 221 } // namespace ui | 372 } // namespace ui |
| OLD | NEW |