diff options
author | pkotwicz <pkotwicz@chromium.org> | 2015-02-03 20:11:27 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-04 04:13:45 +0000 |
commit | 890bd4742e41d386885a3bb3f5f72bac3065659a (patch) | |
tree | 56a2984fdb6866c573fbe30beb8b64ef4dfae654 /ui | |
parent | 03df6f6cec5f06ffb4bda1d03670c2a1a6b26bd0 (diff) | |
download | chromium_src-890bd4742e41d386885a3bb3f5f72bac3065659a.zip chromium_src-890bd4742e41d386885a3bb3f5f72bac3065659a.tar.gz chromium_src-890bd4742e41d386885a3bb3f5f72bac3065659a.tar.bz2 |
Fix grabbing capture when the mouse is pressed on Desktop Linux.
The X specification allows the OS to grab the mouse when a mouse button is
pressed. The OS grab was causing XGrabPointer() in
DesktopWindowTreeHostX11::SetCapture() to fail.
BUG=426380
TEST=Manual
Review URL: https://codereview.chromium.org/749063003
Cr-Commit-Position: refs/heads/master@{#314501}
Diffstat (limited to 'ui')
-rw-r--r-- | ui/events/devices/x11/device_data_manager_x11.cc | 4 | ||||
-rw-r--r-- | ui/events/devices/x11/device_data_manager_x11.h | 7 | ||||
-rw-r--r-- | ui/events/devices/x11/touch_factory_x11.cc | 2 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/x11_pointer_grab.cc | 50 |
4 files changed, 59 insertions, 4 deletions
diff --git a/ui/events/devices/x11/device_data_manager_x11.cc b/ui/events/devices/x11/device_data_manager_x11.cc index 68fdb2c..85c697a 100644 --- a/ui/events/devices/x11/device_data_manager_x11.cc +++ b/ui/events/devices/x11/device_data_manager_x11.cc @@ -202,6 +202,7 @@ bool DeviceDataManagerX11::IsXInput2Available() const { void DeviceDataManagerX11::UpdateDeviceList(Display* display) { cmt_devices_.reset(); touchpads_.reset(); + master_pointers_.clear(); for (int i = 0; i < kMaxDeviceNum; ++i) { valuator_count_[i] = 0; valuator_lookup_[i].clear(); @@ -233,6 +234,9 @@ void DeviceDataManagerX11::UpdateDeviceList(Display* display) { for (int i = 0; i < info_list.count; ++i) { XIDeviceInfo* info = info_list.devices + i; + if (info->use == XIMasterPointer) + master_pointers_.push_back(info->deviceid); + // We currently handle only slave, non-keyboard devices if (info->use != XISlavePointer && info->use != XIFloatingSlave) continue; diff --git a/ui/events/devices/x11/device_data_manager_x11.h b/ui/events/devices/x11/device_data_manager_x11.h index ec580cb..bb5fa15 100644 --- a/ui/events/devices/x11/device_data_manager_x11.h +++ b/ui/events/devices/x11/device_data_manager_x11.h @@ -239,6 +239,10 @@ class EVENTS_DEVICES_EXPORT DeviceDataManagerX11 : public DeviceDataManager { // Returns true if |native_event| should be blocked. bool IsEventBlocked(const base::NativeEvent& native_event); + const std::vector<int>& master_pointers() const { + return master_pointers_; + } + protected: // DeviceHotplugEventObserver: void OnKeyboardDevicesUpdated( @@ -274,6 +278,9 @@ class EVENTS_DEVICES_EXPORT DeviceDataManagerX11 : public DeviceDataManager { std::bitset<kMaxDeviceNum> cmt_devices_; std::bitset<kMaxDeviceNum> touchpads_; + // List of the master pointer devices. + std::vector<int> master_pointers_; + // A quick lookup table for determining if events from the XI device // should be blocked. std::bitset<kMaxDeviceNum> blocked_devices_; diff --git a/ui/events/devices/x11/touch_factory_x11.cc b/ui/events/devices/x11/touch_factory_x11.cc index 929c595..4201fa0 100644 --- a/ui/events/devices/x11/touch_factory_x11.cc +++ b/ui/events/devices/x11/touch_factory_x11.cc @@ -201,6 +201,8 @@ void TouchFactory::SetupXI2ForXWindow(Window window) { XISetMask(mask, XI_ButtonRelease); XISetMask(mask, XI_Motion); #if defined(OS_CHROMEOS) + // XGrabKey() must be replaced with XI2 keyboard grab if XI2 key events are + // enabled on desktop Linux. if (base::SysInfo::IsRunningOnChromeOS()) { XISetMask(mask, XI_KeyPress); XISetMask(mask, XI_KeyRelease); diff --git a/ui/views/widget/desktop_aura/x11_pointer_grab.cc b/ui/views/widget/desktop_aura/x11_pointer_grab.cc index 1354159..26a1c1d 100644 --- a/ui/views/widget/desktop_aura/x11_pointer_grab.cc +++ b/ui/views/widget/desktop_aura/x11_pointer_grab.cc @@ -3,8 +3,11 @@ // found in the LICENSE file. #include "base/logging.h" +#include "ui/base/x/x11_util.h" +#include "ui/events/devices/x11/device_data_manager_x11.h" #include "ui/views/widget/desktop_aura/x11_pointer_grab.h" +#include <X11/extensions/XInput2.h> #include <X11/Xlib.h> namespace views { @@ -20,10 +23,42 @@ bool g_owner_events = false; } // namespace int GrabPointer(XID window, bool owner_events, ::Cursor cursor) { - int event_mask = PointerMotionMask | ButtonReleaseMask | ButtonPressMask; - int result = XGrabPointer(gfx::GetXDisplay(), window, owner_events, - event_mask, GrabModeAsync, GrabModeAsync, None, - cursor, CurrentTime); + int result = GrabInvalidTime; + if (ui::IsXInput2Available()) { + // Do an XInput2 pointer grab. If there is an active XInput2 pointer grab + // as a result of normal button press, XGrabPointer() will fail. + unsigned char mask[XIMaskLen(XI_LASTEVENT)]; + memset(mask, 0, sizeof(mask)); + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); + XIEventMask evmask; + evmask.mask_len = sizeof(mask); + evmask.mask = mask; + + const std::vector<int>& master_pointers = + ui::DeviceDataManagerX11::GetInstance()->master_pointers(); + for (int master_pointer : master_pointers) { + evmask.deviceid = master_pointer; + result = XIGrabDevice( + gfx::GetXDisplay(), master_pointer, window, CurrentTime, cursor, + GrabModeAsync, GrabModeAsync, owner_events, &evmask); + // Assume that the grab will succeed on either all or none of the master + // pointers. + if (result != GrabSuccess) { + // Try core pointer grab. + break; + } + } + } + + if (result != GrabSuccess) { + int event_mask = PointerMotionMask | ButtonReleaseMask | ButtonPressMask; + result = + XGrabPointer(gfx::GetXDisplay(), window, owner_events, event_mask, + GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); + } + if (result == GrabSuccess) { g_grab_window = window; g_owner_events = owner_events; @@ -38,6 +73,13 @@ void ChangeActivePointerGrabCursor(::Cursor cursor) { void UngrabPointer() { g_grab_window = None; + if (ui::IsXInput2Available()) { + const std::vector<int>& master_pointers = + ui::DeviceDataManagerX11::GetInstance()->master_pointers(); + for (int master_pointer : master_pointers) + XIUngrabDevice(gfx::GetXDisplay(), master_pointer, CurrentTime); + } + // Try core pointer ungrab in case the XInput2 pointer ungrab failed. XUngrabPointer(gfx::GetXDisplay(), CurrentTime); } |