Skip to content

Commit

Permalink
cleanup(iced-sctk): add implementation for the iced clipboard actions
Browse files Browse the repository at this point in the history
  • Loading branch information
wash2 committed Oct 31, 2023
1 parent a9bddc5 commit 50fc7ef
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 9 deletions.
4 changes: 2 additions & 2 deletions runtime/src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::fmt;
/// [`Command`]: crate::Command
pub enum Action<T> {
/// Read the clipboard and produce `T` with the result.
Read(Box<dyn Fn(Option<String>) -> T>),
Read(Box<dyn Fn(Option<String>) -> T + Send>),

/// Write the given contents to the clipboard.
Write(String),
Expand Down Expand Up @@ -42,7 +42,7 @@ impl<T> fmt::Debug for Action<T> {

/// Read the current contents of the clipboard.
pub fn read<Message>(
f: impl Fn(Option<String>) -> Message + 'static,
f: impl Fn(Option<String>) -> Message + 'static + std::marker::Send,
) -> Command<Message> {
Command::single(command::Action::Clipboard(Action::Read(Box::new(f))))
}
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/command/platform_specific/wayland/data_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ pub trait DataFromMimeType {
fn from_mime_type(&self, mime_type: &str) -> Option<Vec<u8>>;
}

impl DataFromMimeType for String {
fn from_mime_type(&self, mime_type: &str) -> Option<Vec<u8>> {
if mime_type == "text/plain;charset=utf-8" {
Some(self.as_bytes().to_vec())
} else {
None
}
}
}

/// DataDevice Action
pub enum ActionInner {
/// Indicate that you are setting the selection and will respond to events
Expand Down
18 changes: 12 additions & 6 deletions sctk/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ use sctk::{
seat::{keyboard::Modifiers, pointer::PointerEventKind},
};
use std::{
collections::HashMap, ffi::c_void, hash::Hash, marker::PhantomData,
time::Duration,
collections::HashMap, hash::Hash, marker::PhantomData, time::Duration,
};
use wayland_backend::client::ObjectId;
use wayland_protocols::wp::viewporter::client::wp_viewport::WpViewport;
Expand Down Expand Up @@ -96,6 +95,13 @@ pub enum Event<Message> {
SetCursor(Interaction),
/// Application Message
Message(Message),
/// Miscellaneous messages
Misc(MiscEvent<Message>),
}

pub enum MiscEvent<T> {
IcedReadSelection(Box<dyn Fn(Option<String>) -> T + Send>),
IcedWriteSelection(String),
}

pub struct IcedSctkState;
Expand Down Expand Up @@ -1910,11 +1916,11 @@ where
})));
}
command::Action::Clipboard(action) => match action {
clipboard::Action::Read(..) => {
todo!();
clipboard::Action::Read(m) => {
proxy.send_event(Event::Misc(MiscEvent::IcedReadSelection(m)));
}
clipboard::Action::Write(..) => {
todo!();
clipboard::Action::Write(s) => {
proxy.send_event(Event::Misc(MiscEvent::IcedWriteSelection(s)));
}
},
command::Action::Window(..) => {
Expand Down
2 changes: 1 addition & 1 deletion sctk/src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl iced_runtime::core::clipboard::Clipboard for Clipboard {

/// Read the current contents of the clipboard.
pub fn read<Message>(
f: impl Fn(Option<String>) -> Message + 'static,
f: impl Fn(Option<String>) -> Message + 'static + std::marker::Send,
) -> Command<Message> {
Command::single(command::Action::Clipboard(Action::Read(Box::new(f))))
}
Expand Down
81 changes: 81 additions & 0 deletions sctk/src/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,87 @@ where
}
}
}
Event::Misc(a) => {
match a {
crate::application::MiscEvent::IcedReadSelection(to_msg) => {
if let Some(selection_offer) = self.state.selection_offer.as_mut() {
let mime_type = "text/plain;charset=UTF-8".to_string();
let read_pipe = match selection_offer.offer.receive(mime_type.clone()) {
Ok(p) => p,
Err(_) => continue, // TODO error handling
};
let loop_handle = self.event_loop.handle();
match self.event_loop.handle().insert_source(read_pipe, move |_, f, state| {
let selection_offer = match state.selection_offer.as_mut() {
Some(s) => s,
None => return,
};
let (mime_type, data, token) = match selection_offer.cur_read.take() {
Some(s) => s,
None => return,
};
let mut reader = BufReader::new(f.as_ref());
let consumed = match reader.fill_buf() {
Ok(buf) => {
if buf.is_empty() {
loop_handle.remove(token);
let data = String::from_utf8(data).ok();
state.pending_user_events.push(Event::Message(to_msg(data)));
} else {
let mut data = data;
data.extend_from_slice(buf);
selection_offer.cur_read = Some((mime_type, data, token));
}
buf.len()
},
Err(e) if matches!(e.kind(), std::io::ErrorKind::Interrupted) => {
selection_offer.cur_read = Some((mime_type, data, token));
return;
},
Err(e) => {
error!("Error reading selection data: {}", e);
loop_handle.remove(token);
return;
},
};
reader.consume(consumed);
}) {
Ok(token) => {
selection_offer.cur_read = Some((mime_type.clone(), Vec::new(), token));
},
Err(_) => continue,
};
}
},
crate::application::MiscEvent::IcedWriteSelection(data) => {
let mime_types = vec!["text/plain;charset=UTF-8"];
let qh = &self.state.queue_handle.clone();
let seat = match self.state.seats.get(0) {
Some(s) => s,
None => continue,
};
let serial = match seat.last_ptr_press {
Some(s) => s.2,
None => continue,
};
// remove the old selection
self.state.selection_source = None;
// create a new one
let source = self
.state
.data_device_manager_state
.create_copy_paste_source(qh, mime_types);
source.set_selection(&seat.data_device, serial);
self.state.selection_source = Some(SctkCopyPasteSource {
source,
cur_write: None,
accepted_mime_types: Vec::new(),
pipe: None,
data: Box::new(data),
});
},
}
},
}
}

Expand Down

0 comments on commit 50fc7ef

Please sign in to comment.