mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-26 18:06:26 +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
|
- name: Set up crate rustdoc link
|
||||||
run: |
|
run: |
|
||||||
rgb_version=`grep 'rgb = ' internal/core/Cargo.toml | sed 's/^.*"\(.*\)"/\1/'`
|
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
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,7 @@ unicode-segmentation = { version = "1.12.0" }
|
||||||
glow = { version = "0.16" }
|
glow = { version = "0.16" }
|
||||||
tikv-jemallocator = { version = "0.6" }
|
tikv-jemallocator = { version = "0.6" }
|
||||||
wgpu-26 = { package = "wgpu", version = "26", default-features = false }
|
wgpu-26 = { package = "wgpu", version = "26", default-features = false }
|
||||||
|
input = { version = "0.9.0", default-features = false }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
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"]
|
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]
|
[dependencies]
|
||||||
i-slint-core = { workspace = true }
|
i-slint-core = { workspace = true }
|
||||||
slint-macros = { workspace = true }
|
slint-macros = { workspace = true }
|
||||||
|
|
@ -273,5 +287,6 @@ features = [
|
||||||
"raw-window-handle-06",
|
"raw-window-handle-06",
|
||||||
"unstable-wgpu-26",
|
"unstable-wgpu-26",
|
||||||
"unstable-winit-030",
|
"unstable-winit-030",
|
||||||
|
"unstable-input-09",
|
||||||
]
|
]
|
||||||
rustdoc-args = ["--generate-link-to-definition"]
|
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 }
|
i-slint-renderer-femtovg = { workspace = true, features = ["default"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
input = { version = "0.9.0" }
|
input = { workspace = true, default-features = true }
|
||||||
xkbcommon = { version = "0.8.0" }
|
xkbcommon = { version = "0.8.0" }
|
||||||
calloop = { version = "0.14.1" }
|
calloop = { version = "0.14.1" }
|
||||||
libseat = { version = "0.2.1", optional = true, default-features = false }
|
libseat = { version = "0.2.1", optional = true, default-features = false }
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use calloop::EventLoop;
|
||||||
use i_slint_core::platform::PlatformError;
|
use i_slint_core::platform::PlatformError;
|
||||||
|
|
||||||
use crate::fullscreenwindowadapter::FullscreenWindowAdapter;
|
use crate::fullscreenwindowadapter::FullscreenWindowAdapter;
|
||||||
|
use crate::BackendBuilder;
|
||||||
|
|
||||||
#[cfg(not(any(target_family = "windows", target_vendor = "apple", target_arch = "wasm32")))]
|
#[cfg(not(any(target_family = "windows", target_vendor = "apple", target_arch = "wasm32")))]
|
||||||
mod input;
|
mod input;
|
||||||
|
|
@ -76,16 +77,14 @@ pub struct Backend {
|
||||||
>,
|
>,
|
||||||
sel_clipboard: RefCell<Option<String>>,
|
sel_clipboard: RefCell<Option<String>>,
|
||||||
clipboard: RefCell<Option<String>>,
|
clipboard: RefCell<Option<String>>,
|
||||||
|
input_event_hook: Option<Box<dyn Fn(&::input::Event) -> bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
pub fn new() -> Result<Self, PlatformError> {
|
pub fn build(builder: BackendBuilder) -> Result<Self, PlatformError> {
|
||||||
Self::new_with_renderer_by_name(None)
|
|
||||||
}
|
|
||||||
pub fn new_with_renderer_by_name(renderer_name: Option<&str>) -> Result<Self, PlatformError> {
|
|
||||||
let (user_event_sender, user_event_receiver) = calloop::channel::channel();
|
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")]
|
#[cfg(feature = "renderer-skia-vulkan")]
|
||||||
Some("skia-vulkan") => crate::renderer::skia::SkiaRendererAdapter::new_vulkan,
|
Some("skia-vulkan") => crate::renderer::skia::SkiaRendererAdapter::new_vulkan,
|
||||||
#[cfg(feature = "renderer-skia-opengl")]
|
#[cfg(feature = "renderer-skia-opengl")]
|
||||||
|
|
@ -143,6 +142,7 @@ impl Backend {
|
||||||
renderer_factory,
|
renderer_factory,
|
||||||
sel_clipboard: Default::default(),
|
sel_clipboard: Default::default(),
|
||||||
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(),
|
&event_loop.handle(),
|
||||||
#[cfg(feature = "libseat")]
|
#[cfg(feature = "libseat")]
|
||||||
&self.seat,
|
&self.seat,
|
||||||
|
&self.input_event_hook,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let Some(user_event_receiver) = self.user_event_receiver.borrow_mut().take() else {
|
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)]
|
#[derive(Default)]
|
||||||
pub struct LoopData {}
|
pub struct LoopData {}
|
||||||
|
|
||||||
pub type EventLoopHandle<'a> = calloop::LoopHandle<'a, LoopData>;
|
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ pub struct LibInputHandler<'a> {
|
||||||
last_touch_pos: LogicalPosition,
|
last_touch_pos: LogicalPosition,
|
||||||
window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,
|
window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,
|
||||||
keystate: Option<xkb::State>,
|
keystate: Option<xkb::State>,
|
||||||
|
input_event_hook: &'a Option<Box<dyn Fn(&::input::Event) -> bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LibInputHandler<'a> {
|
impl<'a> LibInputHandler<'a> {
|
||||||
|
|
@ -126,6 +127,7 @@ impl<'a> LibInputHandler<'a> {
|
||||||
window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,
|
window: &'a RefCell<Option<Rc<FullscreenWindowAdapter>>>,
|
||||||
event_loop_handle: &calloop::LoopHandle<'a, T>,
|
event_loop_handle: &calloop::LoopHandle<'a, T>,
|
||||||
#[cfg(feature = "libseat")] seat: &'a Rc<RefCell<libseat::Seat>>,
|
#[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> {
|
) -> Result<Pin<Rc<Property<Option<LogicalPosition>>>>, PlatformError> {
|
||||||
#[cfg(feature = "libseat")]
|
#[cfg(feature = "libseat")]
|
||||||
let libinput = SeatWrap::new(seat);
|
let libinput = SeatWrap::new(seat);
|
||||||
|
|
@ -141,6 +143,7 @@ impl<'a> LibInputHandler<'a> {
|
||||||
last_touch_pos: Default::default(),
|
last_touch_pos: Default::default(),
|
||||||
window,
|
window,
|
||||||
keystate: Default::default(),
|
keystate: Default::default(),
|
||||||
|
input_event_hook,
|
||||||
};
|
};
|
||||||
|
|
||||||
event_loop_handle
|
event_loop_handle
|
||||||
|
|
@ -179,6 +182,9 @@ impl<'a> calloop::EventSource for LibInputHandler<'a> {
|
||||||
let screen_size = window.size().to_logical(window.scale_factor());
|
let screen_size = window.size().to_logical(window.scale_factor());
|
||||||
|
|
||||||
for event in &mut self.libinput {
|
for event in &mut self.libinput {
|
||||||
|
if self.input_event_hook.as_ref().map_or(false, |hook| hook(&event)) {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
match event {
|
match event {
|
||||||
input::Event::Pointer(pointer_event) => {
|
input::Event::Pointer(pointer_event) => {
|
||||||
match pointer_event {
|
match pointer_event {
|
||||||
|
|
|
||||||
|
|
@ -80,12 +80,37 @@ mod renderer {
|
||||||
mod calloop_backend;
|
mod calloop_backend;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub use calloop_backend::*;
|
use calloop_backend::*;
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
mod noop_backend;
|
mod noop_backend;
|
||||||
|
use i_slint_core::api::PlatformError;
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[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)]
|
#[doc(hidden)]
|
||||||
pub type NativeWidgets = ();
|
pub type NativeWidgets = ();
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,7 @@ use i_slint_core::platform::PlatformError;
|
||||||
pub struct Backend {}
|
pub struct Backend {}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
pub fn new() -> Result<Self, PlatformError> {
|
pub fn build(_builder: super::BackendBuilder) -> Result<Self, PlatformError> {
|
||||||
Self::new_with_renderer_by_name(None)
|
|
||||||
}
|
|
||||||
pub fn new_with_renderer_by_name(_renderer_name: Option<&str>) -> Result<Self, PlatformError> {
|
|
||||||
Ok(Backend {})
|
Ok(Backend {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ unstable-wgpu-26 = [
|
||||||
|
|
||||||
unstable-winit-030 = ["i-slint-backend-winit"]
|
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
|
# note that default enable the i-slint-backend-qt, but not its enable feature
|
||||||
default = ["i-slint-backend-qt", "backend-winit"]
|
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]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
i-slint-backend-linuxkms = { workspace = true, features = ["default"], optional = true }
|
i-slint-backend-linuxkms = { workspace = true, features = ["default"], optional = true }
|
||||||
|
input = { workspace = true, optional = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
i-slint-common = { workspace = true }
|
i-slint-common = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ pub struct BackendSelector {
|
||||||
>,
|
>,
|
||||||
#[cfg(feature = "unstable-winit-030")]
|
#[cfg(feature = "unstable-winit-030")]
|
||||||
winit_event_loop_builder: Option<i_slint_backend_winit::EventLoopBuilder>,
|
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 {
|
impl BackendSelector {
|
||||||
|
|
@ -173,6 +175,25 @@ impl BackendSelector {
|
||||||
self
|
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
|
/// 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
|
/// 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,
|
/// 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());
|
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(
|
let mut builder = i_slint_backend_linuxkms::BackendBuilder::default();
|
||||||
self.renderer.as_deref(),
|
|
||||||
)?)
|
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")]
|
#[cfg(feature = "i-slint-backend-winit")]
|
||||||
"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"))]
|
#[cfg(all(feature = "i-slint-backend-linuxkms", target_os = "linux"))]
|
||||||
fn create_linuxkms_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {
|
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! {
|
cfg_if::cfg_if! {
|
||||||
|
|
@ -101,7 +101,13 @@ cfg_if::cfg_if! {
|
||||||
#[cfg(feature = "i-slint-backend-winit")]
|
#[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>),
|
"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"))]
|
#[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