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