diff --git a/Cargo.toml b/Cargo.toml index 2d81063f48..cb942e42f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -178,6 +178,6 @@ web-time = "0.2" # Newer wgpu commit that fixes Vulkan backend on Nvidia wgpu = { git = "https://github.com/gfx-rs/wgpu", rev = "20fda69" } winapi = "0.3" -window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", branch = "mime-types" } -# window_clipboard = { path = "../window_clipboard" } +# window_clipboard = { git = "https://github.com/pop-os/window_clipboard.git", branch = "mime-types" } +window_clipboard = { path = "../window_clipboard" } winit = { git = "https://github.com/pop-os/winit.git", branch = "winit-0.29" } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 3a06eaa594..3186662182 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -25,3 +25,4 @@ sctk.optional = true thiserror.workspace = true iced_accessibility.workspace = true iced_accessibility.optional = true +window_clipboard.workspace = true \ No newline at end of file diff --git a/runtime/src/clipboard.rs b/runtime/src/clipboard.rs index bc45091266..66ad213331 100644 --- a/runtime/src/clipboard.rs +++ b/runtime/src/clipboard.rs @@ -1,4 +1,6 @@ //! Access the clipboard. +use window_clipboard::mime::{AllowedMimeTypes, AsMimeTypes}; + use crate::command::{self, Command}; use crate::futures::MaybeSend; @@ -13,6 +15,24 @@ pub enum Action { /// Write the given contents to the clipboard. Write(String), + + /// Write the given contents to the clipboard. + WriteData(Box), + + /// Read the clipboard and produce `T` with the result. + ReadData(Vec, Box, String)>) -> T>), + + /// Read the clipboard and produce `T` with the result. + ReadPrimary(Box) -> T>), + + /// Write the given contents to the clipboard. + WritePrimary(String), + + /// Write the given contents to the clipboard. + WritePrimaryData(Box), + + /// Read the clipboard and produce `T` with the result. + ReadPrimaryData(Vec, Box, String)>) -> T>), } impl Action { @@ -27,6 +47,20 @@ impl Action { match self { Self::Read(o) => Action::Read(Box::new(move |s| f(o(s)))), Self::Write(content) => Action::Write(content), + Self::WriteData(content) => Action::WriteData(content), + Self::ReadData(a, o) => { + Action::ReadData(a, Box::new(move |s| f(o(s)))) + } + Self::ReadPrimary(o) => { + Action::ReadPrimary(Box::new(move |s| f(o(s)))) + } + Self::WritePrimary(content) => Action::WritePrimary(content), + Self::WritePrimaryData(content) => { + Action::WritePrimaryData(content) + } + Self::ReadPrimaryData(a, o) => { + Action::ReadPrimaryData(a, Box::new(move |s| f(o(s)))) + } } } } @@ -36,6 +70,12 @@ impl fmt::Debug for Action { match self { Self::Read(_) => write!(f, "Action::Read"), Self::Write(_) => write!(f, "Action::Write"), + Self::WriteData(_) => write!(f, "Action::WriteData"), + Self::ReadData(_, _) => write!(f, "Action::ReadData"), + Self::ReadPrimary(_) => write!(f, "Action::ReadPrimary"), + Self::WritePrimary(_) => write!(f, "Action::WritePrimary"), + Self::WritePrimaryData(_) => write!(f, "Action::WritePrimaryData"), + Self::ReadPrimaryData(_, _) => write!(f, "Action::ReadPrimaryData"), } } } @@ -51,3 +91,44 @@ pub fn read( pub fn write(contents: String) -> Command { Command::single(command::Action::Clipboard(Action::Write(contents))) } + +/// Read the current contents of the clipboard. +pub fn read_data( + f: impl Fn(Option) -> Message + 'static, +) -> Command { + Command::single(command::Action::Clipboard(Action::ReadData( + T::allowed().into(), + Box::new(move |d| f(d.and_then(|d| T::try_from(d).ok()))), + ))) +} + +/// Write the given contents to the clipboard. +pub fn write_data( + contents: impl AsMimeTypes + std::marker::Sync + std::marker::Send + 'static, +) -> Command { + Command::single(command::Action::Clipboard(Action::WriteData(Box::new( + contents, + )))) +} + +/// Read the current contents of the clipboard. +pub fn read_primary_data< + T: AllowedMimeTypes + Send + Sync + 'static, + Message, +>( + f: impl Fn(Option) -> Message + 'static, +) -> Command { + Command::single(command::Action::Clipboard(Action::ReadPrimaryData( + T::allowed().into(), + Box::new(move |d| f(d.and_then(|d| T::try_from(d).ok()))), + ))) +} + +/// Write the given contents to the clipboard. +pub fn write_primary_data( + contents: impl AsMimeTypes + std::marker::Sync + std::marker::Send + 'static, +) -> Command { + Command::single(command::Action::Clipboard(Action::WritePrimaryData( + Box::new(contents), + ))) +} diff --git a/sctk/src/application.rs b/sctk/src/application.rs index 9f570a1cff..21a7901f73 100644 --- a/sctk/src/application.rs +++ b/sctk/src/application.rs @@ -73,6 +73,7 @@ use std::{ }; use wayland_backend::client::ObjectId; use wayland_protocols::wp::viewporter::client::wp_viewport::WpViewport; +use window_clipboard::mime::ClipboardStoreData; use crate::subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; @@ -2002,17 +2003,38 @@ where } command::Action::Clipboard(action) => match action { clipboard::Action::Read(s_to_msg) => { - if matches!(clipboard.state(), crate::clipboard::State::Connected(_)) { - let contents = clipboard.read(); - let message = s_to_msg(contents); - proxy.send_event(Event::Message(message)); - } + let contents = clipboard.read(); + let message = s_to_msg(contents); + proxy.send_event(Event::Message(message)); } clipboard::Action::Write(contents) => { - if matches!(clipboard.state(), crate::clipboard::State::Connected(_)) { - clipboard.write(contents) - } + clipboard.write(contents) } + clipboard::Action::WriteData(contents) => { + clipboard.write_data(ClipboardStoreData(contents)) + }, + clipboard::Action::ReadData(allowed, to_msg) => { + let contents = clipboard.read_data(allowed); + let message = to_msg(contents); + proxy.send_event(Event::Message(message)); + + }, + clipboard::Action::ReadPrimary(s_to_msg) => { + let contents = clipboard.read_primary(); + let message = s_to_msg(contents); + proxy.send_event(Event::Message(message)); + }, + clipboard::Action::WritePrimary(content) => { + clipboard.write_primary(content) + }, + clipboard::Action::WritePrimaryData(content) => { + clipboard.write_primary_data(ClipboardStoreData(content)) + }, + clipboard::Action::ReadPrimaryData(a, to_msg) => { + let contents = clipboard.read_primary_data(a); + let message = to_msg(contents); + proxy.send_event(Event::Message(message)); + }, }, command::Action::Window(..) => { unimplemented!("Use platform specific events instead") diff --git a/winit/src/application.rs b/winit/src/application.rs index aae6738372..afc0b2fe44 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -7,7 +7,9 @@ use iced_graphics::core::widget::operation::focusable::focus; use iced_graphics::core::widget::operation::OperationWrapper; use iced_graphics::core::widget::Operation; use iced_runtime::futures::futures::FutureExt; +use iced_style::core::Clipboard as CoreClipboard; pub use state::State; +use window_clipboard::mime::ClipboardStoreData; use crate::conversion; use crate::core; @@ -908,6 +910,30 @@ pub fn run_command( clipboard::Action::Write(contents) => { clipboard.write(contents); } + clipboard::Action::WriteData(contents) => { + clipboard.write_data(ClipboardStoreData(contents)) + } + clipboard::Action::ReadData(allowed, to_msg) => { + let contents = clipboard.read_data(allowed); + let message = to_msg(contents); + _ = proxy.send_event(UserEventWrapper::Message(message)); + } + clipboard::Action::ReadPrimary(s_to_msg) => { + let contents = clipboard.read_primary(); + let message = s_to_msg(contents); + _ = proxy.send_event(UserEventWrapper::Message(message)); + } + clipboard::Action::WritePrimary(content) => { + clipboard.write_primary(content) + } + clipboard::Action::WritePrimaryData(content) => { + clipboard.write_primary_data(ClipboardStoreData(content)) + } + clipboard::Action::ReadPrimaryData(a, to_msg) => { + let contents = clipboard.read_primary_data(a); + let message = to_msg(contents); + _ = proxy.send_event(UserEventWrapper::Message(message)); + } }, command::Action::Window(action) => match action { window::Action::Close(_id) => { diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs index 2ed427b8e2..14dafdfa59 100644 --- a/winit/src/multi_window.rs +++ b/winit/src/multi_window.rs @@ -26,9 +26,11 @@ use crate::runtime::user_interface::{self, UserInterface}; use crate::runtime::Debug; use crate::style::application::StyleSheet; use crate::{Clipboard, Error, Proxy, Settings}; +use core::Clipboard as CoreClipboard; use iced_runtime::futures::futures::FutureExt; use iced_style::Theme; pub use state::State; +use window_clipboard::mime::ClipboardStoreData; use std::collections::HashMap; use std::mem::ManuallyDrop; @@ -1142,6 +1144,30 @@ fn run_command( clipboard::Action::Write(contents) => { clipboard.write(contents); } + clipboard::Action::WriteData(contents) => { + clipboard.write_data(ClipboardStoreData(contents)) + } + clipboard::Action::ReadData(allowed, to_msg) => { + let contents = clipboard.read_data(allowed); + let message = to_msg(contents); + _ = proxy.send_event(UserEventWrapper::Message(message)); + } + clipboard::Action::ReadPrimary(s_to_msg) => { + let contents = clipboard.read_primary(); + let message = s_to_msg(contents); + _ = proxy.send_event(UserEventWrapper::Message(message)); + } + clipboard::Action::WritePrimary(content) => { + clipboard.write_primary(content) + } + clipboard::Action::WritePrimaryData(content) => { + clipboard.write_primary_data(ClipboardStoreData(content)) + } + clipboard::Action::ReadPrimaryData(a, to_msg) => { + let contents = clipboard.read_primary_data(a); + let message = to_msg(contents); + _ = proxy.send_event(UserEventWrapper::Message(message)); + } }, command::Action::Window(action) => match action { window::Action::Spawn(id, settings) => {