1use std::ffi::{CStr, CString};
2use std::fmt;
3use std::os::raw::c_char;
4use std::ptr;
5
6pub trait ClipboardBackend: 'static {
8 fn get(&mut self) -> Option<String>;
11 fn set(&mut self, value: &str);
13}
14
15pub(crate) struct ClipboardContext {
16 backend: Box<dyn ClipboardBackend>,
17 last_value: CString,
19}
20
21impl ClipboardContext {
22 pub fn new<T: ClipboardBackend>(backend: T) -> ClipboardContext {
24 ClipboardContext {
25 backend: Box::new(backend),
26 last_value: CString::default(),
27 }
28 }
29
30 pub fn dummy() -> ClipboardContext {
32 Self {
33 backend: Box::new(DummyClipboardBackend),
34 last_value: CString::default(),
35 }
36 }
37}
38
39pub struct DummyClipboardBackend;
41
42impl ClipboardBackend for DummyClipboardBackend {
43 fn get(&mut self) -> Option<String> {
44 None
45 }
46
47 fn set(&mut self, _: &str) {
48 }
50}
51
52pub(crate) unsafe extern "C" fn get_clipboard_text(
54 _user_data: *mut crate::sys::ImGuiContext,
55) -> *const c_char {
56 let result = std::panic::catch_unwind(|| {
57 let user_data = unsafe { (*crate::sys::igGetPlatformIO_Nil()).Platform_ClipboardUserData };
58
59 let ctx = unsafe { &mut *(user_data as *mut ClipboardContext) };
60 match ctx.backend.get() {
61 Some(text) => {
62 ctx.last_value = CString::new(text).unwrap();
63 ctx.last_value.as_ptr()
64 }
65 None => ptr::null(),
66 }
67 });
68 result.unwrap_or_else(|_| {
69 eprintln!("Clipboard getter panicked");
70 std::process::abort();
71 })
72}
73
74pub(crate) unsafe extern "C" fn set_clipboard_text(
75 _user_data: *mut crate::sys::ImGuiContext,
76 text: *const c_char,
77) {
78 let result = std::panic::catch_unwind(|| {
79 let user_data = unsafe { (*crate::sys::igGetPlatformIO_Nil()).Platform_ClipboardUserData };
80
81 let ctx = unsafe { &mut *(user_data as *mut ClipboardContext) };
82 let text = unsafe { CStr::from_ptr(text) }.to_owned();
83 ctx.backend.set(text.to_str().unwrap());
84 });
85 result.unwrap_or_else(|_| {
86 eprintln!("Clipboard setter panicked");
87 std::process::abort();
88 });
89}
90
91impl fmt::Debug for ClipboardContext {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.debug_struct("ClipboardContext")
94 .field("backend", &(&(*self.backend) as *const _))
95 .field("last_value", &self.last_value)
96 .finish()
97 }
98}