1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright 2014 The Chromium Authors. All rights reserved. 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Use of this source code is governed by a BSD-style license that can be 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file. 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "ui/events/platform/x11/x11_event_source.h" 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 7971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.com#include <X11/extensions/XInput2.h> 857f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include <X11/X.h> 957f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include <X11/Xlib.h> 1057f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include <X11/XKBlib.h> 1157f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com 1257f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include "base/logging.h" 1357f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include "ui/events/event_utils.h" 1457f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include "ui/events/platform/platform_event_dispatcher.h" 1557f7abc8659f17e58fc2d1410117033ad524f9d3epoger@google.com#include "ui/events/x/device_data_manager_x11.h" 16b29c883fb46ac6099440d82ac57b86d25386daedbungeman@google.com#include "ui/events/x/hotplug_event_handler_x11.h" 176f6568b27eae62fea23ab8192c6da02ab892bb5eepoger@google.com#include "ui/gfx/x/x11_types.h" 1837269607334b99bf814c7dc6b426745d9b7c7e3fepoger@google.com 197bc13a62609149f0b535c2f3ff7210eb834d8b36epoger@google.comnamespace ui { 205f6a00775511b5675607c2bfdbb096c0a815025depoger@google.com 21b9b9a18ab459c2616ac4a52c9f8cc0637d284229reed@android.comnamespace { 22d9ba9a05d6f5766fdb1378b6ed84c0659009a8dascroggo@google.com 238a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.comint g_xinput_opcode = -1; 244370aedf7f55af74e9ebb4ad1c2e010c08236dfajunov@google.com 25971d0c8049c6bfc7a58f0b41f8f59f9ec9ca077bbsalomon@google.combool InitializeXInput2(XDisplay* display) { 265e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org if (!display) 27de96163a80167636d95837f9ee6a2e98baf9d350epoger@google.com return false; 28c41295d1223136da4f9e4c65b7145360684ede4bcommit-bot@chromium.org 295af9b2032b552516c9223d9fb22185b022b13c62scroggo@google.com int event, err; 308015dd83ae37147bb630d4751030868051ad0caereed@android.com 318015dd83ae37147bb630d4751030868051ad0caereed@android.com int xiopcode; 328015dd83ae37147bb630d4751030868051ad0caereed@android.com if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { 33e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org DVLOG(1) << "X Input extension not available."; 34e8ebeb1f8fde6525bbab988c6090a5d3ab19855bepoger@google.com return false; 350dcbece326ce2fa1f9046aa69a21bb99de08714avandebo@chromium.org } 369875dd14af6d768da8d1a4be58b98fc91ceca0ddtomhudson@google.com g_xinput_opcode = xiopcode; 37977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com 385e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org#if defined(USE_XI2_MT) 3972c9672ce274a3b6cb40800d66374edf25b157a3scroggo@google.com // USE_XI2_MT also defines the required XI2 minor minimum version. 40f711f320a34216fc9f64839b90b99a1492c54e09epoger@google.com int major = 2, minor = USE_XI2_MT; 4111db6fa9b9fc30b1f504d9f53e0f6ae7149cc5c5reed@google.com#else 422a48c3adb7cf4fc754f99a41352210b4a99edf04bsalomon@google.com int major = 2, minor = 0; 43310478e72c63e639373465216271b81f1e4a9136epoger@google.com#endif 443cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org if (XIQueryVersion(display, &major, &minor) == BadRequest) { 4572c9672ce274a3b6cb40800d66374edf25b157a3scroggo@google.com DVLOG(1) << "XInput2 not supported in the server."; 460770044da6d61dcbc8d9673fed8dd92460faa314reed@google.com return false; 47515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org } 48515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#if defined(USE_XI2_MT) 498065ec50f1937c1562810bfe2b216abfb98362b3commit-bot@chromium.org if (major < 2 || (major == 2 && minor < USE_XI2_MT)) { 50515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org DVLOG(1) << "XI version on server is " << major << "." << minor << ". " 51515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org << "But 2." << USE_XI2_MT << " is required."; 52515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org return false; 53515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org } 54ed5eb4ef2aa1d6c705bc3ed466f9caba2a230a2bepoger@google.com#endif 55ed5eb4ef2aa1d6c705bc3ed466f9caba2a230a2bepoger@google.com 56cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com return true; 57cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com} 58cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com 59cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.combool InitializeXkb(XDisplay* display) { 606f6568b27eae62fea23ab8192c6da02ab892bb5eepoger@google.com if (!display) 616f6568b27eae62fea23ab8192c6da02ab892bb5eepoger@google.com return false; 626f6568b27eae62fea23ab8192c6da02ab892bb5eepoger@google.com 63cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com int opcode, event, error; 6480724dfeb320d1152128cd33636c9024952432d3epoger@google.com int major = XkbMajorVersion; 65cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com int minor = XkbMinorVersion; 66123ac1d4eab757052407064623643fdc59f85363bsalomon@google.com if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) { 67cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com DVLOG(1) << "Xkb extension not available."; 68cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com return false; 69cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com } 7076c913db20de7ae1baa49ae66e943bf7f40781ccepoger@google.com 7176c913db20de7ae1baa49ae66e943bf7f40781ccepoger@google.com // Ask the server not to send KeyRelease event when the user holds down a key. 728923c6cfd580ac9accb11b909fa2a033d69553aareed@google.com // crbug.com/138092 735e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org Bool supported_return; 748923c6cfd580ac9accb11b909fa2a033d69553aareed@google.com if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) { 750770044da6d61dcbc8d9673fed8dd92460faa314reed@google.com DVLOG(1) << "XKB not supported in the server."; 769875dd14af6d768da8d1a4be58b98fc91ceca0ddtomhudson@google.com return false; 779875dd14af6d768da8d1a4be58b98fc91ceca0ddtomhudson@google.com } 780770044da6d61dcbc8d9673fed8dd92460faa314reed@google.com 7900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com return true; 80e3cc2eb88fef9b2123c6ea2ed813ce53b6385926epoger@google.com} 81e3cc2eb88fef9b2123c6ea2ed813ce53b6385926epoger@google.com 82e3cc2eb88fef9b2123c6ea2ed813ce53b6385926epoger@google.com} // namespace 83b29c883fb46ac6099440d82ac57b86d25386daedbungeman@google.com 84b29c883fb46ac6099440d82ac57b86d25386daedbungeman@google.comX11EventSource::X11EventSource(XDisplay* display) 85b29c883fb46ac6099440d82ac57b86d25386daedbungeman@google.com : display_(display), 86b29c883fb46ac6099440d82ac57b86d25386daedbungeman@google.com continue_stream_(true) { 8746cce91f4859b9c229938d4d649870c0a43b1806reed@google.com CHECK(display_); 8846cce91f4859b9c229938d4d649870c0a43b1806reed@google.com DeviceDataManagerX11::CreateInstance(); 8946cce91f4859b9c229938d4d649870c0a43b1806reed@google.com hotplug_event_handler_.reset( 9046cce91f4859b9c229938d4d649870c0a43b1806reed@google.com new HotplugEventHandlerX11(DeviceDataManager::GetInstance())); 9100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com InitializeXInput2(display_); 9200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com InitializeXkb(display_); 9300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com 9400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com // Force the initial device query to have an update list of active devices. 9500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com hotplug_event_handler_->OnHotplugEvent(); 963914958a49ee089ddeb04acc16373aae8bc2eaf7bsalomon@google.com} 973914958a49ee089ddeb04acc16373aae8bc2eaf7bsalomon@google.com 983914958a49ee089ddeb04acc16373aae8bc2eaf7bsalomon@google.comX11EventSource::~X11EventSource() { 993914958a49ee089ddeb04acc16373aae8bc2eaf7bsalomon@google.com} 100dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com 10100dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com// static 102d4dfd10bb6f9bf3ac6e1ebc9bc3ae22c6d06321freed@google.comX11EventSource* X11EventSource::GetInstance() { 103dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com return static_cast<X11EventSource*>(PlatformEventSource::GetInstance()); 10400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com} 105dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com 10600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com//////////////////////////////////////////////////////////////////////////////// 107dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com// X11EventSource, public 10800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com 10900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comvoid X11EventSource::DispatchXEvents() { 11000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com DCHECK(display_); 111d4dfd10bb6f9bf3ac6e1ebc9bc3ae22c6d06321freed@google.com // Handle all pending events. 11200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com // It may be useful to eventually align this event dispatch with vsync, but 113dd0ac281e920b01a63789893cc3e7422789658ddreed@android.com // not yet. 11400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com continue_stream_ = true; 11500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com while (XPending(display_) && continue_stream_) { 11600dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com XEvent xevent; 11700dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com XNextEvent(display_, &xevent); 11800dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com DispatchEvent(&xevent); 11900dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com } 12000dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com} 121d4dfd10bb6f9bf3ac6e1ebc9bc3ae22c6d06321freed@google.com 12200dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.comvoid X11EventSource::BlockUntilWindowMapped(XID window) { 12300dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com XEvent event; 12400dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com do { 12500dae86f5872b60927b28a32b375bc01cd7c61c9reed@android.com // Block until there's a message of |event_mask| type on |w|. Then remove 126ce057fec926f8ec1d60ed4722d1e51a0086e7976epoger@google.com // it from the queue and stuff it in |event|. 127ce057fec926f8ec1d60ed4722d1e51a0086e7976epoger@google.com XWindowEvent(display_, window, StructureNotifyMask, &event); 128ce057fec926f8ec1d60ed4722d1e51a0086e7976epoger@google.com DispatchEvent(&event); 129ce057fec926f8ec1d60ed4722d1e51a0086e7976epoger@google.com } while (event.type != MapNotify); 130ce057fec926f8ec1d60ed4722d1e51a0086e7976epoger@google.com} 131686abdfab0e4c45de1fd30774896c46e43a299acvandebo@chromium.org 1323cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org//////////////////////////////////////////////////////////////////////////////// 1333cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org// X11EventSource, private 1343cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org 1353cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.orguint32_t X11EventSource::DispatchEvent(XEvent* xevent) { 1363cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org bool have_cookie = false; 1373cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org if (xevent->type == GenericEvent && 1383cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org XGetEventData(xevent->xgeneric.display, &xevent->xcookie)) { 1393cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org have_cookie = true; 1403cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org } 1413cb834bd27a16cc60ff30adae96659558c2dc91fjunov@chromium.org 142686abdfab0e4c45de1fd30774896c46e43a299acvandebo@chromium.org uint32_t action = PlatformEventSource::DispatchEvent(xevent); 143686abdfab0e4c45de1fd30774896c46e43a299acvandebo@chromium.org if (xevent->type == GenericEvent && 1447361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com xevent->xgeneric.evtype == XI_HierarchyChanged) { 1457361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com ui::UpdateDeviceList(); 1467361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com hotplug_event_handler_->OnHotplugEvent(); 1477361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com } 148f28dd8ab109663a6fe67fd4ee3d66248e0dac686epoger@google.com 1497361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com if (have_cookie) 1507361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com XFreeEventData(xevent->xgeneric.display, &xevent->xcookie); 1517361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com return action; 1527361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com} 1539875dd14af6d768da8d1a4be58b98fc91ceca0ddtomhudson@google.com 1547361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.comvoid X11EventSource::StopCurrentEventStream() { 1557361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com continue_stream_ = false; 156cf8fb1f6f03fc77f9927564f9ef9abeeeec508d2bsalomon@google.com} 1577361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com 1587361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com} // namespace ui 1597361f54294d65a5c42ce5cf1cd56d0fd7122e268bsalomon@google.com