fix(compositor): correct remaining Smithay 0.7 API issues

- Remove nonexistent TextInputHandler trait impl
- Add missing cursor_position_hint to PointerConstraintsHandler
- Rewrite winit/drm backends: ListeningSocketSource + insert_client
 for per-client WeftClientState; Generic<Display<D>> for dispatch
- Remove calloop direct dep; use via smithay::reexports::calloop
- Remove unused imports in input.rs
This commit is contained in:
Marco Allegretti 2026-03-10 21:20:28 +01:00
parent f70a998f67
commit 3ebe50ef31
5 changed files with 105 additions and 83 deletions

View file

@ -21,7 +21,6 @@ smithay = { version = "0.7", default-features = false, features = [
"wayland_frontend", "wayland_frontend",
"desktop", "desktop",
] } ] }
calloop = { version = "0.14", features = ["executor"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
anyhow = "1" anyhow = "1"

View file

@ -5,66 +5,68 @@ pub fn run() -> anyhow::Result<()> {
} }
// Linux DRM/KMS backend. // Linux DRM/KMS backend.
// GPU enumeration and rendering are deferred; this skeleton establishes the
// session, socket, and event loop that the full implementation will extend.
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub fn run() -> anyhow::Result<()> { pub fn run() -> anyhow::Result<()> {
use std::time::Duration; use std::sync::Arc;
use smithay::{ use smithay::{
backend::{ backend::{
allocator::gbm::{GbmAllocator, GbmBufferFlags, GbmDevice}, session::{libseat::LibSeatSession, Session},
drm::{DrmDevice, DrmDeviceFd, DrmNode, NodeType},
egl::EGLDevice,
libinput::{LibinputInputBackend, LibinputSessionInterface},
renderer::{
damage::OutputDamageTracker,
gles::GlesRenderer,
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer},
},
session::{
libseat::{LibSeatSession, LibSeatSessionNotifier},
Session,
},
udev::{UdevBackend, UdevEvent}, udev::{UdevBackend, UdevEvent},
}, },
desktop::{space::space_render_elements, Space, Window}, reexports::calloop::{generic::Generic, EventLoop, Interest, Mode, PostAction},
output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel}, wayland::socket::ListeningSocketSource,
reexports::{
calloop::{
timer::{TimeoutAction, Timer},
EventLoop, Interest, Mode, PostAction,
},
wayland_server::Display,
},
utils::Transform,
}; };
use crate::{input, state::WeftCompositorState}; use crate::state::{WeftClientState, WeftCompositorState};
let mut display: Display<WeftCompositorState> = Display::new()?; let mut display =
smithay::reexports::wayland_server::Display::<WeftCompositorState>::new()?;
let display_handle = display.handle(); let display_handle = display.handle();
let mut event_loop: EventLoop<'static, WeftCompositorState> = EventLoop::try_new()?; let mut event_loop: EventLoop<'static, WeftCompositorState> = EventLoop::try_new()?;
let loop_handle = event_loop.handle(); let loop_handle = event_loop.handle();
let loop_signal = event_loop.get_signal(); let loop_signal = event_loop.get_signal();
// Open a libseat session to gain DRM device access without root. // Gain DRM device access without root via libseat.
let (session, notifier) = LibSeatSession::new() let (session, _notifier) = LibSeatSession::new()
.map_err(|e| anyhow::anyhow!("libseat session failed: {e}"))?; .map_err(|e| anyhow::anyhow!("libseat session failed: {e}"))?;
// Discover GPU nodes via udev. let listening_socket = ListeningSocketSource::new_auto()
.map_err(|e| anyhow::anyhow!("Wayland socket creation failed: {e}"))?;
let socket_name = listening_socket.socket_name().to_os_string();
std::env::set_var("WAYLAND_DISPLAY", &socket_name);
tracing::info!(?socket_name, "Wayland compositor socket open");
loop_handle
.insert_source(listening_socket, |client_stream, _, state| {
state
.display_handle
.insert_client(client_stream, Arc::new(WeftClientState::default()))
.unwrap();
})
.map_err(|e| anyhow::anyhow!("socket source insertion failed: {e}"))?;
loop_handle
.insert_source(
Generic::new(display, Interest::READ, Mode::Level),
|_, display, state| {
// Safety: the display is owned by this Generic source and is never
// dropped while the event loop runs.
unsafe {
display.get_mut().dispatch_clients(state).unwrap();
}
Ok(PostAction::Continue)
},
)
.map_err(|e| anyhow::anyhow!("display source insertion failed: {e}"))?;
// Enumerate GPU nodes via udev; hotplug events arrive through calloop.
let udev_backend = UdevBackend::new(session.seat())?; let udev_backend = UdevBackend::new(session.seat())?;
loop_handle
let mut state = WeftCompositorState::new( .insert_source(udev_backend, move |event, _, _state| match event {
display_handle,
loop_signal.clone(),
loop_handle.clone(),
session.seat(),
);
// Register the udev backend with calloop so device hotplug is handled.
loop_handle.insert_source(udev_backend, {
let signal = loop_signal.clone();
move |event, _, _state| match event {
UdevEvent::Added { device_id, path } => { UdevEvent::Added { device_id, path } => {
tracing::info!(?device_id, ?path, "GPU device added"); tracing::info!(?device_id, ?path, "GPU device added");
} }
@ -73,22 +75,19 @@ pub fn run() -> anyhow::Result<()> {
} }
UdevEvent::Removed { device_id } => { UdevEvent::Removed { device_id } => {
tracing::info!(?device_id, "GPU device removed"); tracing::info!(?device_id, "GPU device removed");
signal.stop();
} }
} })
})?; .map_err(|e| anyhow::anyhow!("udev source insertion failed: {e}"))?;
let mut state = WeftCompositorState::new(
display_handle,
loop_signal,
loop_handle,
session.seat(),
);
tracing::info!("DRM/KMS backend initialised; entering event loop"); tracing::info!("DRM/KMS backend initialised; entering event loop");
event_loop.run(None, &mut state, |_| {})?;
loop {
display.dispatch_clients(&mut state)?;
display.flush_clients()?;
event_loop.dispatch(Some(Duration::from_millis(16)), &mut state)?;
if loop_signal.is_stopped() {
break;
}
}
Ok(()) Ok(())
} }

