fix(compositor): resolve all Linux cargo check/clippy/fmt failures

Fixes found by running cargo check + clippy -D warnings + fmt --check
on openSUSE Tumbleweed WSL2 (Rust 1.93.0).

input.rs:
- Add GestureBeginEvent (fingers()), GestureEndEvent (cancelled()),
 TouchEvent (slot()) supertrait imports
- Add explicit ::<B> turbofish to all handle_* dispatch calls Rust
 cannot reverse-infer B from an associated type bound
- Remove now-redundant specific gesture/touch event trait imports

state.rs:
- Add reposition_request to XdgShellHandler (E0046)
- Wrap protocol-level LayerSurface in desktop::LayerSurface::new for
 map_layer (E0308)
- Wrap std::env::set_var in unsafe block (E0133, stabilised unsafe in 1.80)
- Add #[allow(dead_code)] on WeftCompositorState protocol state fields
 are held for delegate dispatch, not yet consumed
- Remove spurious mut on display binding

drm.rs:
- Revert initialize_output arg to &output (&Output: Into<OutputModeSource>)
- Specify element type via ::<_, WaylandSurfaceRenderElement<_>> turbofish
 on initialize_output (E0277/E0308)
- Handle Result from scan_connectors, collect via IntoIterator (E0308)
- Wrap set_var in unsafe block; remove spurious mut on display
- Collapse nested if/if-let blocks per clippy::collapsible_if
- Remove useless .into() on render_node (clippy::useless_conversion)

drm_device.rs:
- Add #[allow(dead_code)] on WeftOutputSurface (device_id, global used
 in hotplug handling)

scripts/wsl-check.sh (new):
- WSL2 helper: injects libdisplay-info 0.2.9 shim .pc to satisfy the
 < 0.3.0 constraint while openSUSE ships 0.3.0; runs check/clippy/fmt
This commit is contained in:
Marco Allegretti 2026-03-10 23:43:43 +01:00
parent 4d21b8dba0
commit 732e572c43
5 changed files with 156 additions and 106 deletions

View file

