@@ -214,6 +214,8 @@ pub struct X11ClientState {
pointer_device_states: BTreeMap<xinput::DeviceId, PointerDeviceState>,
+ pub(crate) supports_xinput_gestures: bool,
+
pub(crate) common: LinuxCommon,
pub(crate) clipboard: Clipboard,
pub(crate) clipboard_item: Option<ClipboardItem>,
@@ -345,7 +347,8 @@ impl X11Client {
// Announce to X server that XInput up to 2.4 is supported.
// Version 2.4 is needed for gesture events (GesturePinchBegin/Update/End).
- // If the server only supports an older version, gesture events simply won't be delivered.
+ // The server responds with the highest version it supports; if < 2.4,
+ // we must not request gesture event masks in XISelectEvents.
let xinput_version = get_reply(
|| "XInput XiQueryVersion failed",
xcb_connection.xinput_xi_query_version(2, 4),
@@ -354,6 +357,14 @@ impl X11Client {
xinput_version.major_version >= 2,
"XInput version >= 2 required."
);
+ let supports_xinput_gestures = xinput_version.major_version > 2
+ || (xinput_version.major_version == 2 && xinput_version.minor_version >= 4);
+ log::info!(
+ "XInput version: {}.{}, gesture support: {}",
+ xinput_version.major_version,
+ xinput_version.minor_version,
+ supports_xinput_gestures,
+ );
let pointer_device_states =
current_pointer_device_states(&xcb_connection, &BTreeMap::new()).unwrap_or_default();
@@ -535,6 +546,8 @@ impl X11Client {
pointer_device_states,
+ supports_xinput_gestures,
+
clipboard,
clipboard_item: None,
xdnd_state: Xdnd::default(),
@@ -1593,6 +1606,7 @@ impl LinuxClient for X11Client {
let scale_factor = state.scale_factor;
let appearance = state.common.appearance;
let compositor_gpu = state.compositor_gpu.take();
+ let supports_xinput_gestures = state.supports_xinput_gestures;
let window = X11Window::new(
handle,
X11ClientStatePtr(Rc::downgrade(&self.0)),
@@ -1608,6 +1622,7 @@ impl LinuxClient for X11Client {
scale_factor,
appearance,
parent_window,
+ supports_xinput_gestures,
)?;
check_reply(
|| "Failed to set XdndAware property",
@@ -423,6 +423,7 @@ impl X11WindowState {
scale_factor: f32,
appearance: WindowAppearance,
parent_window: Option<X11WindowStatePtr>,
+ supports_xinput_gestures: bool,
) -> anyhow::Result<Self> {
let x_screen_index = params
.display_id
@@ -660,25 +661,27 @@ impl X11WindowState {
),
)?;
+ let mut xi_event_mask = xinput::XIEventMask::MOTION
+ | xinput::XIEventMask::BUTTON_PRESS
+ | xinput::XIEventMask::BUTTON_RELEASE
+ | xinput::XIEventMask::ENTER
+ | xinput::XIEventMask::LEAVE;
+ if supports_xinput_gestures {
+ // x11rb 0.13 doesn't define XIEventMask constants for gesture
+ // events, so we construct them from the event opcodes (each
+ // XInput event type N maps to mask bit N).
+ xi_event_mask |=
+ xinput::XIEventMask::from(1u32 << xinput::GESTURE_PINCH_BEGIN_EVENT)
+ | xinput::XIEventMask::from(1u32 << xinput::GESTURE_PINCH_UPDATE_EVENT)
+ | xinput::XIEventMask::from(1u32 << xinput::GESTURE_PINCH_END_EVENT);
+ }
check_reply(
|| "X11 XiSelectEvents failed.",
xcb.xinput_xi_select_events(
x_window,
&[xinput::EventMask {
deviceid: XINPUT_ALL_DEVICE_GROUPS,
- mask: vec![
- xinput::XIEventMask::MOTION
- | xinput::XIEventMask::BUTTON_PRESS
- | xinput::XIEventMask::BUTTON_RELEASE
- | xinput::XIEventMask::ENTER
- | xinput::XIEventMask::LEAVE
- // x11rb 0.13 doesn't define XIEventMask constants for gesture
- // events, so we construct them from the event opcodes (each
- // XInput event type N maps to mask bit N).
- | xinput::XIEventMask::from(1u32 << xinput::GESTURE_PINCH_BEGIN_EVENT)
- | xinput::XIEventMask::from(1u32 << xinput::GESTURE_PINCH_UPDATE_EVENT)
- | xinput::XIEventMask::from(1u32 << xinput::GESTURE_PINCH_END_EVENT),
- ],
+ mask: vec![xi_event_mask],
}],
),
)?;
@@ -855,6 +858,7 @@ impl X11Window {
scale_factor: f32,
appearance: WindowAppearance,
parent_window: Option<X11WindowStatePtr>,
+ supports_xinput_gestures: bool,
) -> anyhow::Result<Self> {
let ptr = X11WindowStatePtr {
state: Rc::new(RefCell::new(X11WindowState::new(
@@ -872,6 +876,7 @@ impl X11Window {
scale_factor,
appearance,
parent_window,
+ supports_xinput_gestures,
)?)),
callbacks: Rc::new(RefCell::new(Callbacks::default())),
xcb: xcb.clone(),