mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-22 08:12:48 +00:00
LinuxKMS: Add support for libinput event hooks
Hidden behind the unstable-input-09 feature, the BackendSelector now exposes with_input_090_event_hook, which takes a callback that's invoked for every event received from libinput.
This commit is contained in:
parent
8ed0fd327e
commit
0cfe06b810
11 changed files with 102 additions and 20 deletions
2
.github/workflows/build_docs.yaml
vendored
2
.github/workflows/build_docs.yaml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
- name: Set up crate rustdoc link
|
||||
run: |
|
||||
rgb_version=`grep 'rgb = ' internal/core/Cargo.toml | sed 's/^.*"\(.*\)"/\1/'`
|
||||
echo "RUSTDOCFLAGS=$RUSTDOCFLAGS --extern-html-root-url rgb=https://docs.rs/rgb/$rgb_version/ --extern-html-root-url android_activity=https://docs.rs/android-activity/0.5/ --extern-html-root-url raw_window_handle=https://docs.rs/raw_window_handle/0.6 --extern-html-root-url winit=https://docs.rs/winit/0.30 --extern-html-root-url wgpu=https://docs.rs/wgpu/26" >> $GITHUB_ENV
|
||||
echo "RUSTDOCFLAGS=$RUSTDOCFLAGS --extern-html-root-url rgb=https://docs.rs/rgb/$rgb_version/ --extern-html-root-url android_activity=https://docs.rs/android-activity/0.5/ --extern-html-root-url raw_window_handle=https://docs.rs/raw_window_handle/0.6 --extern-html-root-url winit=https://docs.rs/winit/0.30 --extern-html-root-url wgpu=https://docs.rs/wgpu/26 --extern-html-root-url input=https://docs.rs/input/0.9" >> $GITHUB_ENV
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
|
|
@ -167,6 +167,7 @@ unicode-segmentation = { version = "1.12.0" }
|
|||
glow = { version = "0.16" }
|
||||
tikv-jemallocator = { version = "0.6" }
|
||||
wgpu-26 = { package = "wgpu", version = "26", default-features = false }
|
||||
input = { version = "0.9.0", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -215,6 +215,20 @@ unstable-wgpu-26 = ["i-slint-core/unstable-wgpu-26", "i-slint-backend-selector/u
|
|||
## ```
|
||||
unstable-winit-030 = ["backend-winit", "dep:i-slint-backend-winit", "i-slint-backend-selector/unstable-winit-030"]
|
||||
|
||||
|
||||
## Enable support for exposing [libinput](https://docs.rs/input/latest/input/index.html) related APIs in the LinuxKMS backend.
|
||||
##
|
||||
## APIs guarded with this feature are *NOT* subject to the usual Slint API stability guarantees. This feature as well as the APIs changed or removed
|
||||
## in future minor releases of Slint, likely to be replaced by a feature with a similar name but the input version suffix being bumped.
|
||||
##
|
||||
## To avoid unintended compilation failures, we recommend to use the [tilde requirement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#tilde-requirements)
|
||||
## in your `Cargo.toml` when enabling this feature:
|
||||
##
|
||||
## ```toml
|
||||
## slint = { version = "~1.13", features = ["unstable-input-09"] }
|
||||
## ```
|
||||
unstable-input-09 = ["i-slint-backend-selector/unstable-input-09"]
|
||||
|
||||
[dependencies]
|
||||
i-slint-core = { workspace = true }
|
||||
slint-macros = { workspace = true }
|
||||
|
@ -273,5 +287,6 @@ features = [
|
|||
"raw-window-handle-06",
|
||||
"unstable-wgpu-26",
|
||||
"unstable-winit-030",
|
||||
"unstable-input-09",
|
||||
]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
|
|
@ -33,7 +33,7 @@ i-slint-renderer-skia = { workspace = true, features = ["default", "kms"], optio
|
|||
i-slint-renderer-femtovg = { workspace = true, features = ["default"], optional = true }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
input = { version = "0.9.0" }
|
||||
input = { workspace = true, default-features = true }
|
||||
xkbcommon = { version = "0.8.0" }
|
||||
calloop = { version = "0.14.1" }
|
||||
libseat = { version = "0.2.1", optional = true, default-features = false }
|
||||
|
|
|
@ -17,6 +17,7 @@ use calloop::EventLoop;
|
|||
use i_slint_core::platform::PlatformError;
|
||||
|
||||
use crate::fullscreenwindowadapter::FullscreenWindowAdapter;
|
||||
use crate::BackendBuilder;
|
||||
|
||||
#[cfg(not(any(target_family = "windows", target_vendor = "apple", target_arch = "wasm32")))]
|
||||
mod input;
|
||||
|
@ -76,16 +77,14 @@ pub struct Backend {
|
|||
>,
|
||||
sel_clipboard: RefCell<Option<String>>,
|
||||
clipboard: RefCell<Option<String>>,
|
||||
input_event_hook: Option<Box<dyn Fn(&::input::Event) -> bool>>,
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
pub fn new() -> Result<Self, PlatformError> {
|
||||
Self::new_with_renderer_by_name(None)
|
||||
}
|
||||
pub fn new_with_renderer_by_name(renderer_name: Option<&str>) -> Result<Self, PlatformError> {
|
||||
pub fn build(builder: BackendBuilder) -> Result<Self, PlatformError> {
|
||||
let (user_event_sender, user_event_receiver) = calloop::channel::channel();
|
||||
|
||||
let renderer_factory = match renderer_name {
|
||||
let renderer_factory = match builder.renderer_name.as_deref() {
|
||||
#[cfg(feature = "renderer-skia-vulkan")]
|
||||
Some("skia-vulkan") => crate::renderer::skia::SkiaRendererAdapter::new_vulkan,
|
||||
#[cfg(feature = "renderer-skia-opengl")]
|
||||
|
@ -143,6 +142,7 @@ impl Backend {
|
|||
renderer_factory,
|
||||
sel_clipboard: Default::default(),
|
||||
clipboard: Default::default(),
|
||||
input_event_hook: builder.input_event_hook,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -216,6 +216,7 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
&event_loop.handle(),
|
||||
#[cfg(feature = "libseat")]
|
||||
&self.seat,
|
||||
&self.input_event_hook,
|
||||
)?;
|
||||
|
||||
let Some(user_event_receiver) = self.user_event_receiver.borrow_mut().take() else {
|
||||
|
@ -296,5 +297,3 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct LoopData {}
|
||||
|
||||
pub type EventLoopHandle<'a> = calloop::LoopHandle<'a, LoopData>;
|
||||
|
|
|
@ -119,6 +119,7 @@ pub struct LibInputHandler<'a> {
|
|||
last_touch_pos: LogicalPosition,
|
||||
window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,
|
||||
keystate: Option<xkb::State>,
|
||||
input_event_hook: &'a Option<Box<dyn Fn(&::input::Event) -> bool>>,
|
||||
}
|
||||
|
||||
impl<'a> LibInputHandler<'a> {
|
||||
|
@ -126,6 +127,7 @@ impl<'a> LibInputHandler<'a> {
|
|||
window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,
|
||||
event_loop_handle: &calloop::LoopHandle<'a, T>,
|
||||
#[cfg(feature = "libseat")] seat: &'a Rc<RefCell<libseat::Seat>>,
|
||||
input_event_hook: &'a Option<Box<dyn Fn(&::input::Event) -> bool>>,
|
||||
) -> Result<Pin<Rc<Property<Option<LogicalPosition>>>>, PlatformError> {
|
||||
#[cfg(feature = "libseat")]
|
||||
let libinput = SeatWrap::new(seat);
|
||||
|
@ -141,6 +143,7 @@ impl<'a> LibInputHandler<'a> {
|
|||
last_touch_pos: Default::default(),
|
||||
window,
|
||||
keystate: Default::default(),
|
||||
input_event_hook,
|
||||
};
|
||||
|
||||
event_loop_handle
|
||||
|
@ -179,6 +182,9 @@ impl<'a> calloop::EventSource for LibInputHandler<'a> {
|
|||
let screen_size = window.size().to_logical(window.scale_factor());
|
||||
|
||||
for event in &mut self.libinput {
|
||||
if self.input_event_hook.as_ref().map_or(false, |hook| hook(&event)) {
|
||||
continue;
|
||||
};
|
||||
match event {
|
||||
input::Event::Pointer(pointer_event) => {
|
||||
match pointer_event {
|
||||
|
|
|
@ -80,12 +80,37 @@ mod renderer {
|
|||
mod calloop_backend;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use calloop_backend::*;
|
||||
use calloop_backend::*;
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
mod noop_backend;
|
||||
use i_slint_core::api::PlatformError;
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub use noop_backend::*;
|
||||
use noop_backend::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BackendBuilder {
|
||||
pub(crate) renderer_name: Option<String>,
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) input_event_hook: Option<Box<dyn Fn(&input::Event) -> bool>>,
|
||||
}
|
||||
|
||||
impl BackendBuilder {
|
||||
pub fn with_renderer_name(mut self, name: String) -> Self {
|
||||
self.renderer_name = Some(name);
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn with_input_event_hook(mut self, event_hook: Box<dyn Fn(&input::Event) -> bool>) -> Self {
|
||||
self.input_event_hook = Some(event_hook);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Backend, PlatformError> {
|
||||
Backend::build(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type NativeWidgets = ();
|
||||
|
|
|
@ -5,10 +5,7 @@ use i_slint_core::platform::PlatformError;
|
|||
pub struct Backend {}
|
||||
|
||||
impl Backend {
|
||||
pub fn new() -> Result<Self, PlatformError> {
|
||||
Self::new_with_renderer_by_name(None)
|
||||
}
|
||||
pub fn new_with_renderer_by_name(_renderer_name: Option<&str>) -> Result<Self, PlatformError> {
|
||||
pub fn build(_builder: super::BackendBuilder) -> Result<Self, PlatformError> {
|
||||
Ok(Backend {})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ unstable-wgpu-26 = [
|
|||
|
||||
unstable-winit-030 = ["i-slint-backend-winit"]
|
||||
|
||||
unstable-input-09 = ["dep:input"]
|
||||
|
||||
# note that default enable the i-slint-backend-qt, but not its enable feature
|
||||
default = ["i-slint-backend-qt", "backend-winit"]
|
||||
|
||||
|
@ -76,6 +78,7 @@ i-slint-backend-qt = { workspace = true, optional = true }
|
|||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
i-slint-backend-linuxkms = { workspace = true, features = ["default"], optional = true }
|
||||
input = { workspace = true, optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
i-slint-common = { workspace = true }
|
||||
|
|
|
@ -44,6 +44,8 @@ pub struct BackendSelector {
|
|||
>,
|
||||
#[cfg(feature = "unstable-winit-030")]
|
||||
winit_event_loop_builder: Option<i_slint_backend_winit::EventLoopBuilder>,
|
||||
#[cfg(all(target_os = "linux", feature = "unstable-input-09"))]
|
||||
input_090_event_hook: Option<Box<dyn Fn(&input::Event) -> bool>>,
|
||||
}
|
||||
|
||||
impl BackendSelector {
|
||||
|
@ -173,6 +175,25 @@ impl BackendSelector {
|
|||
self
|
||||
}
|
||||
|
||||
#[i_slint_core_macros::slint_doc]
|
||||
/// Configures this builder to use the specified libinput event filter hook when the LinuxKMS backend
|
||||
/// is selected.
|
||||
///
|
||||
/// The provided hook is invoked for every event received. If the function returns true, the event is
|
||||
/// not dispatched further.
|
||||
///
|
||||
/// *Note*: This function is behind the [`unstable-input-09` feature flag](slint:rust:slint/docs/cargo_features/#backends)
|
||||
/// and may be removed or changed in future minor releases, as new major Winit releases become available.
|
||||
#[must_use]
|
||||
#[cfg(all(target_os = "linux", feature = "unstable-input-09"))]
|
||||
pub fn with_input_090_event_hook(
|
||||
mut self,
|
||||
event_hook: impl Fn(&input::Event) -> bool + 'static,
|
||||
) -> Self {
|
||||
self.input_090_event_hook = Some(Box::new(event_hook));
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds the requirement that the selected renderer must match the given name. This is
|
||||
/// equivalent to setting the `SLINT_BACKEND=name` environment variable and requires
|
||||
/// that the corresponding renderer feature is enabled. For example, to select the Skia renderer,
|
||||
|
@ -237,9 +258,18 @@ impl BackendSelector {
|
|||
return Err("The linuxkms backend does not implement renderer selection by graphics API".into());
|
||||
}
|
||||
|
||||
Box::new(i_slint_backend_linuxkms::Backend::new_with_renderer_by_name(
|
||||
self.renderer.as_deref(),
|
||||
)?)
|
||||
let mut builder = i_slint_backend_linuxkms::BackendBuilder::default();
|
||||
|
||||
if let Some(renderer_name) = self.renderer.as_ref() {
|
||||
builder = builder.with_renderer_name(renderer_name.into());
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "unstable-input-09"))]
|
||||
if let Some(event_hook) = self.input_090_event_hook.take() {
|
||||
builder = builder.with_input_event_hook(event_hook);
|
||||
}
|
||||
|
||||
Box::new(builder.build()?)
|
||||
}
|
||||
#[cfg(feature = "i-slint-backend-winit")]
|
||||
"winit" => {
|
||||
|
|
|
@ -32,7 +32,7 @@ fn create_winit_backend() -> Result<Box<dyn Platform + 'static>, PlatformError>
|
|||
|
||||
#[cfg(all(feature = "i-slint-backend-linuxkms", target_os = "linux"))]
|
||||
fn create_linuxkms_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {
|
||||
Ok(Box::new(i_slint_backend_linuxkms::Backend::new()?))
|
||||
Ok(Box::new(i_slint_backend_linuxkms::BackendBuilder::default().build()?))
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
|
@ -101,7 +101,13 @@ cfg_if::cfg_if! {
|
|||
#[cfg(feature = "i-slint-backend-winit")]
|
||||
"winit" => return i_slint_backend_winit::Backend::new_with_renderer_by_name((!_renderer.is_empty()).then_some(_renderer)).map(|b| Box::new(b) as Box<dyn Platform + 'static>),
|
||||
#[cfg(all(feature = "i-slint-backend-linuxkms", target_os = "linux"))]
|
||||
"linuxkms" => return i_slint_backend_linuxkms::Backend::new_with_renderer_by_name((!_renderer.is_empty()).then(|| _renderer)).map(|b| Box::new(b) as Box<dyn Platform + 'static>),
|
||||
"linuxkms" => {
|
||||
let mut builder = i_slint_backend_linuxkms::BackendBuilder::default();
|
||||
if !_renderer.is_empty() {
|
||||
builder = builder.with_renderer_name(_renderer.into());
|
||||
}
|
||||
return builder.build().map(|b| Box::new(b) as Box<dyn Platform + 'static>)
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue