smithay-clipboard/src/worker.rs

113 lines
3.8 KiB
Rust
Raw Normal View History

2024-03-14 15:46:52 -04:00
use std::borrow::Cow;
use std::io::{Error, ErrorKind, Result};
2024-03-20 15:41:09 -04:00
use std::marker::PhantomData;
use std::sync::mpsc::Sender;
use sctk::reexports::calloop::channel::Channel;
use sctk::reexports::calloop::{channel, EventLoop};
use sctk::reexports::calloop_wayland_source::WaylandSource;
use sctk::reexports::client::globals::registry_queue_init;
use sctk::reexports::client::Connection;
2024-03-22 18:41:31 -04:00
use crate::dnd::DndRequest;
2024-02-27 17:50:33 -05:00
use crate::mime::{AsMimeTypes, MimeType};
2024-03-22 18:41:31 -04:00
use crate::state::{State, Target};
/// Spawn a clipboard worker, which dispatches its own `EventQueue` and handles
/// clipboard requests.
2024-03-22 18:41:31 -04:00
pub fn spawn<T: 'static + Send + Clone>(
name: String,
display: Connection,
2024-03-20 15:41:09 -04:00
rx_chan: Channel<Command<T>>,
2024-02-27 17:50:33 -05:00
worker_replier: Sender<Result<(Vec<u8>, MimeType)>>,
) -> Option<std::thread::JoinHandle<()>> {
std::thread::Builder::new()
.name(name)
.spawn(move || {
worker_impl(display, rx_chan, worker_replier);
})
.ok()
}
/// Clipboard worker thread command.
2024-03-20 15:41:09 -04:00
pub enum Command<T> {
2024-02-28 15:01:39 -05:00
/// Loads data for the first available mime type in the provided list.
2024-03-22 18:41:31 -04:00
Load(Cow<'static, [MimeType]>, Target),
2024-02-28 15:01:39 -05:00
/// Store Data with the given mime types.
2024-03-22 18:41:31 -04:00
Store(Box<dyn AsMimeTypes + Send>, Target),
2024-03-20 15:41:09 -04:00
#[cfg(feature = "dnd")]
/// Init DnD
2024-03-22 18:41:31 -04:00
DndRequest(DndRequest<T>),
/// Shutdown the worker.
Exit,
2024-03-20 15:41:09 -04:00
/// Phantom data
Phantom(PhantomData<T>),
}
/// Handle clipboard requests.
2024-03-22 18:41:31 -04:00
fn worker_impl<T: 'static + Clone>(
connection: Connection,
2024-03-20 15:41:09 -04:00
rx_chan: Channel<Command<T>>,
2024-02-27 17:50:33 -05:00
reply_tx: Sender<Result<(Vec<u8>, MimeType)>>,
) {
let (globals, event_queue) = match registry_queue_init(&connection) {
Ok(data) => data,
Err(_) => return,
};
2024-03-20 15:41:09 -04:00
let mut event_loop = EventLoop::<State<T>>::try_new().unwrap();
let loop_handle = event_loop.handle();
let mut state = match State::new(&globals, &event_queue.handle(), loop_handle.clone(), reply_tx)
{
Some(state) => state,
None => return,
};
loop_handle
.insert_source(rx_chan, |event, _, state| {
if let channel::Event::Msg(event) = event {
match event {
2024-02-27 17:50:33 -05:00
Command::Exit => state.exit = true,
Command::Store(data, target) => {
state.store_selection(target, data);
},
2024-03-22 18:41:31 -04:00
Command::Load(mime_types, Target::Clipboard)
2024-02-27 17:50:33 -05:00
if state.data_device_manager_state.is_some() =>
{
2024-03-22 18:41:31 -04:00
if let Err(err) = state.load(Target::Clipboard, &mime_types) {
let _ = state.reply_tx.send(Err(err));
}
},
2024-03-22 18:41:31 -04:00
Command::Load(mime_types, Target::Primary)
if state.primary_selection_manager_state.is_some() =>
{
2024-03-22 18:41:31 -04:00
if let Err(err) = state.load(Target::Primary, &mime_types) {
let _ = state.reply_tx.send(Err(err));
}
},
2024-02-27 17:50:33 -05:00
Command::Load(..) => {
let _ = state.reply_tx.send(Err(Error::new(
ErrorKind::Other,
"requested selection is not supported",
)));
},
2024-03-20 15:41:09 -04:00
#[cfg(feature = "dnd")]
2024-03-22 18:41:31 -04:00
Command::DndRequest(r) => {
state.handle_dnd_request(r);
2024-03-20 15:41:09 -04:00
},
Command::Phantom(_) => unreachable!(),
}
}
})
.unwrap();
WaylandSource::new(connection, event_queue).insert(loop_handle).unwrap();
loop {
if event_loop.dispatch(None, &mut state).is_err() || state.exit {
break;
}
}
}