@ -1,4 +1,4 @@
// Non-Linux: DRM/KMS backend is unavailable; callers must use --winit.
// Non-Linux: DRM/KMS backend is unavailable; callers must use --winit.
#[cfg(not(target_os = "linux"))]
pub fn run() -> anyhow::Result<()> {
anyhow::bail!("DRM/KMS backend requires Linux; pass --winit for development on other platforms")
@ -14,15 +14,15 @@ use anyhow::Context;
use smithay::{
backend::{
allocator::{
Fourcc, Modifier,
format::FormatSet,
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
Fourcc, Modifier,
},
drm::{
DrmDevice, DrmDeviceFd, DrmEvent, DrmNode, NodeType,
compositor::FrameFlags,
exporter::gbm::GbmFramebufferExporter,
output::{DrmOutputManager, DrmOutputRenderElements},
DrmDevice, DrmDeviceFd, DrmEvent, DrmNode, NodeType,
},
egl::{EGLDevice, EGLDisplay},
input::InputEvent,
@ -30,15 +30,15 @@ use smithay::{
renderer::{
element::surface::WaylandSurfaceRenderElement,
gles::GlesRenderer,
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer},
multigpu::{GpuManager, MultiRenderer, gbm::GbmGlesBackend},
},
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
session::{Event as SessionEvent, Session, libseat::LibSeatSession},
udev::{UdevBackend, UdevEvent, all_gpus, primary_gpu},
},
output::{Mode as WlMode, Output, PhysicalProperties, Subpixel},
reexports::{
calloop::{EventLoop, Interest, Mode, PostAction, generic::Generic},
drm::control::{connector, crtc, ModeTypeFlags},
drm::control::{ModeTypeFlags, connector, crtc},
input::{DeviceCapability, Libinput},
rustix::fs::OFlags,
wayland_server::Display,
@ -83,7 +83,7 @@ pub fn run() -> anyhow::Result<()> {
let mut event_loop: EventLoop<'static, WeftCompositorState> = EventLoop::try_new()?;
let loop_handle = event_loop.handle();
let mut display = Display::<WeftCompositorState>::new()?;
let display = Display::<WeftCompositorState>::new()?;
let display_handle = display.handle();
let (session, session_notifier) =
@ -98,7 +98,12 @@ pub fn run() -> anyhow::Result<()> {
primary_gpu(&seat_name)
.ok()
.flatten()
.and_then(|p| DrmNode::from_path(p).ok()?.node_with_type(NodeType::Render)?.ok())
.and_then(|p| {
DrmNode::from_path(p)
.ok()?
.node_with_type(NodeType::Render)?
.ok()
})
.or_else(|| {
all_gpus(&seat_name)
.unwrap_or_default()
@ -115,7 +120,7 @@ pub fn run() -> anyhow::Result<()> {
let listening_socket =
ListeningSocketSource::new_auto().context("failed to create Wayland socket")?;
let socket_name = listening_socket.socket_name().to_os_string();
std::env::set_var("WAYLAND_DISPLAY", &socket_name);
unsafe { std::env::set_var("WAYLAND_DISPLAY", &socket_name) };
tracing::info!(?socket_name, "Wayland socket open");
loop_handle
@ -140,13 +145,10 @@ pub fn run() -> anyhow::Result<()> {
)
.map_err(|e| anyhow::anyhow!("display source: {e}"))?;
let udev_backend =
UdevBackend::new(&seat_name).context("failed to create udev backend")?;
let udev_backend = UdevBackend::new(&seat_name).context("failed to create udev backend")?;
let mut libinput_ctx =
Libinput::new_with_udev::<LibinputSessionInterface<LibSeatSession>>(
session.clone().into(),
);
Libinput::new_with_udev::<LibinputSessionInterface<LibSeatSession>>(session.clone().into());
libinput_ctx
.udev_assign_seat(&seat_name)
.map_err(|_| anyhow::anyhow!("libinput seat assignment failed"))?;
@ -156,8 +158,9 @@ pub fn run() -> anyhow::Result<()> {
.insert_source(
libinput_backend,
move |mut event, _, state: &mut WeftCompositorState| {
if let InputEvent::DeviceAdded { device } = &mut event {
if device.has_capability(DeviceCapability::Keyboard) {
if let InputEvent::DeviceAdded { device } = &mut event
&& device.has_capability(DeviceCapability::Keyboard)
{
if let Some(led) = state.seat.get_keyboard().map(|k| k.led_state()) {
device.led_update(led.into());
}
@ -165,7 +168,6 @@ pub fn run() -> anyhow::Result<()> {
drm.keyboards.push(device.clone());
}
}
}
input::process_input_event(state, event);
},
)
@ -227,12 +229,8 @@ pub fn run() -> anyhow::Result<()> {
)
.map_err(|e| anyhow::anyhow!("udev source: {e}"))?;
let mut state = WeftCompositorState::new(
display_handle.clone(),
loop_signal,
loop_handle,
seat_name,
);
let mut state =
WeftCompositorState::new(display_handle.clone(), loop_signal, loop_handle, seat_name);
state.drm = Some(WeftDrmData {
session,
@ -269,11 +267,7 @@ pub fn run() -> anyhow::Result<()> {
}
#[cfg(target_os = "linux")]
fn device_added(
state: &mut WeftCompositorState,
node: DrmNode,
path: &Path,
) -> anyhow::Result<()> {
fn device_added(state: &mut WeftCompositorState, node: DrmNode, path: &Path) -> anyhow::Result<()> {
let drm_data = state.drm.as_mut().context("DRM data not initialised")?;
let fd = drm_data
@ -285,16 +279,14 @@ fn device_added(
.context("failed to open DRM device")?;
let fd = DrmDeviceFd::new(DeviceFd::from(fd));
let (drm, notifier) =
DrmDevice::new(fd.clone(), true).context("DrmDevice::new failed")?;
let (drm, notifier) = DrmDevice::new(fd.clone(), true).context("DrmDevice::new failed")?;
let gbm = GbmDevice::new(fd).context("GbmDevice::new failed")?;
let render_node = (|| -> anyhow::Result<DrmNode> {
// Safety: EGLDisplay requires the GBM device to outlive it; gbm lives in WeftDrmDevice.
let egl_display =
unsafe { EGLDisplay::new(gbm.clone()).context("EGLDisplay::new failed")? };
let egl_device =
EGLDevice::device_for_display(&egl_display).context("no EGL device")?;
let egl_device = EGLDevice::device_for_display(&egl_display).context("no EGL device")?;
if egl_device.is_software() {
anyhow::bail!("software renderer");
}
@ -323,7 +315,7 @@ fn device_added(
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
);
let exporter = GbmFramebufferExporter::new(gbm.clone(), render_node.into());
let exporter = GbmFramebufferExporter::new(gbm.clone(), render_node);
let color_formats = if std::env::var("WEFT_DISABLE_10BIT").is_ok() {
SUPPORTED_FORMATS_8BIT_ONLY
@ -391,9 +383,16 @@ fn device_changed(state: &mut WeftCompositorState, node: DrmNode) {
None => return,
};
let events: Vec<DrmScanEvent> = device
let events: Vec<DrmScanEvent> = match device
.drm_scanner
.scan_connectors(device.drm_output_manager.device());
.scan_connectors(device.drm_output_manager.device())
{
Ok(r) => r.into_iter().collect(),
Err(e) => {
tracing::warn!(?e, "connector scan failed");
return;
}
};
for event in events {
match event {
@ -492,11 +491,13 @@ fn connector_connected(
}
};
let drm_output = match device.drm_output_manager.initialize_output(
let drm_output = match device
.drm_output_manager
.initialize_output::<_, WaylandSurfaceRenderElement<_>>(
crtc,
mode,
&[connector.handle()],
output.clone(),
&output,
planes,
&mut renderer,
&DrmOutputRenderElements::default(),
@ -534,12 +535,12 @@ fn connector_disconnected(
Some(d) => d,
None => return,
};
if let Some(device) = drm_data.devices.get_mut(&node) {
if let Some(surface) = device.surfaces.remove(&crtc) {
if let Some(device) = drm_data.devices.get_mut(&node)
&& let Some(surface) = device.surfaces.remove(&crtc)
{
state.space.unmap_output(&surface.output);
}
}
}
#[cfg(target_os = "linux")]
fn device_removed(state: &mut WeftCompositorState, node: DrmNode) {
@ -633,12 +634,9 @@ fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Han
}
space.elements().for_each(|window| {
window.send_frame(
&output,
Duration::ZERO,
Some(Duration::ZERO),
|_, _| Some(output.clone()),
);
window.send_frame(&output, Duration::ZERO, Some(Duration::ZERO), |_, _| {
Some(output.clone())
});
});
let _ = state.display_handle.flush_clients();

View file

@ -4,13 +4,13 @@ use smithay::{
backend::{
allocator::gbm::GbmAllocator,
drm::{
DrmDeviceFd, DrmNode,
exporter::gbm::GbmFramebufferExporter,
output::{DrmOutput, DrmOutputManager},
DrmDeviceFd, DrmNode,
},
renderer::{
gles::GlesRenderer,
multigpu::{gbm::GbmGlesBackend, GpuManager},
multigpu::{GpuManager, gbm::GbmGlesBackend},
},
session::libseat::LibSeatSession,
},
@ -19,27 +19,20 @@ use smithay::{
reexports::{
calloop::RegistrationToken,
drm::control::crtc,
wayland_server::{backend::GlobalId, DisplayHandle},
wayland_server::{DisplayHandle, backend::GlobalId},
},
};
use smithay_drm_extras::drm_scanner::DrmScanner;
pub type WeftAllocator = GbmAllocator<DrmDeviceFd>;
pub type WeftExporter = GbmFramebufferExporter<DrmDeviceFd>;
pub type WeftDrmOutput = DrmOutput<
WeftAllocator,
WeftExporter,
Option<OutputPresentationFeedback>,
DrmDeviceFd,
>;
pub type WeftDrmOutputManager = DrmOutputManager<
WeftAllocator,
WeftExporter,
Option<OutputPresentationFeedback>,
DrmDeviceFd,
>;
pub type WeftDrmOutput =
DrmOutput<WeftAllocator, WeftExporter, Option<OutputPresentationFeedback>, DrmDeviceFd>;
pub type WeftDrmOutputManager =
DrmOutputManager<WeftAllocator, WeftExporter, Option<OutputPresentationFeedback>, DrmDeviceFd>;
pub type WeftGpuManager = GpuManager<GbmGlesBackend<GlesRenderer, DrmDeviceFd>>;
#[allow(dead_code)]
pub struct WeftOutputSurface {
pub output: Output,
pub drm_output: WeftDrmOutput,

View file

@ -1,41 +1,41 @@
use smithay::{
backend::input::{
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, GestureHoldBeginEvent,
GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, InputBackend,
InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent,
PointerMotionAbsoluteEvent, PointerMotionEvent, TouchCancelEvent, TouchDownEvent,
TouchFrameEvent, TouchMotionEvent, TouchUpEvent,
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, GestureBeginEvent,
GestureEndEvent, GesturePinchUpdateEvent, GestureSwipeUpdateEvent, InputBackend,
InputEvent, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent,
TouchEvent,
},
input::{
keyboard::FilterResult,
pointer::{AxisFrame, ButtonEvent, MotionEvent},
},
utils::{Logical, Point, SERIAL_COUNTER, Serial},
utils::{Logical, Point, SERIAL_COUNTER},
};
use crate::state::WeftCompositorState;
pub fn process_input_event<B: InputBackend>(state: &mut WeftCompositorState, event: InputEvent<B>) {
match event {
InputEvent::Keyboard { event } => handle_keyboard(state, event),
InputEvent::PointerMotion { event } => handle_pointer_motion(state, event),
InputEvent::PointerMotionAbsolute { event } => handle_pointer_motion_absolute(state, event),
InputEvent::PointerButton { event } => handle_pointer_button(state, event),
InputEvent::PointerAxis { event } => handle_pointer_axis(state, event),
InputEvent::TouchDown { event } => handle_touch_down(state, event),
InputEvent::TouchUp { event } => handle_touch_up(state, event),
InputEvent::TouchMotion { event } => handle_touch_motion(state, event),
InputEvent::TouchFrame { event } => handle_touch_frame(state, event),
InputEvent::TouchCancel { event } => handle_touch_cancel(state, event),
InputEvent::GestureSwipeBegin { event } => handle_gesture_swipe_begin(state, event),
InputEvent::GestureSwipeUpdate { event } => handle_gesture_swipe_update(state, event),
InputEvent::GestureSwipeEnd { event } => handle_gesture_swipe_end(state, event),
InputEvent::GesturePinchBegin { event } => handle_gesture_pinch_begin(state, event),
InputEvent::GesturePinchUpdate { event } => handle_gesture_pinch_update(state, event),
InputEvent::GesturePinchEnd { event } => handle_gesture_pinch_end(state, event),
InputEvent::GestureHoldBegin { event } => handle_gesture_hold_begin(state, event),
InputEvent::GestureHoldEnd { event } => handle_gesture_hold_end(state, event),
InputEvent::Keyboard { event } => handle_keyboard::<B>(state, event),
InputEvent::PointerMotion { event } => handle_pointer_motion::<B>(state, event),
InputEvent::PointerMotionAbsolute { event } => {
handle_pointer_motion_absolute::<B>(state, event)
}
InputEvent::PointerButton { event } => handle_pointer_button::<B>(state, event),
InputEvent::PointerAxis { event } => handle_pointer_axis::<B>(state, event),
InputEvent::TouchDown { event } => handle_touch_down::<B>(state, event),
InputEvent::TouchUp { event } => handle_touch_up::<B>(state, event),
InputEvent::TouchMotion { event } => handle_touch_motion::<B>(state, event),
InputEvent::TouchFrame { event } => handle_touch_frame::<B>(state, event),
InputEvent::TouchCancel { event } => handle_touch_cancel::<B>(state, event),
InputEvent::GestureSwipeBegin { event } => handle_gesture_swipe_begin::<B>(state, event),
InputEvent::GestureSwipeUpdate { event } => handle_gesture_swipe_update::<B>(state, event),
InputEvent::GestureSwipeEnd { event } => handle_gesture_swipe_end::<B>(state, event),
InputEvent::GesturePinchBegin { event } => handle_gesture_pinch_begin::<B>(state, event),
InputEvent::GesturePinchUpdate { event } => handle_gesture_pinch_update::<B>(state, event),
InputEvent::GesturePinchEnd { event } => handle_gesture_pinch_end::<B>(state, event),
InputEvent::GestureHoldBegin { event } => handle_gesture_hold_begin::<B>(state, event),
InputEvent::GestureHoldEnd { event } => handle_gesture_hold_end::<B>(state, event),
// Device added/removed events are handled at the backend level.
InputEvent::DeviceAdded { .. } | InputEvent::DeviceRemoved { .. } => {}
_ => {}

View file

@ -6,7 +6,10 @@ use smithay::{
delegate_compositor, delegate_cursor_shape, delegate_dmabuf, delegate_input_method_manager,
delegate_layer_shell, delegate_output, delegate_pointer_constraints, delegate_presentation,
delegate_seat, delegate_shm, delegate_text_input_manager, delegate_xdg_shell,
desktop::{PopupKind, PopupManager, Space, Window, WindowSurfaceType, layer_map_for_output},
desktop::{
LayerSurface as DesktopLayerSurface, PopupKind, PopupManager, Space, Window,
WindowSurfaceType, layer_map_for_output,
},
input::{Seat, SeatHandler, SeatState, keyboard::XkbConfig, pointer::CursorImageStatus},
output::Output,
reexports::{
@ -51,6 +54,7 @@ impl ClientData for WeftClientState {
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {}
}
#[allow(dead_code)]
pub struct WeftCompositorState {
pub display_handle: DisplayHandle,
pub loop_signal: LoopSignal,
@ -225,6 +229,19 @@ impl XdgShellHandler for WeftCompositorState {
}
}
fn reposition_request(
&mut self,
surface: PopupSurface,
positioner: PositionerState,
token: u32,
) {
surface.with_pending_state(|state| {
state.geometry = positioner.get_geometry();
state.positioner = positioner;
});
surface.send_repositioned(token);
}
fn grab(
&mut self,
_surface: PopupSurface,
@ -248,13 +265,12 @@ impl WlrLayerShellHandler for WeftCompositorState {
surface: LayerSurface,
_output: Option<WlOutput>,
_layer: Layer,
_namespace: String,
namespace: String,
) {
// Map to the first available output. Proper output matching is deferred to
// the shell protocol wave where the compositor receives explicit placement requests.
let desktop_surface = DesktopLayerSurface::new(surface, namespace);
if let Some(output) = self.space.outputs().next().cloned() {
layer_map_for_output(&output)
.map_layer(&surface)
.map_layer(&desktop_surface)
.expect("layer surface must not already be mapped");
layer_map_for_output(&output).arrange();
}

43
scripts/wsl-check.sh Normal file
View file

@ -0,0 +1,43 @@
#!/usr/bin/env bash
set -e
PROJECT="/mnt/c/Users/might/Desktop/Development/Systems/WEFT OS"
# ── Fake libdisplay-info.pc that reports 0.2.9 ───────────────────────────────
# libdisplay-info-sys 0.2.2 requires >= 0.1.0 < 0.3.0; openSUSE ships 0.3.0.
# cargo check does not link, so reporting 0.2.9 satisfies the version guard
# without requiring a source build.
FAKE_PC_DIR="$HOME/.local/fake-pkgconfig"
mkdir -p "$FAKE_PC_DIR"
cat > "$FAKE_PC_DIR/libdisplay-info.pc" << 'EOF'
prefix=/usr
exec_prefix=${prefix}
libdir=/usr/lib64
includedir=/usr/include
Name: libdisplay-info
Description: EDID and DisplayID library (version shim for cargo check)
Version: 0.2.9
Libs: -L${libdir} -ldisplay-info
Cflags: -I${includedir}
EOF
echo "==> libdisplay-info shim: $(pkg-config --modversion libdisplay-info --with-path "$FAKE_PC_DIR" 2>/dev/null || echo written)"
# ── cargo check ───────────────────────────────────────────────────────────────
source "$HOME/.cargo/env"
export PKG_CONFIG_PATH="$FAKE_PC_DIR:/usr/lib64/pkgconfig:/usr/share/pkgconfig"
cd "$PROJECT"
echo ""
echo "==> cargo check -p weft-compositor"
cargo check -p weft-compositor 2>&1
echo ""
echo "==> cargo clippy -p weft-compositor -- -D warnings"
cargo clippy -p weft-compositor -- -D warnings 2>&1
echo ""
echo "==> cargo fmt --check -p weft-compositor"
cargo fmt --check -p weft-compositor 2>&1
echo ""
echo "ALL DONE"