servo/
clipboard_delegate.rs1use ipc_channel::ipc::IpcSender;
6
7use crate::WebView;
8
9pub struct StringRequest {
10 pub(crate) result_sender: IpcSender<Result<String, String>>,
11 response_sent: bool,
12}
13
14impl StringRequest {
15 pub fn success(mut self, string: String) {
16 let _ = self.result_sender.send(Ok(string));
17 self.response_sent = true;
18 }
19
20 pub fn failure(mut self, message: String) {
21 let _ = self.result_sender.send(Err(message));
22 self.response_sent = true;
23 }
24}
25
26impl From<IpcSender<Result<String, String>>> for StringRequest {
27 fn from(result_sender: IpcSender<Result<String, String>>) -> Self {
28 Self {
29 result_sender,
30 response_sent: false,
31 }
32 }
33}
34
35impl Drop for StringRequest {
36 fn drop(&mut self) {
37 if !self.response_sent {
38 let _ = self
39 .result_sender
40 .send(Err("No response sent to request.".into()));
41 }
42 }
43}
44
45pub trait ClipboardDelegate {
50 fn clear(&self, _webview: WebView) {}
52
53 fn get_text(&self, _webview: WebView, _request: StringRequest) {}
57
58 fn set_text(&self, _webview: WebView, _new_contents: String) {}
60}
61
62pub(crate) struct DefaultClipboardDelegate;
63
64impl ClipboardDelegate for DefaultClipboardDelegate {
65 fn clear(&self, _webview: WebView) {
66 clipboard::clear();
67 }
68
69 fn get_text(&self, _webview: WebView, request: StringRequest) {
70 clipboard::get_text(request);
71 }
72
73 fn set_text(&self, _webview: WebView, new_contents: String) {
74 clipboard::set_text(new_contents);
75 }
76}
77
78mod fallback_clipboard {
79 use std::sync::{LockResult, Mutex, OnceLock};
80
81 use crate::clipboard_delegate::StringRequest;
82
83 static SHARED_FALLBACK_CLIPBOARD: OnceLock<Mutex<String>> = OnceLock::new();
86
87 fn with_shared_clipboard(callback: impl FnOnce(&mut String)) {
88 let clipboard_mutex =
89 SHARED_FALLBACK_CLIPBOARD.get_or_init(|| Mutex::new(Default::default()));
90 if let LockResult::Ok(mut string) = clipboard_mutex.lock() {
91 callback(&mut string)
92 }
93 }
94
95 pub(super) fn clear() {
96 with_shared_clipboard(|clipboard_string| {
97 clipboard_string.clear();
98 });
99 }
100
101 pub(super) fn get_text(request: StringRequest) {
102 with_shared_clipboard(move |clipboard_string| request.success(clipboard_string.clone()));
103 }
104
105 pub(super) fn set_text(new_contents: String) {
106 with_shared_clipboard(move |clipboard_string| {
107 *clipboard_string = new_contents;
108 });
109 }
110}
111
112#[cfg(all(
113 feature = "clipboard",
114 not(any(target_os = "android", target_env = "ohos"))
115))]
116mod clipboard {
117 use std::sync::OnceLock;
118
119 use arboard::Clipboard;
120 use parking_lot::Mutex;
121
122 use super::StringRequest;
123 use crate::clipboard_delegate::fallback_clipboard;
124
125 static SHARED_CLIPBOARD: OnceLock<Option<Mutex<Clipboard>>> = OnceLock::new();
130
131 fn with_shared_clipboard<ResultType>(
132 callback: impl FnOnce(&mut Clipboard) -> Result<ResultType, arboard::Error>,
133 ) -> Result<ResultType, arboard::Error> {
134 match SHARED_CLIPBOARD.get_or_init(|| Clipboard::new().ok().map(Mutex::new)) {
135 Some(clipboard_mutex) => callback(&mut clipboard_mutex.lock()),
136 None => Err(arboard::Error::ClipboardNotSupported),
137 }
138 }
139
140 pub(super) fn clear() {
141 if with_shared_clipboard(|clipboard| clipboard.clear()).is_err() {
142 fallback_clipboard::clear();
143 }
144 }
145
146 pub(super) fn get_text(request: StringRequest) {
147 if let Ok(text) = with_shared_clipboard(|clipboard| clipboard.get_text()) {
148 request.success(text);
149 return;
150 };
151 fallback_clipboard::get_text(request);
152 }
153
154 pub(super) fn set_text(new_contents: String) {
155 if with_shared_clipboard(|clipboard| clipboard.set_text(&new_contents)).is_err() {
156 fallback_clipboard::set_text(new_contents);
157 }
158 }
159}
160
161#[cfg(any(not(feature = "clipboard"), target_os = "android", target_env = "ohos"))]
162mod clipboard {
163 use super::StringRequest;
164 use crate::clipboard_delegate::fallback_clipboard;
165
166 pub(super) fn clear() {
167 fallback_clipboard::clear();
168 }
169
170 pub(super) fn get_text(request: StringRequest) {
171 fallback_clipboard::get_text(request);
172 }
173
174 pub(super) fn set_text(new_contents: String) {
175 fallback_clipboard::set_text(new_contents);
176 }
177}