diff --git a/crates/rnote-ui/src/canvas/input.rs b/crates/rnote-ui/src/canvas/input.rs index 2c8dd138f7..c288721e4a 100644 --- a/crates/rnote-ui/src/canvas/input.rs +++ b/crates/rnote-ui/src/canvas/input.rs @@ -23,13 +23,19 @@ pub(crate) fn handle_pointer_controller_event( let gdk_modifiers = event.modifier_state(); let _gdk_device = event.device().unwrap(); let backlog_policy = canvas.engine_ref().penholder.backlog_policy(); - let is_stylus = event_is_stylus(event); + let input_source = input_source_from_event(event); + let is_stylus = input_source == Some(gdk::InputSource::Pen); //std::thread::sleep(std::time::Duration::from_millis(100)); //super::input::debug_gdk_event(event); - if reject_pointer_input(event, touch_drawing) { - return (glib::Propagation::Proceed, pen_state); + if let Some(propagation) = reject_pointer_input( + event, + pen_state, + input_source == canvas.pen_input_source(), + touch_drawing, + ) { + return (propagation, pen_state); } let mut handle_pen_event = false; @@ -216,6 +222,7 @@ pub(crate) fn handle_pointer_controller_event( } } + canvas.set_pen_input_source(input_source); canvas.emit_handle_widget_flags(widget_flags); (propagation, pen_state) } @@ -293,24 +300,27 @@ fn debug_gdk_event(event: &gdk::Event) { ); } -/// Returns true if input should be rejected -fn reject_pointer_input(event: &gdk::Event, touch_drawing: bool) -> bool { +/// Returns Option if pointer input should be rejected +fn reject_pointer_input( + event: &gdk::Event, + state: PenState, + input_source_matches: bool, + touch_drawing: bool, +) -> Option { + // If pen is already down, reject events from other input sources + if matches!(state, PenState::Down) && !input_source_matches { + return Some(glib::Propagation::Stop); + } if touch_drawing { if event.device().unwrap().num_touches() > 1 { - return true; + return Some(glib::Propagation::Proceed); } } else { - let event_type = event.event_type(); - if event.is_pointer_emulated() - || event_type == gdk::EventType::TouchBegin - || event_type == gdk::EventType::TouchUpdate - || event_type == gdk::EventType::TouchEnd - || event_type == gdk::EventType::TouchCancel - { - return true; + if event.is_pointer_emulated() || event_is_touchscreen(event) { + return Some(glib::Propagation::Proceed); } } - false + None } fn event_is_stylus(event: &gdk::Event) -> bool { @@ -318,6 +328,29 @@ fn event_is_stylus(event: &gdk::Event) -> bool { event.device_tool().is_some() } +fn event_is_touchscreen(event: &gdk::Event) -> bool { + matches!( + event.event_type(), + gdk::EventType::TouchBegin + | gdk::EventType::TouchUpdate + | gdk::EventType::TouchEnd + | gdk::EventType::TouchCancel + ) +} + +// gdk::Device.source() returns InputSource::Mouse for pens and touchscreens, +// so use manual detection instead, with gdk::Device.source() as a fallback. +// (see https://gitlab.gnome.org/GNOME/gtk/issues/4374) +pub(crate) fn input_source_from_event(event: &gdk::Event) -> Option { + if event_is_stylus(event) { + Some(gdk::InputSource::Pen) + } else if event_is_touchscreen(event) { + Some(gdk::InputSource::Touchscreen) + } else { + event.device().and_then(|d| Some(d.source())) + } +} + fn retrieve_pointer_elements( canvas: &RnCanvas, now: Instant, diff --git a/crates/rnote-ui/src/canvas/mod.rs b/crates/rnote-ui/src/canvas/mod.rs index 2b0b96109f..fa407a3637 100644 --- a/crates/rnote-ui/src/canvas/mod.rs +++ b/crates/rnote-ui/src/canvas/mod.rs @@ -63,6 +63,7 @@ mod imp { pub(crate) key_controller_im_context: IMMulticontext, pub(crate) drop_target: DropTarget, pub(crate) drawing_cursor_enabled: Cell, + pub(crate) pen_input_source: Cell>, pub(crate) engine: RefCell, pub(crate) engine_task_handler_handle: RefCell>>, @@ -156,6 +157,7 @@ mod imp { key_controller_im_context, drop_target, drawing_cursor_enabled: Cell::new(false), + pen_input_source: Cell::new(None), engine: RefCell::new(engine), engine_task_handler_handle: RefCell::new(None), @@ -685,6 +687,16 @@ impl RnCanvas { } } + #[allow(unused)] + pub(crate) fn pen_input_source(&self) -> Option { + self.imp().pen_input_source.get() + } + + #[allow(unused)] + pub(crate) fn set_pen_input_source(&self, pen_input_source: Option) { + self.imp().pen_input_source.set(pen_input_source); + } + #[allow(unused)] pub(crate) fn show_drawing_cursor(&self) -> bool { self.property::("show-drawing-cursor")