1use std::{cell::RefCell, collections::VecDeque};
8
9use crate::{keyboard_state::next_input_sequence, runtime::schedule_runtime_redraw};
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum ClipboardAction {
14 Copy,
16 Cut,
18 Paste(String),
20}
21
22pub struct ClipboardWrite {
24 text: String,
25 on_success: Box<dyn FnOnce() + Send + Sync>,
26}
27
28impl ClipboardWrite {
29 pub fn text(&self) -> &str {
31 &self.text
32 }
33
34 pub fn complete(self, succeeded: bool) {
36 if succeeded {
37 (self.on_success)();
38 }
39 }
40}
41
42pub enum ClipboardResponse {
44 Ignored,
46 Handled,
48 Write(ClipboardWrite),
50}
51
52pub struct ClipboardInput<'a> {
54 pub action: &'a ClipboardAction,
56 pub(crate) response: &'a mut Option<ClipboardResponse>,
57}
58
59impl ClipboardInput<'_> {
60 pub fn handle(&mut self) {
62 *self.response = Some(ClipboardResponse::Handled);
63 }
64
65 pub fn write_text(&mut self, text: String, on_success: impl FnOnce() + Send + Sync + 'static) {
67 *self.response = Some(ClipboardResponse::Write(ClipboardWrite {
68 text,
69 on_success: Box::new(on_success),
70 }));
71 }
72}
73
74pub trait ClipboardInputModifierNode: Send + Sync + 'static {
76 fn on_clipboard_input(&self, input: ClipboardInput<'_>);
78}
79
80pub(crate) struct QueuedClipboardAction {
81 pub sequence: u64,
82 pub action: ClipboardAction,
83 pub reply: Box<dyn FnOnce(ClipboardResponse) + Send + Sync>,
84}
85
86const REQUESTS: crate::session::SessionLocal<RefCell<VecDeque<QueuedClipboardAction>>> =
87 crate::session::SessionLocal::new();
88
89pub fn request_clipboard_action(
95 action: ClipboardAction,
96 reply: impl FnOnce(ClipboardResponse) + Send + Sync + 'static,
97) {
98 REQUESTS.with_borrow_mut(|requests| {
99 requests.push_back(QueuedClipboardAction {
100 sequence: next_input_sequence(),
101 action,
102 reply: Box::new(reply),
103 })
104 });
105 schedule_runtime_redraw();
106}
107
108pub(crate) fn take_requests() -> Vec<QueuedClipboardAction> {
109 REQUESTS.with_borrow_mut(|requests| requests.drain(..).collect())
110}
111
112pub(crate) fn has_pending_requests() -> bool {
113 REQUESTS.with_borrow(|requests| !requests.is_empty())
114}
115
116pub(crate) fn clear_requests() {
117 let requests = REQUESTS.with_borrow_mut(std::mem::take);
118 drop(requests);
119}