View file

@ -1,4 +1,4 @@
use std::time::Duration; use std::{sync::Arc, time::Duration};
use smithay::{ use smithay::{
backend::{ backend::{
@ -9,11 +9,15 @@ use smithay::{
winit::{self, WinitEvent}, winit::{self, WinitEvent},
}, },
output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel}, output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel},
reexports::calloop::EventLoop, reexports::calloop::{generic::Generic, EventLoop, Interest, Mode, PostAction},
utils::{Rectangle, Transform}, utils::{Rectangle, Transform},
wayland::socket::ListeningSocketSource,
}; };
use crate::{input, state::WeftCompositorState}; use crate::{
input,
state::{WeftClientState, WeftCompositorState},
};
pub fn run() -> anyhow::Result<()> { pub fn run() -> anyhow::Result<()> {
let mut display = let mut display =
@ -49,13 +53,38 @@ pub fn run() -> anyhow::Result<()> {
); );
output.set_preferred(mode); output.set_preferred(mode);
// Open the Wayland socket so clients can connect. // Create the listening socket; each connecting client is inserted with
let socket_name = display // default per-client data so CompositorHandler::client_compositor_state works.
.add_socket_auto() let listening_socket = ListeningSocketSource::new_auto()
.map_err(|e| anyhow::anyhow!("Wayland socket creation failed: {e}"))?; .map_err(|e| anyhow::anyhow!("Wayland socket creation failed: {e}"))?;
let socket_name = listening_socket.socket_name().to_os_string();
std::env::set_var("WAYLAND_DISPLAY", &socket_name); std::env::set_var("WAYLAND_DISPLAY", &socket_name);
tracing::info!(?socket_name, "Wayland compositor socket open"); tracing::info!(?socket_name, "Wayland compositor socket open");
loop_handle
.insert_source(listening_socket, |client_stream, _, state| {
state
.display_handle
.insert_client(client_stream, Arc::new(WeftClientState::default()))
.unwrap();
})
.map_err(|e| anyhow::anyhow!("socket source insertion failed: {e}"))?;
// Register the display fd so calloop dispatches Wayland client messages when readable.
loop_handle
.insert_source(
Generic::new(display, Interest::READ, Mode::Level),
|_, display, state| {
// Safety: the display is owned by this Generic source and is never dropped
// while the event loop runs.
unsafe {
display.get_mut().dispatch_clients(state).unwrap();
}
Ok(PostAction::Continue)
},
)
.map_err(|e| anyhow::anyhow!("display source insertion failed: {e}"))?;
let mut state = WeftCompositorState::new( let mut state = WeftCompositorState::new(
display_handle, display_handle,
loop_signal, loop_signal,
@ -67,8 +96,8 @@ pub fn run() -> anyhow::Result<()> {
let mut damage_tracker = OutputDamageTracker::from_output(&output); let mut damage_tracker = OutputDamageTracker::from_output(&output);
let start_time = std::time::Instant::now(); let start_time = std::time::Instant::now();
// WinitEventLoop implements calloop's EventSource; insert it so Winit events // WinitEventLoop implements calloop's EventSource; Winit events arrive
// arrive through the same dispatch loop as all other compositor sources. // through the same dispatch loop as all other compositor sources.
loop_handle loop_handle
.insert_source(winit, move |event, _, state| match event { .insert_source(winit, move |event, _, state| match event {
WinitEvent::Resized { size, .. } => { WinitEvent::Resized { size, .. } => {
@ -123,7 +152,7 @@ pub fn run() -> anyhow::Result<()> {
state.popups.cleanup(); state.popups.cleanup();
let _ = state.display_handle.flush_clients(); let _ = state.display_handle.flush_clients();
// Request the next redraw to drive continuous rendering. // Request next redraw to drive continuous rendering.
backend.window().request_redraw(); backend.window().request_redraw();
} }
WinitEvent::CloseRequested => { WinitEvent::CloseRequested => {
@ -134,13 +163,7 @@ pub fn run() -> anyhow::Result<()> {
}) })
.map_err(|e| anyhow::anyhow!("winit source insertion failed: {e}"))?; .map_err(|e| anyhow::anyhow!("winit source insertion failed: {e}"))?;
// The idle callback dispatches pending Wayland client requests after each event_loop.run(None, &mut state, |_| {})?;
// calloop iteration so protocol handlers in state receive them promptly.
event_loop.run(None, &mut state, move |state| {
if let Err(e) = display.dispatch_clients(state) {
tracing::error!("Wayland client dispatch failed: {e}");
}
})?;
Ok(()) Ok(())
} }

View file

@ -8,10 +8,9 @@ use smithay::{
TouchCancelEvent, TouchDownEvent, TouchFrameEvent, TouchMotionEvent, TouchUpEvent, TouchCancelEvent, TouchDownEvent, TouchFrameEvent, TouchMotionEvent, TouchUpEvent,
}, },
input::{ input::{
keyboard::{FilterResult, KeysymHandle, ModifiersState}, keyboard::FilterResult,
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent}, pointer::{AxisFrame, ButtonEvent, MotionEvent},
}, },
reexports::wayland_server::protocol::wl_pointer,
utils::{Logical, Point, Serial, SERIAL_COUNTER}, utils::{Logical, Point, Serial, SERIAL_COUNTER},
}; };

View file

@ -31,12 +31,13 @@ use smithay::{
output::OutputManagerState, output::OutputManagerState,
pointer_constraints::{PointerConstraintsHandler, PointerConstraintsState}, pointer_constraints::{PointerConstraintsHandler, PointerConstraintsState},
presentation::{PresentationHandler, PresentationState}, presentation::{PresentationHandler, PresentationState},
seat::WaylandFocus,
shell::{ shell::{
wlr_layer::{Layer, LayerSurface, WlrLayerShellHandler, WlrLayerShellState}, wlr_layer::{Layer, LayerSurface, WlrLayerShellHandler, WlrLayerShellState},
xdg::{PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState}, xdg::{PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState},
}, },
shm::{ShmHandler, ShmState}, shm::{ShmHandler, ShmState},
text_input::{TextInputHandler, TextInputManagerState}, text_input::TextInputManagerState,
}, },
}; };
@ -310,14 +311,7 @@ impl PresentationHandler for WeftCompositorState {
delegate_presentation!(WeftCompositorState); delegate_presentation!(WeftCompositorState);
// --- TextInputHandler --- // TextInputManagerState has no handler trait; delegate macro only requires SeatHandler.
impl TextInputHandler for WeftCompositorState {
fn text_input_state(&mut self) -> &mut TextInputManagerState {
&mut self.text_input_state
}
}
delegate_text_input_manager!(WeftCompositorState); delegate_text_input_manager!(WeftCompositorState);
// --- InputMethodHandler --- // --- InputMethodHandler ---
@ -352,6 +346,14 @@ impl PointerConstraintsHandler for WeftCompositorState {
_pointer: &smithay::input::pointer::PointerHandle<Self>, _pointer: &smithay::input::pointer::PointerHandle<Self>,
) { ) {
} }
fn cursor_position_hint(
&mut self,
_surface: &WlSurface,
_pointer: &smithay::input::pointer::PointerHandle<Self>,
_location: smithay::utils::Point<f64, Logical>,
) {
}
} }
delegate_pointer_constraints!(WeftCompositorState); delegate_pointer_constraints!(WeftCompositorState);