From d4a27115e8f17a5fb2aa3a02eafa3dac6a460bfa Mon Sep 17 00:00:00 2001 From: FlashOnFire_ Date: Tue, 4 Nov 2025 21:22:11 +0100 Subject: [PATCH 1/4] feat: Added hook to get newly connected screens (in preparation for profile manager # Conflicts: # waypaper_engine_daemon/src/wl_renderer.rs --- waypaper_engine_daemon/src/wl_renderer.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/waypaper_engine_daemon/src/wl_renderer.rs b/waypaper_engine_daemon/src/wl_renderer.rs index 4ae073a..186b17d 100644 --- a/waypaper_engine_daemon/src/wl_renderer.rs +++ b/waypaper_engine_daemon/src/wl_renderer.rs @@ -42,7 +42,7 @@ pub struct RenderingContext { } impl RenderingContext { - pub fn new(new_output_tx: Sender<(WlOutput, OutputInfo)>) -> Self { + pub fn new(new_output_tx: Sender) -> Self { let connection = Rc::new(Connection::connect_to_env().unwrap()); let egl_state = Rc::new(EGLState::new(connection.clone())); let (globals, event_queue): (GlobalList, EventQueue) = @@ -136,7 +136,7 @@ pub struct WLState { layer_shell: LayerShell, pub layers: HashMap, - new_output_tx: Sender<(WlOutput, OutputInfo)>, + new_output_tx: Sender, } impl WLState { @@ -145,7 +145,7 @@ impl WLState { egl_state: Rc, globals: &GlobalList, queue_handle: QueueHandle, - new_output_tx: Sender<(WlOutput, OutputInfo)>, + new_output_tx: Sender, ) -> Self { Self { connection, @@ -358,7 +358,7 @@ impl OutputHandler for WLState { match self.output_state.info(&output) { Some(infos) => { self.new_output_tx - .send((output, infos)) + .send(infos) .expect("Error sending new output event"); } None => tracing::error!("Could not retrieve new output info"), From 76d23781eaffda9720384e0cdc3a6fe2fb30f79b Mon Sep 17 00:00:00 2001 From: undermirrors Date: Wed, 19 Nov 2025 11:26:39 +0100 Subject: [PATCH 2/4] feat: add save and load --- Cargo.lock | 113 ++++---- waypaper_engine_cli/src/main.rs | 4 + waypaper_engine_daemon/src/app_state.rs | 246 +++++++++++------- waypaper_engine_daemon/src/main.rs | 1 + waypaper_engine_daemon/src/profile_manager.rs | 55 ++++ waypaper_engine_daemon/src/wl_renderer.rs | 30 ++- waypaper_engine_shared/Cargo.toml | 3 +- waypaper_engine_shared/src/ipc.rs | 10 +- waypaper_engine_shared/src/lib.rs | 5 +- 9 files changed, 302 insertions(+), 165 deletions(-) create mode 100644 waypaper_engine_daemon/src/profile_manager.rs diff --git a/Cargo.lock b/Cargo.lock index 9600932..63ce4c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,7 +141,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -253,7 +253,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -360,7 +360,7 @@ checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -611,7 +611,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -821,7 +821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -831,7 +831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -861,7 +861,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -872,7 +872,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -895,7 +895,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -907,7 +907,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -965,7 +965,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -997,7 +997,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -1196,7 +1196,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -1273,7 +1273,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -1559,7 +1559,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -1638,7 +1638,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -2017,7 +2017,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -2389,7 +2389,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -2621,7 +2621,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -2681,7 +2681,7 @@ dependencies = [ "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3146,7 +3146,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3340,9 +3340,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -3363,7 +3363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3401,9 +3401,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -3777,7 +3777,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3866,7 +3866,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3877,7 +3877,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3900,7 +3900,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3960,7 +3960,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -3982,7 +3982,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -4204,6 +4204,18 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subenum" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3d08fe7078c57309d5c3d938e50eba95ba1d33b9c3a101a8465fc6861a5416" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.109", +] + [[package]] name = "swift-rs" version = "1.0.7" @@ -4228,9 +4240,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -4254,7 +4266,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -4318,7 +4330,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -4418,7 +4430,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.101", + "syn 2.0.109", "tauri-utils", "thiserror 2.0.12", "time", @@ -4436,7 +4448,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", "tauri-codegen", "tauri-utils", ] @@ -4617,7 +4629,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -4628,7 +4640,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -4908,7 +4920,7 @@ checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -5237,7 +5249,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", "wasm-bindgen-shared", ] @@ -5272,7 +5284,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5480,6 +5492,7 @@ dependencies = [ "serde", "serde-this-or-that", "serde_json", + "subenum", ] [[package]] @@ -5574,7 +5587,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -5694,7 +5707,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -5705,7 +5718,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -6159,7 +6172,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", "synstructure", ] @@ -6180,7 +6193,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] @@ -6200,7 +6213,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", "synstructure", ] @@ -6234,7 +6247,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.109", ] [[package]] diff --git a/waypaper_engine_cli/src/main.rs b/waypaper_engine_cli/src/main.rs index b1ddc51..65f13fc 100644 --- a/waypaper_engine_cli/src/main.rs +++ b/waypaper_engine_cli/src/main.rs @@ -147,6 +147,10 @@ fn print_ipc_error(error: &IPCError, json_output: bool) { "internal_error", "An internal error occurred while processing the request.", ), + IPCError::WallpaperLoadingError => ( + "wallpaper_loading_error", + "Unable to load correctly wallpaper", + ), }; if json_output { diff --git a/waypaper_engine_daemon/src/app_state.rs b/waypaper_engine_daemon/src/app_state.rs index aefc716..2431112 100644 --- a/waypaper_engine_daemon/src/app_state.rs +++ b/waypaper_engine_daemon/src/app_state.rs @@ -1,18 +1,19 @@ +use crate::profile_manager::ProfileManager; +use crate::wallpaper::Wallpaper; +use crate::wl_renderer::RenderingContext; +use crossbeam::channel::{Receiver, Sender, TryRecvError}; +use linux_ipc::IpcChannel; use std::error::Error; use std::path::PathBuf; -use std::sync::mpsc; -use std::sync::mpsc::{Sender, TryRecvError}; use std::thread; - -use linux_ipc::IpcChannel; -use waypaper_engine_shared::ipc::{IPCError, IPCRequest, IPCResponse}; - -use crate::wallpaper::Wallpaper; -use crate::wl_renderer::RenderingContext; +use waypaper_engine_shared::ipc::{IPCError, IPCRequest, IPCResponse, InternalRequest}; pub struct AppState { wpe_dir: PathBuf, rendering_context: RenderingContext, + internal_ipc_tx: Sender<(InternalRequest, Sender)>, + internal_ipc_rx: Receiver<(InternalRequest, Sender)>, + profile_manager: ProfileManager } impl AppState { @@ -22,23 +23,23 @@ impl AppState { wpe_dir.to_string_lossy() ); - let (new_output_tx, new_output_rx) = crossbeam::channel::unbounded(); - thread::spawn(move || { - loop { - println!("new output: {:?}", new_output_rx.recv().expect("oui")); - } - }); + let (internal_ipc_tx, internal_ipc_rx) = + crossbeam::channel::unbounded::<(InternalRequest, Sender)>(); AppState { wpe_dir, - rendering_context: RenderingContext::new(new_output_tx), + rendering_context: RenderingContext::new(internal_ipc_tx.clone()), + internal_ipc_tx, + internal_ipc_rx, + profile_manager: ProfileManager::new(), } } pub fn run(&mut self) -> Result<(), Box> { ffmpeg_next::init()?; - let (tx, rx) = mpsc::channel::<(IPCRequest, Sender)>(); + // we clone here to be thread safe + let internal_ipc_tx = self.internal_ipc_tx.clone(); let ipc_thread = thread::spawn(move || { let mut channel = IpcChannel::new("/tmp/waypaper-engine.sock").unwrap(); @@ -53,8 +54,10 @@ impl AppState { break; } - let (req_tx, req_rx) = mpsc::channel::(); - tx.send((request.clone(), req_tx)).unwrap(); + let (req_tx, req_rx) = crossbeam::channel::unbounded::(); + internal_ipc_tx + .send((InternalRequest::from(request.clone()), req_tx)) + .unwrap(); match req_rx.recv() { Ok(response) => { tracing::debug!("Sending response : [{:?}]", response); @@ -79,100 +82,35 @@ impl AppState { loop { self.rendering_context.tick(); - match rx.try_recv() { + match self.internal_ipc_rx.try_recv() { Ok((req, response)) => match req { - IPCRequest::SetWallpaper { id, screen } => { - let outputs = self.rendering_context.get_outputs(); - - if let Some(output) = outputs - .iter() - .find(|output| output.1.name.as_ref().unwrap() == &screen) + InternalRequest::SetWallpaper { id, screen } => { + if Self::set_wallpaper(self, id, &screen, &response) + && let Err(err) = self.profile_manager.save_wallpaper(id, &screen) { - let path = self.wpe_dir.join(id.to_string()); - - if !path.exists() { - tracing::warn!("Wallpaper path does not exist: {:?}", path); - response - .send(IPCResponse::Error(IPCError::WallpaperNotFound)) - .unwrap(); - continue; - } - - if !path.is_dir() { - tracing::warn!("Wallpaper path is not a directory: {:?}", path); - response - .send(IPCResponse::Error(IPCError::WallpaperNotFound)) - .unwrap(); - continue; - } - - let wallpaper = Wallpaper::new(path)?; - let path = self.wpe_dir.join(id.to_string()); - match wallpaper { - Wallpaper::Video { ref project, .. } => { - let video_path = path.join(project.file.as_ref().unwrap()); - - if video_path.exists() { - tracing::info!( - "Found video file ! (Path : {video_path:?})" - ); - - self.rendering_context.set_wallpaper(output, wallpaper); - } - } - Wallpaper::Scene { .. } => { - let scene_pkg_file = path.join("scene.pkg"); - - if scene_pkg_file.exists() { - tracing::info!( - "Found scene package file ! (Path : {scene_pkg_file:?})" - ); - - self.rendering_context.set_wallpaper(output, wallpaper); - } - } - _ => { - tracing::warn!( - "Unsupported wallpaper type for SetWallpaper request: [{}]", - screen - ); - response - .send(IPCResponse::Error( - IPCError::UnsupportedWallpaperType, - )) - .unwrap(); - continue; - } - } - - tracing::info!( - "Set wallpaper for output [{}] with id [{}]", - screen, - id - ); - response.send(IPCResponse::Success).unwrap(); - } else { - tracing::warn!( - "Received wrong output in SetWallpaper request: [{}]", - screen - ); - response - .send(IPCResponse::Error(IPCError::ScreenNotFound)) - .unwrap(); + tracing::warn!("Unable to save wallpaper: {}", err); } } - IPCRequest::ListOutputs => { + + InternalRequest::ListOutputs => { let outputs = self .rendering_context .get_outputs() .drain() .filter_map(|(_, output)| output.name) .collect(); - response.send(IPCResponse::Outputs(outputs)).unwrap(); + response.send(IPCResponse::Outputs(outputs))?; } - IPCRequest::KillDaemon => { + InternalRequest::KillDaemon => { unreachable!() } + InternalRequest::NewOutput { screen } => { + if let Some(id) = self.profile_manager.load_wallpaper(&screen) + && Self::set_wallpaper(self, id, &screen, &response) + { + tracing::info!("Wallpaper [{}] loaded for screen [{}]", id, screen); + } + } }, Err(err) => match err { TryRecvError::Empty => {} @@ -187,4 +125,114 @@ impl AppState { Ok(()) } + + fn set_wallpaper(&mut self, id: u64, screen: &str, response: &Sender) -> bool { + let outputs = self.rendering_context.get_outputs(); + + if let Some(output) = outputs.iter().find(|output| match output.1.name.as_ref() { + Some(name) => name == screen, + None => false, + }) { + let path = self.wpe_dir.join(id.to_string()); + + if !path.exists() { + tracing::warn!("Wallpaper path does not exist: {:?}", path); + response + .send(IPCResponse::Error(IPCError::WallpaperNotFound)) + .unwrap(); + return false; + } + + if !path.is_dir() { + tracing::warn!("Wallpaper path is not a directory: {:?}", path); + response + .send(IPCResponse::Error(IPCError::WallpaperNotFound)) + .unwrap(); + // The wallpaper path is expected to be a directory containing wallpaper resources. + return false; + } + + let wallpaper = match Wallpaper::new(path.clone()) { + Ok(wallpaper) => wallpaper, + Err(e) => { + tracing::warn!("Failed to load wallpaper: {:?}", e); + response + .send(IPCResponse::Error(IPCError::WallpaperLoadingError)) + .unwrap(); + return false; + } + }; + match wallpaper { + Wallpaper::Video { ref project, .. } => { + if let Some(file) = project.file.as_ref() { + let video_path = path.join(file); + if video_path.exists() { + tracing::info!("Found video file ! (Path : {video_path:?})"); + self.rendering_context.set_wallpaper(output, wallpaper); + } else { + tracing::warn!("Video file does not exist: {:?}", video_path); + response + .send(IPCResponse::Error(IPCError::WallpaperNotFound)) + .unwrap(); + return false; + } + } else { + tracing::warn!("Wallpaper project file is None for video wallpaper"); + response + .send(IPCResponse::Error(IPCError::WallpaperNotFound)) + .unwrap(); + return false; + } + } + Wallpaper::Scene { .. } => { + let scene_pkg_file = path.join("scene.pkg"); + + if scene_pkg_file.exists() { + tracing::info!("Found scene package file ! (Path : {scene_pkg_file:?})"); + + self.rendering_context.set_wallpaper(output, wallpaper); + } + } + _ => { + tracing::warn!( + "Unsupported wallpaper type for SetWallpaper request: [{}]", + screen + ); + if response + .send(IPCResponse::Error(IPCError::UnsupportedWallpaperType)) + .is_err() + { + tracing::info!("Unable to send UnsupportedWallpaperType"); + } + return false; + } + } + + tracing::info!("Set wallpaper for output [{}] with id [{}]", screen, id); + + if response.send(IPCResponse::Success).is_err() { + tracing::info!("Unable to send Success"); + } + + true + } else { + tracing::warn!( + "Received wrong output in SetWallpaper request: [{}]", + screen + ); + if response + .send(IPCResponse::Error(IPCError::ScreenNotFound)) + .is_err() + { + tracing::warn!( + "Failed to send ScreenNotFound response for output [{}]: {:?}. \ + The IPC channel may be closed; client will not receive error response.", + screen, + IPCError::ScreenNotFound + ); + } + + false + } + } } diff --git a/waypaper_engine_daemon/src/main.rs b/waypaper_engine_daemon/src/main.rs index 9b53426..9cb3f95 100644 --- a/waypaper_engine_daemon/src/main.rs +++ b/waypaper_engine_daemon/src/main.rs @@ -13,6 +13,7 @@ mod tex_file; mod wallpaper; mod wallpaper_renderer; mod wl_renderer; +mod profile_manager; #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; diff --git a/waypaper_engine_daemon/src/profile_manager.rs b/waypaper_engine_daemon/src/profile_manager.rs new file mode 100644 index 0000000..4fc4877 --- /dev/null +++ b/waypaper_engine_daemon/src/profile_manager.rs @@ -0,0 +1,55 @@ +use std::collections::HashMap; +use std::error::Error; +use std::fs::File; +use std::path::PathBuf; +use std::{env, fs}; + +pub struct ProfileManager { + wallpapers: HashMap +} + +impl ProfileManager { + pub fn new() -> ProfileManager { + ProfileManager { + wallpapers: HashMap::new() + } + } + + pub fn save_wallpaper(&mut self, id: u64, screen: &str) -> Result<(), Box> { + let path = save_dir()?; + self.wallpapers.insert(screen.to_owned(), id); + + let file = File::create(&path)?; + serde_json::to_writer_pretty(file, &self.wallpapers)?; + + Ok(()) + } + + pub fn load_wallpaper(&mut self, screen: &str) -> Option { + if !self.wallpapers. contains_key(screen) { + let file_path = save_dir().ok()?; + let file = File::open(&file_path).ok()?; + self.wallpapers = serde_json::from_reader(file).ok()?; + } + self.wallpapers.get(screen).copied() + } +} + +fn save_dir() -> Result> { + let base_dir = if let Ok(home) = env::var("HOME") { + PathBuf::from(home).join(".config") + } else { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::NotFound, + "Unable to determine configuration directory", + ))); + }; + + let parent = base_dir.join("waypaper_engine"); + if !parent.exists() { + fs::create_dir_all(&parent)?; + } + + let file_path = parent.join("wallpapers.conf"); + Ok(file_path) +} diff --git a/waypaper_engine_daemon/src/wl_renderer.rs b/waypaper_engine_daemon/src/wl_renderer.rs index 186b17d..5868351 100644 --- a/waypaper_engine_daemon/src/wl_renderer.rs +++ b/waypaper_engine_daemon/src/wl_renderer.rs @@ -1,11 +1,6 @@ -use std::collections::HashMap; -use std::ops::{Deref, DerefMut}; -use std::rc::Rc; - use crate::egl::EGLState; use crate::wallpaper::Wallpaper; use crate::wallpaper_renderer::WPRenderer; -use crossbeam::channel::Sender; use fps_counter::FPSCounter; use gl::COLOR_BUFFER_BIT; use khronos_egl::ATTRIB_NONE; @@ -32,7 +27,12 @@ use smithay_client_toolkit::{ }, }, }; +use std::collections::HashMap; +use std::ops::{Deref, DerefMut}; +use std::rc::Rc; +use crossbeam::channel::{RecvError, Sender}; use wayland_egl::WlEglSurface; +use waypaper_engine_shared::ipc::{IPCResponse, InternalRequest}; pub struct RenderingContext { _connection: Rc, @@ -42,7 +42,7 @@ pub struct RenderingContext { } impl RenderingContext { - pub fn new(new_output_tx: Sender) -> Self { + pub fn new(internal_ipc_tx: Sender<(InternalRequest, Sender)>) -> Self { let connection = Rc::new(Connection::connect_to_env().unwrap()); let egl_state = Rc::new(EGLState::new(connection.clone())); let (globals, event_queue): (GlobalList, EventQueue) = @@ -54,7 +54,7 @@ impl RenderingContext { egl_state.clone(), &globals, queue_handle, - new_output_tx, + internal_ipc_tx, ); tracing::info!("Created WL state"); @@ -136,7 +136,7 @@ pub struct WLState { layer_shell: LayerShell, pub layers: HashMap, - new_output_tx: Sender, + new_output_tx: Sender<(InternalRequest, Sender)>, } impl WLState { @@ -145,7 +145,7 @@ impl WLState { egl_state: Rc, globals: &GlobalList, queue_handle: QueueHandle, - new_output_tx: Sender, + new_output_tx: Sender<(InternalRequest, Sender)>, ) -> Self { Self { connection, @@ -357,9 +357,15 @@ impl OutputHandler for WLState { fn new_output(&mut self, _conn: &Connection, _qh: &QueueHandle, output: WlOutput) { match self.output_state.info(&output) { Some(infos) => { + let (resp_tx, _resp_rx) = crossbeam::channel::unbounded::(); self.new_output_tx - .send(infos) - .expect("Error sending new output event"); + .send(( + InternalRequest::NewOutput { + screen: infos.name.unwrap(), + }, + resp_tx, + )) + .unwrap_or_else(|e| tracing::error!("Failed to send new output event: {}", e)); } None => tracing::error!("Could not retrieve new output info"), } @@ -511,7 +517,7 @@ impl SimpleLayer { .swap_buffers(self.egl_state.egl_display, self.egl_window_surface) .unwrap(); - // Now that buffers are swapped we can reset the egl context + // Now that buffers are swapped, we can reset the egl context self.egl_state.detach_context(); // Request our next frame diff --git a/waypaper_engine_shared/Cargo.toml b/waypaper_engine_shared/Cargo.toml index 6b5905d..9ffe195 100644 --- a/waypaper_engine_shared/Cargo.toml +++ b/waypaper_engine_shared/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" serde = { version = "1", features = ["derive"] } cgmath = "0.18.0" serde-this-or-that = "0.5.0" -serde_json = "1" \ No newline at end of file +serde_json = "1" +subenum = "1.1.3" \ No newline at end of file diff --git a/waypaper_engine_shared/src/ipc.rs b/waypaper_engine_shared/src/ipc.rs index 8482096..00db193 100644 --- a/waypaper_engine_shared/src/ipc.rs +++ b/waypaper_engine_shared/src/ipc.rs @@ -1,10 +1,17 @@ use serde::{Deserialize, Serialize}; +use subenum::subenum; +#[subenum(IPCRequest)] #[derive(Clone, Debug, Serialize, Deserialize)] -pub enum IPCRequest { +pub enum InternalRequest { + #[subenum(IPCRequest)] SetWallpaper { id: u64, screen: String }, + #[subenum(IPCRequest)] KillDaemon, + #[subenum(IPCRequest)] ListOutputs, + + NewOutput { screen: String }, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -20,4 +27,5 @@ pub enum IPCError { WallpaperNotFound, UnsupportedWallpaperType, InternalError, + WallpaperLoadingError } diff --git a/waypaper_engine_shared/src/lib.rs b/waypaper_engine_shared/src/lib.rs index 1111bc4..73fdd85 100644 --- a/waypaper_engine_shared/src/lib.rs +++ b/waypaper_engine_shared/src/lib.rs @@ -1,3 +1,4 @@ +use std::env; use std::path::PathBuf; pub mod ipc; @@ -7,7 +8,7 @@ pub mod serde_utils; const WPE_DIR: &str = ".steam/steam/steamapps/workshop/content/431960/"; pub fn get_wpe_dir() -> PathBuf { - let wpe_dir = PathBuf::from(std::env::var("HOME").expect("No HOME environment variable set ?")) + let wpe_dir = PathBuf::from(env::var("HOME").expect("No HOME environment variable set ?")) .join(WPE_DIR); assert!( @@ -17,4 +18,4 @@ pub fn get_wpe_dir() -> PathBuf { ); wpe_dir -} +} \ No newline at end of file From cbfd6318355663ee794847376a0424ccc83c6411 Mon Sep 17 00:00:00 2001 From: undermirrors Date: Fri, 21 Nov 2025 13:23:21 +0100 Subject: [PATCH 3/4] feat: suggestion done --- waypaper_engine_daemon/src/profile_manager.rs | 49 ++++++++++--------- waypaper_engine_shared/Cargo.toml | 2 +- waypaper_engine_shared/src/lib.rs | 2 +- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/waypaper_engine_daemon/src/profile_manager.rs b/waypaper_engine_daemon/src/profile_manager.rs index 4fc4877..4e76651 100644 --- a/waypaper_engine_daemon/src/profile_manager.rs +++ b/waypaper_engine_daemon/src/profile_manager.rs @@ -1,53 +1,54 @@ use std::collections::HashMap; -use std::error::Error; use std::fs::File; use std::path::PathBuf; use std::{env, fs}; pub struct ProfileManager { - wallpapers: HashMap + wallpapers: HashMap, } impl ProfileManager { pub fn new() -> ProfileManager { ProfileManager { - wallpapers: HashMap::new() + wallpapers: HashMap::new(), } } - pub fn save_wallpaper(&mut self, id: u64, screen: &str) -> Result<(), Box> { + pub fn save_wallpaper(&mut self, id: u64, screen: &str) -> Result<(), String> { let path = save_dir()?; self.wallpapers.insert(screen.to_owned(), id); - let file = File::create(&path)?; - serde_json::to_writer_pretty(file, &self.wallpapers)?; - - Ok(()) + match File::create(&path) { + Ok(file) => match serde_json::to_writer_pretty(file, &self.wallpapers) { + Ok(_) => Ok(()), + Err(e) => Err(e.to_string()), + }, + Err(e) => Err(e.to_string()), + } } - pub fn load_wallpaper(&mut self, screen: &str) -> Option { - if !self.wallpapers. contains_key(screen) { - let file_path = save_dir().ok()?; - let file = File::open(&file_path).ok()?; - self.wallpapers = serde_json::from_reader(file).ok()?; - } - self.wallpapers.get(screen).copied() - } + pub fn load_wallpaper(&mut self, screen: &str) -> Option { + if !self.wallpapers.contains_key(screen) { + let file_path = save_dir().ok()?; + let file = File::open(&file_path).ok()?; + self.wallpapers = serde_json::from_reader(file).ok()?; + } + self.wallpapers.get(screen).copied() + } } -fn save_dir() -> Result> { - let base_dir = if let Ok(home) = env::var("HOME") { +fn save_dir() -> Result { + let base_dir = if let Ok(config) = env::var("XDG_CONFIG_HOME") { + PathBuf::from(config) + } else if let Ok(home) = env::var("HOME") { PathBuf::from(home).join(".config") } else { - return Err(Box::new(std::io::Error::new( - std::io::ErrorKind::NotFound, - "Unable to determine configuration directory", - ))); + return Err("Unable to find directory".to_string()) }; let parent = base_dir.join("waypaper_engine"); - if !parent.exists() { - fs::create_dir_all(&parent)?; + if !parent.exists() && fs::create_dir_all(&parent).is_err() { + return Err("Unable to create save directory".to_string()); } let file_path = parent.join("wallpapers.conf"); diff --git a/waypaper_engine_shared/Cargo.toml b/waypaper_engine_shared/Cargo.toml index 9ffe195..5bdb19c 100644 --- a/waypaper_engine_shared/Cargo.toml +++ b/waypaper_engine_shared/Cargo.toml @@ -8,4 +8,4 @@ serde = { version = "1", features = ["derive"] } cgmath = "0.18.0" serde-this-or-that = "0.5.0" serde_json = "1" -subenum = "1.1.3" \ No newline at end of file +subenum = "1.1.3" diff --git a/waypaper_engine_shared/src/lib.rs b/waypaper_engine_shared/src/lib.rs index 73fdd85..2fef58b 100644 --- a/waypaper_engine_shared/src/lib.rs +++ b/waypaper_engine_shared/src/lib.rs @@ -18,4 +18,4 @@ pub fn get_wpe_dir() -> PathBuf { ); wpe_dir -} \ No newline at end of file +} From 1cb2c6add3210b559386be1a9a7ee760dd497305 Mon Sep 17 00:00:00 2001 From: undermirrors Date: Fri, 21 Nov 2025 15:42:38 +0100 Subject: [PATCH 4/4] feat: make waypaper panic when you can't save --- waypaper_engine_daemon/src/app_state.rs | 9 ++---- waypaper_engine_daemon/src/profile_manager.rs | 29 +++++++------------ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/waypaper_engine_daemon/src/app_state.rs b/waypaper_engine_daemon/src/app_state.rs index 2431112..3ac2936 100644 --- a/waypaper_engine_daemon/src/app_state.rs +++ b/waypaper_engine_daemon/src/app_state.rs @@ -13,7 +13,7 @@ pub struct AppState { rendering_context: RenderingContext, internal_ipc_tx: Sender<(InternalRequest, Sender)>, internal_ipc_rx: Receiver<(InternalRequest, Sender)>, - profile_manager: ProfileManager + profile_manager: ProfileManager, } impl AppState { @@ -38,7 +38,6 @@ impl AppState { pub fn run(&mut self) -> Result<(), Box> { ffmpeg_next::init()?; - // we clone here to be thread safe let internal_ipc_tx = self.internal_ipc_tx.clone(); let ipc_thread = thread::spawn(move || { @@ -85,10 +84,8 @@ impl AppState { match self.internal_ipc_rx.try_recv() { Ok((req, response)) => match req { InternalRequest::SetWallpaper { id, screen } => { - if Self::set_wallpaper(self, id, &screen, &response) - && let Err(err) = self.profile_manager.save_wallpaper(id, &screen) - { - tracing::warn!("Unable to save wallpaper: {}", err); + if Self::set_wallpaper(self, id, &screen, &response) { + self.profile_manager.save_wallpaper(id, &screen); } } diff --git a/waypaper_engine_daemon/src/profile_manager.rs b/waypaper_engine_daemon/src/profile_manager.rs index 4e76651..d0135d0 100644 --- a/waypaper_engine_daemon/src/profile_manager.rs +++ b/waypaper_engine_daemon/src/profile_manager.rs @@ -14,22 +14,16 @@ impl ProfileManager { } } - pub fn save_wallpaper(&mut self, id: u64, screen: &str) -> Result<(), String> { - let path = save_dir()?; + pub fn save_wallpaper(&mut self, id: u64, screen: &str) { + let path = save_dir(); self.wallpapers.insert(screen.to_owned(), id); - - match File::create(&path) { - Ok(file) => match serde_json::to_writer_pretty(file, &self.wallpapers) { - Ok(_) => Ok(()), - Err(e) => Err(e.to_string()), - }, - Err(e) => Err(e.to_string()), - } + let file = File::create(&path).expect("Unable to create save file"); + serde_json::to_writer_pretty(file, &self.wallpapers).expect("Unable to write save into file"); } pub fn load_wallpaper(&mut self, screen: &str) -> Option { if !self.wallpapers.contains_key(screen) { - let file_path = save_dir().ok()?; + let file_path = save_dir(); let file = File::open(&file_path).ok()?; self.wallpapers = serde_json::from_reader(file).ok()?; } @@ -37,20 +31,17 @@ impl ProfileManager { } } -fn save_dir() -> Result { +fn save_dir() -> PathBuf { let base_dir = if let Ok(config) = env::var("XDG_CONFIG_HOME") { PathBuf::from(config) - } else if let Ok(home) = env::var("HOME") { - PathBuf::from(home).join(".config") } else { - return Err("Unable to find directory".to_string()) + PathBuf::from(env::var("HOME").expect("Unable to find directory")).join(".config") }; let parent = base_dir.join("waypaper_engine"); - if !parent.exists() && fs::create_dir_all(&parent).is_err() { - return Err("Unable to create save directory".to_string()); + if !parent.exists() { + fs::create_dir_all(&parent).expect("Unable to create save directory"); } - let file_path = parent.join("wallpapers.conf"); - Ok(file_path) + parent.join("wallpapers.conf") }