diff --git a/src/lock.rs b/src/lock.rs index 40a929f..44c04a1 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -1,11 +1,13 @@ use cairo::ImageSurface; +use std::error::Error; use std::time::Instant; -use wayland_client::protocol::wl_surface; +use wayland_client::protocol::{wl_shm, wl_surface}; use crate::config::Config; use crate::input::{InputAction, InputHandler}; use crate::render::Renderer; use crate::screenshot::Screenshot; +use smithay_client_toolkit::shm::slot::SlotPool; /// Manages a locked surface for a single output pub struct LockedSurface { @@ -144,6 +146,30 @@ impl LockedSurface { self.last_update = Instant::now(); } + /// Commit the rendered frame to the Wayland surface + pub fn commit(&self, pool: &mut SlotPool) -> Result<(), Box> { + // Get pixel data from renderer + let pixel_data = self.renderer.get_pixel_data()?; + let (width, height, stride) = self.renderer.surface_info(); + + // Create buffer from pool + let (buffer, mut canvas) = + pool.create_buffer(width, height, stride, wl_shm::Format::Argb8888)?; + + // Copy pixel data to buffer + let copy_len = pixel_data.len().min(canvas.len()); + canvas[..copy_len].copy_from_slice(&pixel_data[..copy_len]); + + // Attach buffer to Wayland surface and commit + if let Some(wl_surface) = &self.wayland_surface { + buffer.attach_to(wl_surface)?; + wl_surface.damage_buffer(0, 0, width, height); + wl_surface.commit(); + } + + Ok(()) + } + /// Handle resize event from Wayland pub fn resize(&mut self, width: i32, height: i32) { if width <= 0 || height <= 0 { diff --git a/src/main.rs b/src/main.rs index 3a55f20..58cb67b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,11 +84,13 @@ fn lock_wayland_session( lock_manager: Arc>, ctrlc_exit: Arc, ) -> Result<(), Box> { + use smithay_client_toolkit::reexports::calloop; + use smithay_client_toolkit::reexports::calloop::timer::TimeoutAction; use smithay_client_toolkit::{ compositor::{CompositorHandler, CompositorState}, output::{OutputHandler, OutputState}, reexports::{ - calloop::{channel, EventLoop, LoopHandle}, + calloop::{channel, timer, EventLoop, LoopHandle}, calloop_wayland_source::WaylandSource, }, registry::{ProvidesRegistryState, RegistryState}, @@ -651,7 +653,7 @@ fn lock_wayland_session( shm_state: Shm::bind(&globals, &qh).map_err(|_| "wl_shm protocol not supported")?, pool: SlotPool::new( - 1920 * 1080 * 4, + 1920 * 1080 * 4 * 3, // triple buffering for smooth rendering &Shm::bind(&globals, &qh).map_err(|_| "wl_shm protocol not supported")?, ) .map_err(|e| format!("Failed to create slot pool: {:?}", e))?, @@ -688,6 +690,28 @@ fn lock_wayland_session( }, )?; + // Insert a timer to update and commit surfaces at 60fps + let render_timer = timer::Timer::from_duration(Duration::from_millis(16)); + event_loop.handle().insert_source( + render_timer, + |event, _metadata, state: &mut WaylandLock| { + // Update lock manager (renders to Cairo surfaces) + if let Ok(mut lock_manager) = state.lock_manager.lock() { + lock_manager.update(); + // Commit each surface that has a Wayland surface + for surface in lock_manager.surfaces.iter_mut() { + if let Some(wl_surface) = surface.wayland_surface() { + if let Err(e) = surface.commit(&mut state.pool) { + log::error!("Failed to commit surface: {:?}", e); + } + } + } + } + // Reschedule timer to fire again in 16ms (60fps) + calloop::timer::TimeoutAction::ToDuration(Duration::from_millis(16)) + }, + )?; + log_to_file("Starting event loop"); eprintln!("Starting event loop - press Enter to unlock"); @@ -706,7 +730,6 @@ fn run_demonstration_mode( _config: Config, lock_manager: Arc>, ) -> Result<(), Box> { - use std::time::Duration; println!("wayrustlock - Wayland Screen Locker (Demonstration Mode)");