This commit is contained in:
nora 2025-09-18 20:06:07 +02:00
parent 0df0d40f7c
commit fce09d16cd
3 changed files with 53 additions and 176 deletions

109
Cargo.lock generated
View file

@ -108,15 +108,6 @@ dependencies = [
"winit", "winit",
] ]
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]] [[package]]
name = "adler2" name = "adler2"
version = "2.0.1" version = "2.0.1"
@ -421,21 +412,6 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "backtrace"
version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "bit-set" name = "bit-set"
version = "0.8.0" version = "0.8.0"
@ -644,7 +620,6 @@ dependencies = [
"eyre", "eyre",
"rustix 1.1.2", "rustix 1.1.2",
"serde", "serde",
"tokio",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"wayland-client", "wayland-client",
@ -1295,12 +1270,6 @@ dependencies = [
"wasi 0.14.4+wasi-0.2.4", "wasi 0.14.4+wasi-0.2.4",
] ]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]] [[package]]
name = "gl_generator" name = "gl_generator"
version = "0.14.0" version = "0.14.0"
@ -1622,17 +1591,6 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "io-uring"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
dependencies = [
"bitflags 2.9.4",
"cfg-if",
"libc",
]
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@ -1862,17 +1820,6 @@ dependencies = [
"simd-adler32", "simd-adler32",
] ]
[[package]]
name = "mio"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "moxcms" name = "moxcms"
version = "0.7.5" version = "0.7.5"
@ -2297,15 +2244,6 @@ dependencies = [
"objc2-foundation 0.2.2", "objc2-foundation 0.2.2",
] ]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.21.3" version = "1.21.3"
@ -2709,12 +2647,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "1.1.0" version = "1.1.0"
@ -2926,16 +2858,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "socket2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "spirv" name = "spirv"
version = "0.3.0+sdk-1.3.268.0" version = "0.3.0+sdk-1.3.268.0"
@ -3127,37 +3049,6 @@ dependencies = [
"zerovec", "zerovec",
] ]
[[package]]
name = "tokio"
version = "1.47.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
dependencies = [
"backtrace",
"bytes",
"io-uring",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"slab",
"socket2",
"tokio-macros",
"windows-sys 0.59.0",
]
[[package]]
name = "tokio-macros"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.11" version = "0.6.11"

View file

@ -11,7 +11,6 @@ egui_extras = { version = "0.32.2", features = ["image"] }
eyre = "0.6.12" eyre = "0.6.12"
rustix = "1.1.2" rustix = "1.1.2"
serde = "1.0.219" serde = "1.0.219"
tokio = { version = "1.47.1", features = ["full", "sync"] }
tracing = { version = "0.1.41", features = ["attributes"] } tracing = { version = "0.1.41", features = ["attributes"] }
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
wayland-client = "0.31.11" wayland-client = "0.31.11"

View file

