Merge pull request #49 from NotAShelf/notashelf/push-vootvqpuytyv

multicall: go back to forking solution
This commit is contained in:
raf 2025-11-25 10:08:24 +03:00 committed by GitHub
commit f838365314
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 44 additions and 22 deletions

1
Cargo.lock generated
View file

@ -1664,6 +1664,7 @@ dependencies = [
"env_logger", "env_logger",
"imagesize", "imagesize",
"inquire", "inquire",
"libc",
"log", "log",
"notify-rust", "notify-rust",
"ratatui", "ratatui",

View file

@ -28,6 +28,7 @@ imagesize = "0.14.0"
inquire = { default-features = false, version = "0.9.1", features = [ inquire = { default-features = false, version = "0.9.1", features = [
"crossterm", "crossterm",
] } ] }
libc = "0.2.177"
log = "0.4.28" log = "0.4.28"
env_logger = "0.11.8" env_logger = "0.11.8"
thiserror = "2.0.17" thiserror = "2.0.17"

View file

@ -6,6 +6,6 @@ pub trait QueryCommand {
impl QueryCommand for SqliteClipboardDb { impl QueryCommand for SqliteClipboardDb {
fn query_delete(&self, query: &str) -> Result<usize, StashError> { fn query_delete(&self, query: &str) -> Result<usize, StashError> {
<SqliteClipboardDb as ClipboardDb>::delete_query(self, query) <Self as ClipboardDb>::delete_query(self, query)
} }
} }

View file

@ -266,7 +266,7 @@ impl ClipboardDb for SqliteClipboardDb {
.execute( .execute(
"INSERT INTO clipboard (contents, mime, content_hash) VALUES (?1, ?2, \ "INSERT INTO clipboard (contents, mime, content_hash) VALUES (?1, ?2, \
?3)", ?3)",
params![buf, mime.map(|s| s.to_string()), content_hash], params![buf, mime, content_hash],
) )
.map_err(|e| StashError::Store(e.to_string().into()))?; .map_err(|e| StashError::Store(e.to_string().into()))?;

View file

@ -106,7 +106,7 @@ fn handle_check_primary() {
std::process::exit(exit_code); std::process::exit(exit_code);
} }
fn get_clipboard_type(primary: bool) -> CopyClipboardType { const fn get_clipboard_type(primary: bool) -> CopyClipboardType {
if primary { if primary {
CopyClipboardType::Primary CopyClipboardType::Primary
} else { } else {
@ -213,21 +213,32 @@ fn handle_clear_clipboard(
} }
fn fork_and_serve(prepared_copy: wl_clipboard_rs::copy::PreparedCopy) { fn fork_and_serve(prepared_copy: wl_clipboard_rs::copy::PreparedCopy) {
// Use a simpler approach: serve in background thread instead of forking // Use proper Unix fork() to create a child process that continues
// This avoids all the complexity and safety issues with fork() // serving clipboard content after parent exits.
let handle = std::thread::spawn(move || { // XXX: I wanted to choose and approach without fork, but we could not
if let Err(e) = prepared_copy.serve() { // ensure persistence after the thread dies. Alas, we gotta fork.
log::error!("background clipboard service failed: {e}"); unsafe {
match libc::fork() {
0 => {
// Child process - serve clipboard content
if let Err(e) = prepared_copy.serve() {
log::error!("background clipboard service failed: {e}");
std::process::exit(1);
}
std::process::exit(0);
},
-1 => {
// Fork failed
log::error!("failed to fork background process");
std::process::exit(1);
},
_ => {
// Parent process - exit immediately
log::debug!("forked background process to serve clipboard content");
std::process::exit(0);
},
} }
}); }
// Give the background thread a moment to start
std::thread::sleep(std::time::Duration::from_millis(50));
log::debug!("clipboard service started in background thread");
// Detach the thread to allow it to run independently
// The thread will be cleaned up when it completes or when the process exits
std::mem::forget(handle);
} }
pub fn wl_copy_main() -> Result<()> { pub fn wl_copy_main() -> Result<()> {
@ -255,14 +266,23 @@ pub fn wl_copy_main() -> Result<()> {
// Handle foreground vs background mode // Handle foreground vs background mode
if args.foreground { if args.foreground {
// Foreground mode: copy and serve in current process // Foreground mode: copy content and serve in current process
opts // Use prepare_copy + serve to ensure proper clipboard registration
.copy(Source::Bytes(input.into()), mime_type) let mut opts_fg = opts;
.context("failed to copy to clipboard")?; opts_fg.foreground(true);
let prepared_copy = opts_fg
.prepare_copy(Source::Bytes(input.into()), mime_type)
.context("failed to prepare copy")?;
// Serve in foreground - blocks until interrupted (Ctrl+C, etc.)
prepared_copy
.serve()
.context("failed to serve clipboard content")?;
} else { } else {
// Background mode: spawn child process to serve requests // Background mode: spawn child process to serve requests
// First prepare to copy to validate before spawning // First prepare to copy to validate before spawning
let mut opts_fg = opts.clone(); let mut opts_fg = opts;
opts_fg.foreground(true); opts_fg.foreground(true);
let prepared_copy = opts_fg let prepared_copy = opts_fg