Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 63 additions & 50 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions waypaper_engine_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
245 changes: 145 additions & 100 deletions waypaper_engine_daemon/src/app_state.rs
Original file line number Diff line number Diff line change
@@ -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<IPCResponse>)>,
internal_ipc_rx: Receiver<(InternalRequest, Sender<IPCResponse>)>,
profile_manager: ProfileManager,
}

impl AppState {
Expand All @@ -22,23 +23,22 @@ 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<IPCResponse>)>();

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<dyn Error>> {
ffmpeg_next::init()?;

let (tx, rx) = mpsc::channel::<(IPCRequest, Sender<IPCResponse>)>();
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();
Expand All @@ -53,8 +53,10 @@ impl AppState {
break;
}

let (req_tx, req_rx) = mpsc::channel::<IPCResponse>();
tx.send((request.clone(), req_tx)).unwrap();
let (req_tx, req_rx) = crossbeam::channel::unbounded::<IPCResponse>();
internal_ipc_tx
.send((InternalRequest::from(request.clone()), req_tx))
.unwrap();
match req_rx.recv() {
Ok(response) => {
tracing::debug!("Sending response : [{:?}]", response);
Expand All @@ -79,100 +81,33 @@ 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)
{
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();
InternalRequest::SetWallpaper { id, screen } => {
if Self::set_wallpaper(self, id, &screen, &response) {
self.profile_manager.save_wallpaper(id, &screen);
}
}
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 => {}
Expand All @@ -187,4 +122,114 @@ impl AppState {

Ok(())
}

fn set_wallpaper(&mut self, id: u64, screen: &str, response: &Sender<IPCResponse>) -> 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");
Comment thread
flashonfire marked this conversation as resolved.
}

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
}
}
}
1 change: 1 addition & 0 deletions waypaper_engine_daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
47 changes: 47 additions & 0 deletions waypaper_engine_daemon/src/profile_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use std::{env, fs};

pub struct ProfileManager {
wallpapers: HashMap<String, u64>,
}

impl ProfileManager {
pub fn new() -> ProfileManager {
ProfileManager {
wallpapers: HashMap::new(),
}
}

pub fn save_wallpaper(&mut self, id: u64, screen: &str) {
let path = save_dir();
self.wallpapers.insert(screen.to_owned(), id);
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<u64> {
if !self.wallpapers.contains_key(screen) {
let file_path = save_dir();
let file = File::open(&file_path).ok()?;
self.wallpapers = serde_json::from_reader(file).ok()?;
}
self.wallpapers.get(screen).copied()
}
}

fn save_dir() -> PathBuf {
let base_dir = if let Ok(config) = env::var("XDG_CONFIG_HOME") {
PathBuf::from(config)
} else {
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).expect("Unable to create save directory");
}

parent.join("wallpapers.conf")
}
Loading