summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorpkotwicz <pkotwicz@chromium.org>2015-02-03 20:11:27 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-04 04:13:45 +0000
commit890bd4742e41d386885a3bb3f5f72bac3065659a (patch)
tree56a2984fdb6866c573fbe30beb8b64ef4dfae654 /ui
parent03df6f6cec5f06ffb4bda1d03670c2a1a6b26bd0 (diff)
downloadchromium_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.cc4
-rw-r--r--ui/events/devices/x11/device_data_manager_x11.h7
-rw-r--r--ui/events/devices/x11/touch_factory_x11.cc2
-rw-r--r--ui/views/widget/desktop_aura/x11_pointer_grab.cc50
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);
}