diff --git a/crates/weft-compositor/src/backend/drm.rs b/crates/weft-compositor/src/backend/drm.rs index ad70ed2..51e9be8 100644 --- a/crates/weft-compositor/src/backend/drm.rs +++ b/crates/weft-compositor/src/backend/drm.rs @@ -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::::new()?; + let display = Display::::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::>( - session.clone().into(), - ); + Libinput::new_with_udev::>(session.clone().into()); libinput_ctx .udev_assign_seat(&seat_name) .map_err(|_| anyhow::anyhow!("libinput seat assignment failed"))?; @@ -156,14 +158,14 @@ 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 Some(led) = state.seat.get_keyboard().map(|k| k.led_state()) { - device.led_update(led.into()); - } - if let Some(drm) = state.drm.as_mut() { - drm.keyboards.push(device.clone()); - } + 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()); + } + if let Some(drm) = state.drm.as_mut() { + 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 { // 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 = device + let events: Vec = 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,15 +491,17 @@ fn connector_connected( } }; - let drm_output = match device.drm_output_manager.initialize_output( - crtc, - mode, - &[connector.handle()], - output.clone(), - planes, - &mut renderer, - &DrmOutputRenderElements::default(), - ) { + let drm_output = match device + .drm_output_manager + .initialize_output::<_, WaylandSurfaceRenderElement<_>>( + crtc, + mode, + &[connector.handle()], + &output, + planes, + &mut renderer, + &DrmOutputRenderElements::default(), + ) { Ok(o) => o, Err(e) => { tracing::warn!(?e, ?name, "initialize_output failed"); @@ -534,10 +535,10 @@ 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) { - state.space.unmap_output(&surface.output); - } + if let Some(device) = drm_data.devices.get_mut(&node) + && let Some(surface) = device.surfaces.remove(&crtc) + { + state.space.unmap_output(&surface.output); } } @@ -633,13 +634,10 @@ 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(); -} \ No newline at end of file +} diff --git a/crates/weft-compositor/src/backend/drm_device.rs b/crates/weft-compositor/src/backend/drm_device.rs index 06537bf..efc1e64 100644 --- a/crates/weft-compositor/src/backend/drm_device.rs +++ b/crates/weft-compositor/src/backend/drm_device.rs @@ -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; pub type WeftExporter = GbmFramebufferExporter; -pub type WeftDrmOutput = DrmOutput< - WeftAllocator, - WeftExporter, - Option, - DrmDeviceFd, ->; -pub type WeftDrmOutputManager = DrmOutputManager< - WeftAllocator, - WeftExporter, - Option, - DrmDeviceFd, ->; +pub type WeftDrmOutput = + DrmOutput, DrmDeviceFd>; +pub type WeftDrmOutputManager = + DrmOutputManager, DrmDeviceFd>; pub type WeftGpuManager = GpuManager>; +#[allow(dead_code)] pub struct WeftOutputSurface { pub output: Output, pub drm_output: WeftDrmOutput, diff --git a/crates/weft-compositor/src/input.rs b/crates/weft-compositor/src/input.rs index 19b379f..c884a09 100644 --- a/crates/weft-compositor/src/input.rs +++ b/crates/weft-compositor/src/input.rs @@ -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(state: &mut WeftCompositorState, event: InputEvent) { 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::(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), // Device added/removed events are handled at the backend level. InputEvent::DeviceAdded { .. } | InputEvent::DeviceRemoved { .. } => {} _ => {} diff --git a/crates/weft-compositor/src/state.rs b/crates/weft-compositor/src/state.rs index 141dded..e5c17cb 100644 --- a/crates/weft-compositor/src/state.rs +++ b/crates/weft-compositor/src/state.rs @@ -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, _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(); } diff --git a/scripts/wsl-check.sh b/scripts/wsl-check.sh new file mode 100644 index 0000000..2a59e17 --- /dev/null +++ b/scripts/wsl-check.sh @@ -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"