Skip to content

Commit

Permalink
Merge pull request #273 from Fuyukai/nested-wayland
Browse files Browse the repository at this point in the history
Add support for running on multiple Wayland displays simultaneously.
  • Loading branch information
LGFae authored Apr 11, 2024
2 parents 3a3596c + cfc676c commit 01540d7
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 84 deletions.
70 changes: 33 additions & 37 deletions daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ mod cli;
pub mod raw_pool;
mod wallpaper;
use log::{debug, error, info, warn, LevelFilter};
use rustix::event::{poll, PollFd, PollFlags};
use rustix::{
event::{poll, PollFd, PollFlags},
path::Arg,
};
use simplelog::{ColorChoice, TermLogger, TerminalMode, ThreadLogMode};
use wallpaper::Wallpaper;

Expand All @@ -18,6 +21,7 @@ use std::{
fd::OwnedFd,
unix::net::{UnixListener, UnixStream},
},
path::PathBuf,
sync::{
atomic::{AtomicBool, Ordering},
Arc, OnceLock,
Expand All @@ -39,7 +43,9 @@ use wayland_client::{
Connection, Dispatch, Proxy, QueueHandle,
};

use utils::ipc::{get_socket_path, Answer, BgInfo, PixelFormat, Request};
use utils::ipc::{
connect_to_socket, get_socket_path, read_socket, Answer, BgInfo, PixelFormat, Request,
};

use animations::Animator;

Expand Down Expand Up @@ -242,20 +248,24 @@ fn setup_signals_and_eventfd() -> OwnedFd {
struct SocketWrapper(UnixListener);
impl SocketWrapper {
fn new() -> Result<Self, String> {
if is_daemon_running()? {
return Err("There is an swww-daemon instance already running!".to_string());
}

let socket_addr = get_socket_path();

if socket_addr.exists() {
warn!(
"socket file {} was not deleted when the previous daemon exited",
socket_addr.to_string_lossy()
);
if let Err(e) = std::fs::remove_file(&socket_addr) {
return Err(format!("failed to delete previous socket: {e}"));
if is_daemon_running(&socket_addr)? {
return Err(
"There is an swww-daemon instance already running on this socket!".to_string(),
);
} else {
warn!(
"socket file {} was not deleted when the previous daemon exited",
socket_addr.to_string_lossy()
);
if let Err(e) = std::fs::remove_file(&socket_addr) {
return Err(format!("failed to delete previous socket: {e}"));
}
}
}

let runtime_dir = match socket_addr.parent() {
Some(path) => path,
None => return Err("couldn't find a valid runtime directory".to_owned()),
Expand Down Expand Up @@ -725,32 +735,18 @@ fn make_logger(quiet: bool) {
.expect("Failed to initialize logger. Cancelling...");
}

fn is_daemon_running() -> Result<bool, String> {
let proc = std::path::PathBuf::from("/proc");

let entries = match proc.read_dir() {
Ok(e) => e,
Err(e) => return Err(e.to_string()),
pub fn is_daemon_running(addr: &PathBuf) -> Result<bool, String> {
let sock = match connect_to_socket(addr, 5, 100) {
Ok(s) => s,
// likely a connection refused; either way, this is a reliable signal there's no surviving
// daemon.
Err(_) => return Ok(false),
};

for entry in entries.flatten() {
let dirname = entry.file_name();
if let Ok(pid) = dirname.to_string_lossy().parse::<u32>() {
if std::process::id() == pid {
continue;
}
let mut entry_path = entry.path();
entry_path.push("cmdline");
if let Ok(cmd) = std::fs::read_to_string(entry_path) {
let mut args = cmd.split(&[' ', '\0']);
if let Some(arg0) = args.next() {
if arg0.ends_with("swww-daemon") {
return Ok(true);
}
}
}
}
Request::Ping.send(&sock)?;
let answer = Answer::receive(&read_socket(&sock)?);
match answer {
Answer::Ping(_) => Ok(true),
_ => Err("Daemon did not return Answer::Ping, as expected".to_string()),
}

Ok(false)
}
52 changes: 8 additions & 44 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use clap::Parser;
use std::{os::unix::net::UnixStream, path::PathBuf, process::Stdio, time::Duration};
use std::{path::PathBuf, process::Stdio, time::Duration};

use utils::{
cache,
ipc::{self, get_socket_path, read_socket, AnimationRequest, Answer, Request},
ipc::{
self, connect_to_socket, get_socket_path, read_socket, AnimationRequest, Answer, Request,
},
};

mod imgproc;
Expand Down Expand Up @@ -61,7 +63,7 @@ fn main() -> Result<(), String> {

let mut configured = false;
while !configured {
let socket = connect_to_socket(5, 100)?;
let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
Request::Ping.send(&socket)?;
let bytes = read_socket(&socket)?;
let answer = Answer::receive(&bytes);
Expand All @@ -83,7 +85,7 @@ fn process_swww_args(args: &Swww) -> Result<(), String> {
Some(request) => request,
None => return Ok(()),
};
let socket = connect_to_socket(5, 100)?;
let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
request.send(&socket)?;
let bytes = read_socket(&socket)?;
drop(socket);
Expand Down Expand Up @@ -144,7 +146,7 @@ fn make_request(args: &Swww) -> Result<Option<Request>, String> {
let img_request = make_img_request(img, first_frame, &dims, &outputs)?;
let animations = make_animation_request(img, &imgbuf, &dims, format, &outputs);

let socket = connect_to_socket(5, 100)?;
let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
Request::Img(img_request).send(&socket)?;
let bytes = read_socket(&socket)?;
drop(socket);
Expand Down Expand Up @@ -219,7 +221,7 @@ fn get_format_dims_and_outputs(
let mut dims: Vec<(u32, u32)> = Vec::new();
let mut imgs: Vec<ipc::BgImg> = Vec::new();

let socket = connect_to_socket(5, 100)?;
let socket = connect_to_socket(&get_socket_path(), 5, 100)?;
Request::Query.send(&socket)?;
let bytes = read_socket(&socket)?;
drop(socket);
Expand Down Expand Up @@ -340,44 +342,6 @@ fn spawn_daemon(no_daemon: bool, format: &Option<cli::PixelFormat>) -> Result<()
}
}

/// We make sure the Stream is always set to blocking mode
///
/// * `tries` - how many times to attempt the connection
/// * `interval` - how long to wait between attempts, in milliseconds
fn connect_to_socket(tries: u8, interval: u64) -> Result<UnixStream, String> {
//Make sure we try at least once
let tries = if tries == 0 { 1 } else { tries };
let path = get_socket_path();
let mut error = None;
for _ in 0..tries {
match UnixStream::connect(&path) {
Ok(socket) => {
if let Err(e) = socket.set_nonblocking(false) {
return Err(format!("Failed to set blocking connection: {e}"));
}
#[cfg(debug_assertions)]
let timeout = Duration::from_secs(30); //Some operations take a while to respond in debug mode
#[cfg(not(debug_assertions))]
let timeout = Duration::from_secs(5);

if let Err(e) = socket.set_read_timeout(Some(timeout)) {
return Err(format!("failed to set read timeout for socket: {e}"));
}

return Ok(socket);
}
Err(e) => error = Some(e),
}
std::thread::sleep(Duration::from_millis(interval));
}
let error = error.unwrap();
if error.kind() == std::io::ErrorKind::NotFound {
return Err("Socket file not found. Are you sure swww-daemon is running?".to_string());
}

Err(format!("Failed to connect to socket: {error}"))
}

fn is_daemon_running() -> Result<bool, String> {
let proc = PathBuf::from("/proc");

Expand Down
57 changes: 54 additions & 3 deletions utils/src/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{
fmt,
io::{BufReader, BufWriter, Read, Write},
os::unix::net::UnixStream,
path::{Path, PathBuf},
path::PathBuf,
time::Duration,
};

Expand Down Expand Up @@ -328,8 +328,22 @@ pub fn get_socket_path() -> PathBuf {
} else {
"/tmp/swww".to_string()
};
let runtime_dir = Path::new(&runtime_dir);
runtime_dir.join("swww.socket")

let mut socket_path = PathBuf::new();
socket_path.push(runtime_dir);

let mut socket_name = String::new();
socket_name.push_str("swww-");
if let Ok(socket) = std::env::var("WAYLAND_DISPLAY") {
socket_name.push_str(socket.as_str());
} else {
socket_name.push_str("wayland-0")
}
socket_name.push_str(".socket");

socket_path.push(socket_name);

socket_path
}

pub fn get_cache_path() -> Result<PathBuf, String> {
Expand Down Expand Up @@ -360,3 +374,40 @@ pub fn get_cache_path() -> Result<PathBuf, String> {

Ok(cache_path)
}

/// We make sure the Stream is always set to blocking mode
///
/// * `tries` - how many times to attempt the connection
/// * `interval` - how long to wait between attempts, in milliseconds
pub fn connect_to_socket(addr: &PathBuf, tries: u8, interval: u64) -> Result<UnixStream, String> {
//Make sure we try at least once
let tries = if tries == 0 { 1 } else { tries };
let mut error = None;
for _ in 0..tries {
match UnixStream::connect(addr) {
Ok(socket) => {
if let Err(e) = socket.set_nonblocking(false) {
return Err(format!("Failed to set blocking connection: {e}"));
}
#[cfg(debug_assertions)]
let timeout = Duration::from_secs(30); //Some operations take a while to respond in debug mode
#[cfg(not(debug_assertions))]
let timeout = Duration::from_secs(5);

if let Err(e) = socket.set_read_timeout(Some(timeout)) {
return Err(format!("failed to set read timeout for socket: {e}"));
}

return Ok(socket);
}
Err(e) => error = Some(e),
}
std::thread::sleep(Duration::from_millis(interval));
}
let error = error.unwrap();
if error.kind() == std::io::ErrorKind::NotFound {
return Err("Socket file not found. Are you sure swww-daemon is running?".to_string());
}

Err(format!("Failed to connect to socket: {error}"))
}

0 comments on commit 01540d7

Please sign in to comment.