// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2026, Nathan Gill pub mod args; pub mod auth; pub mod auth_sys; pub mod buffer; pub mod cairo_ext; pub mod comm; pub mod config; pub mod event; pub mod event_loop; pub mod font; pub mod render; pub mod seat; pub mod shm; pub mod signal; pub mod state; pub mod surface; pub mod util; use std::sync::{Arc, atomic::Ordering}; use anyhow::{Result, bail}; #[cfg_attr(debug_assertions, allow(unused_imports))] #[cfg(target_os = "linux")] use nix::sys::prctl; use tracing::{debug, error, info, warn}; use wayland_client::Connection; use crate::{ args::run_cli, auth::{AuthChannel, AuthConfig, setup_auth}, config::NLockConfig, state::{NLockState, NLockStateArgs}, util::LogLevel, }; fn start(config: NLockConfig, debug: bool) -> Result<()> { // Prevent ptrace from attaching to nlock // Only do this in release config #[cfg(not(debug_assertions))] #[cfg(target_os = "linux")] prctl::set_dumpable(false)?; if debug { info!("Running in DEBUG mode"); } let conn = Connection::connect_to_env()?; let display = conn.display(); let auth_comm = Arc::new(AuthChannel::new()?); let auth_config: AuthConfig = (&config).into(); let state_args = NLockStateArgs { config, display, auth_comm: auth_comm.clone(), debug, }; let mut state = NLockState::new(state_args)?; let mut event_queue = conn.new_event_queue(); let qh = event_queue.handle(); state.get_registry(&qh); event_queue.roundtrip(&mut state)?; if state.compositor.is_none() { bail!("Missing WlCompositor"); } if state.subcompositor.is_none() { bail!("Missing WlSubcompositor"); } if state.shm.is_none() { bail!("Missing WlShm"); } if state.r_seat.is_none() { bail!("Missing WlSeat"); } if state.session_lock_manager.is_none() { bail!("Missing ExtSessionLockManagerV1"); } // spawn the auth thread let handle = setup_auth(auth_config, auth_comm.clone())?; state.lock(&qh); while state.running.load(Ordering::Relaxed) { if let Err(e) = state.event_loop_cycle(&mut event_queue) { warn!("Error while running event loop: {e}"); } } state.unlock(); event_queue.roundtrip(&mut state)?; if let Err(e) = auth_comm.stop.write(true) { warn!("Failed to stop auth loop: {e}"); } else { let _ = handle.join(); } Ok(()) } fn main() { let args = run_cli(); tracing_subscriber::fmt() .with_timer(tracing_subscriber::fmt::time::uptime()) .with_max_level(args.log_level.unwrap_or(if args.debug { LogLevel::Debug } else { LogLevel::Info })) .init(); let now = chrono::Local::now(); debug!("nlock started at {}", now.to_rfc3339()); match NLockConfig::load(&args) { Ok(cfg) => { if let Err(e) = start(cfg, args.debug) { error!("{:?}", e); } } Err(e) => { error!("Error loading configuration: {:?}", e); return; } } let now = chrono::Local::now(); debug!("nlock exited at {}", now.to_rfc3339()); }