@ -2,12 +2,16 @@ use super::HistoryItem;
use super::MAX_ENTRY_SIZE; use super::MAX_ENTRY_SIZE;
use eframe::egui::ahash::HashSet; use eframe::egui::ahash::HashSet;
use eyre::Context; use eyre::Context;
use eyre::ContextCompat;
use eyre::bail; use eyre::bail;
use rustix::event::PollFd;
use rustix::event::PollFlags;
use rustix::fs::OFlags; use rustix::fs::OFlags;
use rustix::fs::fcntl_setfl; use rustix::fs::fcntl_setfl;
use rustix::io::FdFlags; use rustix::io::FdFlags;
use std::collections::HashMap; use std::collections::HashMap;
use std::future::poll_fn; use std::future::poll_fn;
use std::io::PipeReader;
use std::io::{BufReader, BufWriter, PipeWriter, Read, Write}; use std::io::{BufReader, BufWriter, PipeWriter, Read, Write};
use std::os::fd::AsFd; use std::os::fd::AsFd;
use std::os::unix::net::{UnixListener, UnixStream}; use std::os::unix::net::{UnixListener, UnixStream};
@ -19,6 +23,7 @@ use tracing::error;
use tracing::info; use tracing::info;
use tracing::warn; use tracing::warn;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
use wayland_client::EventQueue;
use wayland_client::protocol::wl_callback::WlCallback; use wayland_client::protocol::wl_callback::WlCallback;
use wayland_client::protocol::wl_display::WlDisplay; use wayland_client::protocol::wl_display::WlDisplay;
use wayland_client::protocol::wl_registry::WlRegistry; use wayland_client::protocol::wl_registry::WlRegistry;
@ -39,7 +44,7 @@ struct SharedState {
// for deduplication because the event stream will tell us that we just copied something :) // for deduplication because the event stream will tell us that we just copied something :)
last_copied_item_id: AtomicU64, last_copied_item_id: AtomicU64,
items: Mutex<Vec<HistoryItem>>, items: Mutex<Vec<HistoryItem>>,
select_history_send: tokio::sync::mpsc::Sender<HistoryItem>, notify_write_send: PipeWriter,
data_control_manager: OnceLock<ExtDataControlManagerV1>, data_control_manager: OnceLock<ExtDataControlManagerV1>,
data_control_devices: Mutex<HashMap</*seat global name */ u32, ExtDataControlDeviceV1>>, data_control_devices: Mutex<HashMap</*seat global name */ u32, ExtDataControlDeviceV1>>,
@ -172,12 +177,6 @@ impl Dispatch<WlSeat, ()> for WlState {
} }
} }
impl Dispatch<ExtDataControlDeviceV1, ()> for WlState { impl Dispatch<ExtDataControlDeviceV1, ()> for WlState {
#[tracing::instrument(
skip(state, _proxy, event, _data, _conn, _qhandle),
level = "info",
ret,
target = "ExtDataControlDeviceV1::event"
)]
fn event( fn event(
state: &mut Self, state: &mut Self,
_proxy: &ExtDataControlDeviceV1, _proxy: &ExtDataControlDeviceV1,
@ -303,12 +302,6 @@ impl Dispatch<ExtDataControlOfferV1, ()> for WlState {
} }
impl Dispatch<ExtDataControlSourceV1, OfferData> for WlState { impl Dispatch<ExtDataControlSourceV1, OfferData> for WlState {
#[tracing::instrument(
skip(_state, proxy, event, data, _conn, _qhandle),
level = "info",
ret,
target = "ExtDataControlSourceV1::event"
)]
fn event( fn event(
_state: &mut Self, _state: &mut Self,
proxy: &ExtDataControlSourceV1, proxy: &ExtDataControlSourceV1,
@ -357,18 +350,15 @@ pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
let conn = let conn =
wayland_client::Connection::connect_to_env().wrap_err("connecting to the compositor")?; wayland_client::Connection::connect_to_env().wrap_err("connecting to the compositor")?;
rustix::fs::fcntl_setfl(conn.as_fd(), OFlags::NONBLOCK).expect("TODO");
let mut queue = conn.new_event_queue::<WlState>(); let mut queue = conn.new_event_queue::<WlState>();
let (select_history_send, mut select_history_recv) = let (notify_write_recv, notify_write_send) = std::io::pipe().expect("todo");
tokio::sync::mpsc::channel::<HistoryItem>(1);
let shared_state = Arc::new(SharedState { let shared_state = Arc::new(SharedState {
next_item_id: AtomicU64::new(0), next_item_id: AtomicU64::new(0),
last_copied_item_id: AtomicU64::new(u64::MAX), last_copied_item_id: AtomicU64::new(u64::MAX),
items: Mutex::new(Vec::<HistoryItem>::new()), items: Mutex::new(Vec::<HistoryItem>::new()),
select_history_send, notify_write_send,
data_control_manager: OnceLock::new(), data_control_manager: OnceLock::new(),
data_control_devices: Mutex::new(HashMap::new()), data_control_devices: Mutex::new(HashMap::new()),
@ -403,57 +393,20 @@ pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
if wl_state.shared_state.data_control_manager.get().is_none() { if wl_state.shared_state.data_control_manager.get().is_none() {
bail!( bail!(
"{} not found, the ext-data-control-v1 Wayland extension is likely unsupported by your compositor.\n\ "{} not found, the ext-data-control-v1 Wayland extension is likely unsupported by your compositor.\n\
check https://wayland.app/protocols/ext-data-control-v1#compositor-support check https://wayland.app/protocols/ext-data-control-v1#compositor-support\
", ",
ExtDataControlManagerV1::interface().name ExtDataControlManagerV1::interface().name
); );
} }
rustix::fs::fcntl_setfl(notify_write_recv.as_fd(), OFlags::NONBLOCK).expect("todo");
rustix::fs::fcntl_setfl(conn.as_fd(), OFlags::NONBLOCK).expect("TODO");
std::thread::spawn(move || { std::thread::spawn(move || {
tokio::runtime::Builder::new_multi_thread() if let Err(err) = dispatch_wayland(queue, wl_state, notify_write_recv) {
.enable_all() error!("error on Wayland thread: {err:?}");
.build() std::process::exit(1);
.unwrap() }
.block_on(async {
loop {
info!("about to cook");
queue.dispatch_pending(&mut wl_state).expect("todo");
let read_guard = queue.prepare_read().expect("todo");
let fd =
tokio::io::unix::AsyncFd::new(read_guard.connection_fd()).expect("todo");
info!("gonna wait, maybe forever");
tokio::select! {
result = fd.readable() => {
info!("we are ready to read!");
if let Err(err) = result {
error!("Received error from Wayland: {:?}", err);
std::process::exit(1);
}
drop(fd);
read_guard.read().expect("todo");
}
item = select_history_recv.recv() => {
info!("received thing from channel");
match item {
None => {
error!("IPC socket thread hung up");
std::process::exit(1);
}
Some(item) => {
do_copy_into_clipboard(item, &wl_state.shared_state);
}
}
}
}
}
});
}); });
info!("Listening on {}", socket_path.display()); info!("Listening on {}", socket_path.display());
@ -478,6 +431,32 @@ pub fn main(socket_path: &PathBuf) -> eyre::Result<()> {
Ok(()) Ok(())
} }
fn dispatch_wayland(
mut queue: EventQueue<WlState>,
mut wl_state: WlState,
notify_write_recv: PipeReader,
) -> eyre::Result<()> {
loop {
queue
.dispatch_pending(&mut wl_state)
.wrap_err("dispatching Wayland events")?;
let read_guard = queue
.prepare_read()
.wrap_err("preparing read from Wayland socket")?;
let _ = queue.flush();
let pollfd1_read = PollFd::from_borrowed_fd(read_guard.connection_fd(), PollFlags::IN);
let pollfd_signal = PollFd::from_borrowed_fd(notify_write_recv.as_fd(), PollFlags::IN);
let _ = rustix::event::poll(&mut [pollfd1_read, pollfd_signal], None);
read_guard
.read_without_dispatch()
.wrap_err("reading from wayland socket")?;
}
}
#[tracing::instrument(skip(peer, shared_state), level = "info")] #[tracing::instrument(skip(peer, shared_state), level = "info")]
fn handle_peer(mut peer: UnixStream, shared_state: &SharedState) -> eyre::Result<()> { fn handle_peer(mut peer: UnixStream, shared_state: &SharedState) -> eyre::Result<()> {
let mut request = [0; 1]; let mut request = [0; 1];
@ -509,9 +488,17 @@ fn handle_copy(mut peer: UnixStream, shared_state: &SharedState) -> Result<(), e
let Some(idx) = items.iter().position(|item| item.id == id) else { let Some(idx) = items.iter().position(|item| item.id == id) else {
return Ok(()); return Ok(());
}; };
let entry = items.remove(idx); let item = items.remove(idx);
items.push(entry.clone()); items.push(item.clone());
shared_state.select_history_send.try_send(entry)?;
drop(items);
do_copy_into_clipboard(item, &shared_state).wrap_err("doing copy")?;
(&shared_state.notify_write_send)
.write_all(&[0])
.wrap_err("notifying wayland thread")?;
Ok(()) Ok(())
} }