123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/base/x/x11_pointer_grab.h"
- #include "base/bind.h"
- #include "base/cancelable_callback.h"
- #include "base/check.h"
- #include "base/no_destructor.h"
- #include "base/sys_byteorder.h"
- #include "ui/base/x/x11_util.h"
- #include "ui/events/devices/x11/device_data_manager_x11.h"
- #include "ui/gfx/x/connection.h"
- #include "ui/gfx/x/xinput.h"
- #include "ui/gfx/x/xproto.h"
- namespace ui {
- namespace {
- // The grab window. None if there are no active pointer grabs.
- x11::Window g_grab_window = x11::Window::None;
- // The "owner events" parameter used to grab the pointer.
- bool g_owner_events = false;
- base::CancelableOnceCallback<void(x11::Cursor)>& GetGrabCallback() {
- static base::NoDestructor<base::CancelableOnceCallback<void(x11::Cursor)>>
- callback;
- return *callback;
- }
- x11::GrabStatus GrabPointerImpl(x11::Window window,
- bool owner_events,
- x11::Cursor cursor) {
- GetGrabCallback().Cancel();
- auto result = x11::GrabStatus::InvalidTime;
- auto* connection = x11::Connection::Get();
- if (ui::IsXInput2Available()) {
- // Do an xinput pointer grab. If there is an active xinput pointer grab
- // as a result of normal button press, GrabPointer() will fail.
- auto mask = x11::Input::XIEventMask::ButtonPress |
- x11::Input::XIEventMask::ButtonRelease |
- x11::Input::XIEventMask::Motion |
- x11::Input::XIEventMask::TouchBegin |
- x11::Input::XIEventMask::TouchUpdate |
- x11::Input::XIEventMask::TouchEnd;
- static_assert(sizeof(mask) == 4, "");
- for (auto master_pointer :
- ui::DeviceDataManagerX11::GetInstance()->master_pointers()) {
- x11::Input::XIGrabDeviceRequest req{
- .window = window,
- .time = x11::Time::CurrentTime,
- .cursor = cursor,
- .deviceid = master_pointer,
- .mode = x11::GrabMode::Async,
- .paired_device_mode = x11::GrabMode::Async,
- .owner_events = owner_events ? x11::Input::GrabOwner::Owner
- : x11::Input::GrabOwner::NoOwner,
- .mask = {base::ByteSwapToLE32(static_cast<uint32_t>(mask))},
- };
- if (auto reply = connection->xinput().XIGrabDevice(req).Sync())
- result = reply->status;
- // Assume that the grab will succeed on either all or none of the master
- // pointers.
- if (result != x11::GrabStatus::Success) {
- // Try core pointer grab.
- break;
- }
- }
- }
- if (result != x11::GrabStatus::Success) {
- auto mask = x11::EventMask::PointerMotion | x11::EventMask::ButtonRelease |
- x11::EventMask::ButtonPress;
- x11::GrabPointerRequest req{
- .owner_events = owner_events,
- .grab_window = window,
- .event_mask = mask,
- .pointer_mode = x11::GrabMode::Async,
- .keyboard_mode = x11::GrabMode::Async,
- .confine_to = x11::Window::None,
- .cursor = cursor,
- .time = x11::Time::CurrentTime,
- };
- if (auto reply = connection->GrabPointer(req).Sync())
- result = reply->status;
- }
- if (result == x11::GrabStatus::Success) {
- g_grab_window = window;
- g_owner_events = owner_events;
- }
- return result;
- }
- } // namespace
- x11::GrabStatus GrabPointer(x11::Window window,
- bool owner_events,
- scoped_refptr<ui::X11Cursor> cursor) {
- if (!cursor)
- return GrabPointerImpl(window, owner_events, x11::Cursor::None);
- if (cursor->loaded())
- return GrabPointerImpl(window, owner_events, cursor->xcursor());
- auto result = GrabPointerImpl(window, owner_events, x11::Cursor::None);
- GetGrabCallback().Reset(base::BindOnce(base::IgnoreResult(GrabPointerImpl),
- window, owner_events));
- cursor->OnCursorLoaded(GetGrabCallback().callback());
- return result;
- }
- void ChangeActivePointerGrabCursor(scoped_refptr<ui::X11Cursor> cursor) {
- if (g_grab_window != x11::Window::None)
- GrabPointer(g_grab_window, g_owner_events, cursor);
- }
- void UngrabPointer() {
- GetGrabCallback().Cancel();
- g_grab_window = x11::Window::None;
- auto* connection = x11::Connection::Get();
- if (ui::IsXInput2Available()) {
- for (auto master_pointer :
- ui::DeviceDataManagerX11::GetInstance()->master_pointers()) {
- connection->xinput()
- .XIUngrabDevice({x11::Time::CurrentTime, master_pointer})
- .IgnoreError();
- }
- }
- // Try core pointer ungrab in case the XInput2 pointer ungrab failed.
- connection->UngrabPointer().IgnoreError();
- }
- } // namespace ui
|