diff --git a/src/backend.rs b/src/backend.rs index 49320aff..7c2e18ae 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -348,6 +348,11 @@ pub enum InputEvent { dx_unaccelerated: Fixed, dy_unaccelerated: Fixed, }, + MotionAbsolute { + time_usec: u64, + x_normed: f32, + y_normed: f32, + }, Button { time_usec: u64, button: u32, diff --git a/src/backends/metal/input.rs b/src/backends/metal/input.rs index 4456ede6..58fdc569 100644 --- a/src/backends/metal/input.rs +++ b/src/backends/metal/input.rs @@ -95,6 +95,7 @@ impl MetalBackend { c::LIBINPUT_EVENT_DEVICE_REMOVED => self.handle_li_device_removed(event), c::LIBINPUT_EVENT_KEYBOARD_KEY => self.handle_keyboard_key(event), c::LIBINPUT_EVENT_POINTER_MOTION => self.handle_pointer_motion(event), + c::LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE => self.handle_pointer_motion_absolute(event), c::LIBINPUT_EVENT_POINTER_BUTTON => self.handle_pointer_button(event), c::LIBINPUT_EVENT_POINTER_SCROLL_WHEEL => { self.handle_pointer_axis(event, AxisSource::Wheel) @@ -248,6 +249,15 @@ impl MetalBackend { }); } + fn handle_pointer_motion_absolute(self: &Rc, event: LibInputEvent) { + let (event, dev) = unpack!(self, event, pointer_event); + dev.event(InputEvent::MotionAbsolute { + time_usec: event.time_usec(), + x_normed: event.x_transformed(1) as f32, + y_normed: event.y_transformed(1) as f32, + }); + } + fn handle_gesture_swipe_begin(self: &Rc, event: LibInputEvent) { let (event, dev) = unpack!(self, event, gesture_event); dev.event(InputEvent::SwipeBegin { diff --git a/src/compositor.rs b/src/compositor.rs index 39df57bd..c6dce04d 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -359,6 +359,7 @@ fn start_compositor2( enable_primary_selection: Cell::new(true), xdg_surface_configure_events: Default::default(), workspace_display_order: Cell::new(WorkspaceDisplayOrder::Manual), + outputs_without_hc: Default::default(), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); diff --git a/src/cursor_user.rs b/src/cursor_user.rs index 0f945d39..f983e577 100644 --- a/src/cursor_user.rs +++ b/src/cursor_user.rs @@ -85,7 +85,7 @@ impl CursorUserGroup { let x_int = x.round_down(); let y_int = y.round_down(); let extents = cursor.extents_at_scale(Scale::default()); - self.state.damage2(true, extents.move_(x_int, y_int)); + self.damage(extents.move_(x_int, y_int)); } } @@ -248,6 +248,10 @@ impl CursorUserGroup { }; active.present_hardware_cursor(output, hc); } + + fn damage(&self, rect: Rect) { + self.state.damage2(true, self.hardware_cursor.get(), rect); + } } impl CursorUser { @@ -416,10 +420,8 @@ impl CursorUser { let old_x_int = old_x.round_down(); let old_y_int = old_y.round_down(); let extents = cursor.extents_at_scale(Scale::default()); - self.group - .state - .damage2(true, extents.move_(old_x_int, old_y_int)); - self.group.state.damage2(true, extents.move_(x_int, y_int)); + self.group.damage(extents.move_(old_x_int, old_y_int)); + self.group.damage(extents.move_(x_int, y_int)); } self.pos.set((x, y)); self.update_hardware_cursor_(false); @@ -435,7 +437,8 @@ impl CursorUser { } pub fn software_cursor(&self) -> bool { - self.is_active() && !self.group.hardware_cursor.get() + self.is_active() + && (!self.group.hardware_cursor.get() || self.group.state.outputs_without_hc.get() > 0) } fn update_hardware_cursor_(&self, render: bool) { diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 42586ed2..7f2010e5 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -310,6 +310,7 @@ impl WlSeatGlobal { InputEvent::Key { time_usec, .. } | InputEvent::ConnectorPosition { time_usec, .. } | InputEvent::Motion { time_usec, .. } + | InputEvent::MotionAbsolute { time_usec, .. } | InputEvent::Button { time_usec, .. } | InputEvent::AxisFrame { time_usec, .. } | InputEvent::SwipeBegin { time_usec, .. } @@ -350,6 +351,7 @@ impl WlSeatGlobal { match event { InputEvent::ConnectorPosition { .. } | InputEvent::Motion { .. } + | InputEvent::MotionAbsolute { .. } | InputEvent::Button { .. } | InputEvent::AxisFrame { .. } | InputEvent::SwipeBegin { .. } @@ -406,6 +408,13 @@ impl WlSeatGlobal { dy_unaccelerated, time_usec, } => self.motion_event(time_usec, dx, dy, dx_unaccelerated, dy_unaccelerated), + InputEvent::MotionAbsolute { + time_usec, + x_normed, + y_normed, + } => { + self.motion_absolute_event(time_usec, dev.get_rect(&self.state), x_normed, y_normed) + } InputEvent::Button { time_usec, button, @@ -651,6 +660,18 @@ impl WlSeatGlobal { self.cursor_moved(time_usec, false); } + fn motion_absolute_event( + self: &Rc, + time_usec: u64, + rect: Rect, + x_normed: f32, + y_normed: f32, + ) { + let x = Fixed::from_f32(rect.x1() as f32 + x_normed * rect.width() as f32); + let y = Fixed::from_f32(rect.y1() as f32 + y_normed * rect.height() as f32); + self.motion_event_abs(time_usec, x, y, false); + } + pub fn button_event(self: &Rc, time_usec: u64, button: u32, state: KeyState) { self.for_each_ei_seat(|ei_seat| { ei_seat.handle_button(time_usec, button, state); diff --git a/src/libinput/event.rs b/src/libinput/event.rs index 8af7ff4a..ed8b362b 100644 --- a/src/libinput/event.rs +++ b/src/libinput/event.rs @@ -19,14 +19,16 @@ use { libinput_event_get_touch_event, libinput_event_get_type, libinput_event_keyboard, libinput_event_keyboard_get_key, libinput_event_keyboard_get_key_state, libinput_event_keyboard_get_time_usec, libinput_event_pointer, - libinput_event_pointer_get_button, libinput_event_pointer_get_button_state, - libinput_event_pointer_get_dx, libinput_event_pointer_get_dx_unaccelerated, - libinput_event_pointer_get_dy, libinput_event_pointer_get_dy_unaccelerated, - libinput_event_pointer_get_scroll_value, libinput_event_pointer_get_scroll_value_v120, - libinput_event_pointer_get_time_usec, libinput_event_pointer_has_axis, - libinput_event_switch, libinput_event_switch_get_switch, - libinput_event_switch_get_switch_state, libinput_event_switch_get_time_usec, - libinput_event_tablet_pad, libinput_event_tablet_pad_get_button_number, + libinput_event_pointer_get_absolute_x_transformed, + libinput_event_pointer_get_absolute_y_transformed, libinput_event_pointer_get_button, + libinput_event_pointer_get_button_state, libinput_event_pointer_get_dx, + libinput_event_pointer_get_dx_unaccelerated, libinput_event_pointer_get_dy, + libinput_event_pointer_get_dy_unaccelerated, libinput_event_pointer_get_scroll_value, + libinput_event_pointer_get_scroll_value_v120, libinput_event_pointer_get_time_usec, + libinput_event_pointer_has_axis, libinput_event_switch, + libinput_event_switch_get_switch, libinput_event_switch_get_switch_state, + libinput_event_switch_get_time_usec, libinput_event_tablet_pad, + libinput_event_tablet_pad_get_button_number, libinput_event_tablet_pad_get_button_state, libinput_event_tablet_pad_get_dial_delta_v120, libinput_event_tablet_pad_get_dial_number, libinput_event_tablet_pad_get_mode, @@ -186,6 +188,14 @@ impl<'a> LibInputEventKeyboard<'a> { } impl<'a> LibInputEventPointer<'a> { + pub fn x_transformed(&self, width: u32) -> f64 { + unsafe { libinput_event_pointer_get_absolute_x_transformed(self.event, width) } + } + + pub fn y_transformed(&self, height: u32) -> f64 { + unsafe { libinput_event_pointer_get_absolute_y_transformed(self.event, height) } + } + pub fn dx(&self) -> f64 { unsafe { libinput_event_pointer_get_dx(self.event) } } diff --git a/src/libinput/sys.rs b/src/libinput/sys.rs index e849d0f2..2de8d416 100644 --- a/src/libinput/sys.rs +++ b/src/libinput/sys.rs @@ -155,6 +155,14 @@ unsafe extern "C" { pub fn libinput_event_pointer_get_dy(event: *mut libinput_event_pointer) -> f64; pub fn libinput_event_pointer_get_dx_unaccelerated(event: *mut libinput_event_pointer) -> f64; pub fn libinput_event_pointer_get_dy_unaccelerated(event: *mut libinput_event_pointer) -> f64; + pub fn libinput_event_pointer_get_absolute_x_transformed( + event: *mut libinput_event_pointer, + width: u32, + ) -> f64; + pub fn libinput_event_pointer_get_absolute_y_transformed( + event: *mut libinput_event_pointer, + height: u32, + ) -> f64; pub fn libinput_event_pointer_get_button(event: *mut libinput_event_pointer) -> u32; pub fn libinput_event_pointer_get_button_state( event: *mut libinput_event_pointer, diff --git a/src/state.rs b/src/state.rs index 421d77e9..56f38271 100644 --- a/src/state.rs +++ b/src/state.rs @@ -277,6 +277,7 @@ pub struct State { pub enable_primary_selection: Cell, pub xdg_surface_configure_events: AsyncQueue, pub workspace_display_order: Cell, + pub outputs_without_hc: NumCell, } // impl Drop for State { @@ -648,7 +649,7 @@ impl State { fn visit_output(&mut self, node: &Rc) { node.render_data.borrow_mut().titles.clear(); node.render_data.borrow_mut().status.take(); - node.hardware_cursor.set(None); + node.set_hardware_cursor(None); node.node_visit_children(self); } fn visit_float(&mut self, node: &Rc) { @@ -968,16 +969,19 @@ impl State { } pub fn damage(&self, rect: Rect) { - self.damage2(false, rect); + self.damage2(false, false, rect); } - pub fn damage2(&self, cursor: bool, rect: Rect) { + pub fn damage2(&self, cursor: bool, skip_hc: bool, rect: Rect) { if rect.is_empty() { return; } self.damage_visualizer.add(rect); for output in self.root.outputs.lock().values() { if output.global.pos.get().intersects(&rect) { + if skip_hc && output.hardware_cursor.is_some() { + continue; + } output.global.add_damage_area(&rect); if cursor && output.schedule.defer_cursor_updates() { output.schedule.software_cursor_changed(); diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index f7960960..2ca0f8d8 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -271,6 +271,7 @@ impl ConnectorHandler { self.state.outputs.set(self.id, output_data.clone()); on.schedule_update_render_data(); self.state.root.outputs.set(self.id, on.clone()); + self.state.outputs_without_hc.fetch_add(1); self.state.output_extents_changed(); global.opt.node.set(Some(on.clone())); global.opt.global.set(Some(global.clone())); @@ -330,7 +331,7 @@ impl ConnectorHandler { ConnectorEvent::Disconnected => break 'outer, ConnectorEvent::HardwareCursor(hc) => { on.schedule.set_hardware_cursor(&hc); - on.hardware_cursor.set(hc); + on.set_hardware_cursor(hc); self.state.refresh_hardware_cursors(); } ConnectorEvent::FormatsChanged(formats) => { @@ -363,6 +364,9 @@ impl ConnectorHandler { sc.stop(); } global.destroyed.set(true); + if on.hardware_cursor.is_none() { + self.state.outputs_without_hc.fetch_sub(1); + } self.state.root.outputs.remove(&self.id); self.state.output_extents_changed(); self.state.outputs.remove(&self.id); diff --git a/src/tree/output.rs b/src/tree/output.rs index c7842d64..c0f49100 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -1433,6 +1433,19 @@ impl OutputNode { .handle_tearing_mode_change(mode.to_config()); } } + + pub fn set_hardware_cursor(&self, hc: Option>) { + let is_none = hc.is_none(); + let old = self.hardware_cursor.set(hc); + let was_none = old.is_none(); + if was_none != is_none { + if is_none { + self.state.outputs_without_hc.fetch_add(1); + } else { + self.state.outputs_without_hc.fetch_sub(1); + } + } + } } pub struct OutputTitle {