diff --git a/Cargo.toml b/Cargo.toml index 4d13334..d0fb561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,21 +11,9 @@ readme = "README.md" keywords = ["clipboard", "window", "ui", "gui", "raw-window-handle"] categories = ["gui"] -[features] -# Yoda: put the unix clipboard backends behind opt-in features. Upstream -# pulled both X11 + Wayland unconditionally on unix — pure bloat for -# Wayland-only builds (clipboard_x11 pulls x11rb + its protocol machinery). -# Default keeps both enabled to preserve upstream behaviour; yoda consumers -# pass default-features=false + "wayland" at the dep declaration. -default = ["x11", "wayland"] -x11 = ["dep:clipboard_x11"] -wayland = ["dep:clipboard_wayland"] - [dependencies] raw-window-handle = { version = "0.6", features = ["std"] } thiserror = "1.0" -mime = { path = "./mime" } -dnd = { path = "./dnd" } [target.'cfg(windows)'.dependencies] clipboard-win = { version = "5.0", features = ["std"] } @@ -34,12 +22,16 @@ clipboard-win = { version = "5.0", features = ["std"] } clipboard_macos = { version = "0.1", path = "./macos" } [target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten", target_os="ios", target_os="redox"))))'.dependencies] -clipboard_x11 = { version = "0.4.2", path = "./x11", optional = true } -clipboard_wayland = { version = "0.2.2", path = "./wayland", optional = true } +clipboard_x11 = { version = "0.4.2", path = "./x11" } +clipboard_wayland = { version = "0.2.2", path = "./wayland" } [dev-dependencies] rand = "0.8" winit = "0.29" [workspace] -members = ["dnd", "macos", "mime", "dnd", "wayland", "x11"] +members = [ + "macos", + "wayland", + "x11", +] diff --git a/dnd/Cargo.toml b/dnd/Cargo.toml deleted file mode 100644 index 868bceb..0000000 --- a/dnd/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "dnd" -version = "0.1.0" -edition = "2021" - -[dependencies] -mime = { path = "../mime" } -bitflags = "2.5.0" -raw-window-handle = "0.6" - -[target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten", target_os="ios", target_os="redox"))))'.dependencies] -smithay-clipboard = { path = "../../smithay-clipboard", features = [ - "dnd", -] } -sctk = { package = "smithay-client-toolkit", version = "0.20", default-features = false, features = [ - "calloop", -] } diff --git a/dnd/src/lib.rs b/dnd/src/lib.rs deleted file mode 100644 index 66ccd8c..0000000 --- a/dnd/src/lib.rs +++ /dev/null @@ -1,201 +0,0 @@ -use std::{ - borrow::Cow, - fmt::Debug, - sync::{mpsc::SendError, Arc}, -}; - -use bitflags::bitflags; -use raw_window_handle::HasWindowHandle; - -#[cfg(all( - unix, - not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "emscripten", - target_os = "redox" - )) -))] -#[path = "platform/linux.rs"] -pub mod platform; - -bitflags! { - // Attributes can be applied to flags types - #[repr(transparent)] - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct DndAction: u32 { - const Copy = 0b00000001; - const Move = 0b00000010; - const Ask = 0b00000100; - } -} - -#[derive(Debug, Clone)] -pub enum DndEvent { - /// Dnd Offer event with the corresponding destination rectangle ID. - Offer(Option, OfferEvent), - /// Dnd Source event. - Source(SourceEvent), -} - -impl PartialEq for DndEvent { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (DndEvent::Offer(a, b), DndEvent::Offer(a2, b2)) => { - a == a2 && b == b2 - } - (DndEvent::Source(a), DndEvent::Source(b)) => a == b, - _ => false, - } - } -} - -#[derive(Debug, Clone)] -pub enum SourceEvent { - /// DnD operation ended. - Finished, - /// DnD Cancelled. - Cancelled, - /// DnD action chosen by the compositor. - Action(DndAction), - /// Mime accepted by destination. - /// If [`None`], no mime types are accepted. - Mime(Option), - /// DnD Dropped. The operation is still ongoing until receiving a - /// [`SourceEvent::Finished`] event. - Dropped, -} - -impl PartialEq for SourceEvent { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (SourceEvent::Finished, SourceEvent::Finished) - | (SourceEvent::Cancelled, SourceEvent::Cancelled) - | (SourceEvent::Dropped, SourceEvent::Dropped) => true, - (SourceEvent::Action(a), SourceEvent::Action(b)) => a == b, - (SourceEvent::Mime(a), SourceEvent::Mime(b)) => a == b, - _ => false, - } - } -} - -#[derive(Debug, Clone)] -pub enum OfferEvent { - Enter { - x: f64, - y: f64, - mime_types: Vec, - surface: T, - }, - Motion { - x: f64, - y: f64, - }, - /// The offer is no longer on a DnD destination. - LeaveDestination, - /// The offer has left the surface. - Leave, - /// An offer was dropped - Drop, - /// If the selected action is ASK, the user must be presented with a - /// choice. [`Clipboard::set_action`] should then be called before data - /// can be requested and th DnD operation can be finished. - SelectedAction(DndAction), - Data { - data: Vec, - mime_type: String, - }, -} - -impl PartialEq for OfferEvent { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - ( - OfferEvent::Enter { - x, - y, - mime_types, - surface: _, - }, - OfferEvent::Enter { - x: x2, - y: y2, - mime_types: mime_types2, - surface: _, - }, - ) => x == x2 && y == y2 && mime_types == mime_types2, - ( - OfferEvent::Motion { x, y }, - OfferEvent::Motion { x: x2, y: y2 }, - ) => x == x2 && y == y2, - (OfferEvent::LeaveDestination, OfferEvent::LeaveDestination) - | (OfferEvent::Leave, OfferEvent::Leave) - | (OfferEvent::Drop, OfferEvent::Drop) => true, - (OfferEvent::SelectedAction(a), OfferEvent::SelectedAction(b)) => { - a == b - } - ( - OfferEvent::Data { data, mime_type }, - OfferEvent::Data { - data: data2, - mime_type: mime_type2, - }, - ) => data == data2 && mime_type == mime_type2, - _ => false, - } - } -} - -/// A rectangle with a logical location and size relative to a [`DndSurface`] -#[derive(Debug, Default, Clone)] -pub struct Rectangle { - pub x: f64, - pub y: f64, - pub width: f64, - pub height: f64, -} - -pub trait Sender { - /// Send an event in the channel - fn send(&self, t: DndEvent) -> Result<(), SendError>>; -} - -/// A rectangle with a logical location and size relative to a [`DndSurface`] -#[derive(Debug, Clone)] -pub struct DndDestinationRectangle { - /// A unique ID - pub id: u128, - /// The rectangle representing this destination. - pub rectangle: Rectangle, - /// Accepted mime types in this rectangle - pub mime_types: Vec>, - /// Accepted actions in this rectangle - pub actions: DndAction, - /// Prefered action in this rectangle - pub preferred: DndAction, -} - -#[derive(Clone)] -pub enum Icon { - Surface(DndSurface), - /// Xrgb8888 or Argb8888 image data with premultiplied alpha - Buffer { - data: Arc>, - width: u32, - height: u32, - transparent: bool, - }, -} - -#[derive(Clone)] -pub struct DndSurface(pub Arc); - -impl Debug for DndSurface { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("DndSurface").finish() - } -} - -#[derive(Clone)] -pub struct DataWrapper(pub T); diff --git a/dnd/src/platform/linux.rs b/dnd/src/platform/linux.rs deleted file mode 100644 index 31a1879..0000000 --- a/dnd/src/platform/linux.rs +++ /dev/null @@ -1,110 +0,0 @@ -use std::{borrow::Cow, ffi::c_void, sync::Arc}; - -use crate::{DataWrapper, DndAction, DndSurface, Icon}; -use raw_window_handle::HasWindowHandle; -use smithay_clipboard::mime::{AllowedMimeTypes, AsMimeTypes, MimeType}; - -impl< - T: mime::AllowedMimeTypes - + std::convert::TryFrom<(std::vec::Vec, String)>, - > AllowedMimeTypes for DataWrapper -{ - fn allowed() -> Cow<'static, [MimeType]> { - T::allowed() - .into_iter() - .map(|s| MimeType::from(Cow::Owned(s.to_string()))) - .collect() - } -} - -impl, String)>> TryFrom<(Vec, MimeType)> - for DataWrapper -{ - type Error = T::Error; - - fn try_from( - (data, mime): (Vec, MimeType), - ) -> Result { - T::try_from((data, mime.to_string())).map(|d| DataWrapper(d)) - } -} - -impl AsMimeTypes for DataWrapper { - fn available(&self) -> Cow<'static, [MimeType]> { - self.0 - .available() - .into_iter() - .map(|m| MimeType::from(Cow::Owned(m.to_string()))) - .collect() - } - - fn as_bytes(&self, mime_type: &MimeType) -> Option> { - self.0.as_bytes(mime_type.as_ref()) - } -} - -impl smithay_clipboard::dnd::RawSurface for DndSurface { - unsafe fn get_ptr(&mut self) -> *mut c_void { - self.0.window_handle().unwrap().get_ptr() - } -} - -impl From - for DndAction -{ - fn from( - action: sctk::reexports::client::protocol::wl_data_device_manager::DndAction, - ) -> Self { - let mut a = DndAction::empty(); - if action.contains(sctk::reexports::client::protocol::wl_data_device_manager::DndAction::Copy) { - a |= DndAction::Copy; - } - if action.contains(sctk::reexports::client::protocol::wl_data_device_manager::DndAction::Move) { - a |= DndAction::Move; - } - if action.contains(sctk::reexports::client::protocol::wl_data_device_manager::DndAction::Ask) { - a |= DndAction::Ask; - } - a - } -} - -impl From - for sctk::reexports::client::protocol::wl_data_device_manager::DndAction -{ - fn from(action: DndAction) -> Self { - let mut a = sctk::reexports::client::protocol::wl_data_device_manager::DndAction::empty(); - if action.contains(DndAction::Copy) { - a |= sctk::reexports::client::protocol::wl_data_device_manager::DndAction::Copy; - } - if action.contains(DndAction::Move) { - a |= sctk::reexports::client::protocol::wl_data_device_manager::DndAction::Move; - } - if action.contains(DndAction::Ask) { - a |= sctk::reexports::client::protocol::wl_data_device_manager::DndAction::Ask; - } - a - } -} - -impl From for smithay_clipboard::dnd::Icon { - fn from(icon: Icon) -> Self { - match icon { - Icon::Surface(surface) => { - smithay_clipboard::dnd::Icon::Surface(surface) - } - Icon::Buffer { - data, - width, - height, - transparent, - } => smithay_clipboard::dnd::Icon::Buf { - data: Arc::try_unwrap(data) - .unwrap_or_else(|d| d.as_ref().clone()), - width, - height, - transparent, - }, - } - } -} diff --git a/dnd/src/platform/mod.rs b/dnd/src/platform/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/examples/big_file.rs b/examples/big_file.rs index 8be0fa2..f666812 100644 --- a/examples/big_file.rs +++ b/examples/big_file.rs @@ -1,5 +1,5 @@ use rand::distributions::{Alphanumeric, Distribution}; -use window_clipboard::PlatformClipboard; +use window_clipboard::Clipboard; use winit::{ error::EventLoopError, event::{ElementState, Event, KeyEvent, WindowEvent}, @@ -24,8 +24,8 @@ fn main() -> Result<(), EventLoopError> { .build(&event_loop) .unwrap(); - let mut clipboard = unsafe { PlatformClipboard::connect(&window) } - .expect("Connect to clipboard"); + let mut clipboard = + unsafe { Clipboard::connect(&window) }.expect("Connect to clipboard"); clipboard.write(data.clone()).unwrap(); diff --git a/examples/read.rs b/examples/read.rs index 8407133..ddbaf8b 100644 --- a/examples/read.rs +++ b/examples/read.rs @@ -1,4 +1,4 @@ -use window_clipboard::PlatformClipboard; +use window_clipboard::Clipboard; use winit::{ error::EventLoopError, event::{Event, WindowEvent}, @@ -14,8 +14,8 @@ fn main() -> Result<(), EventLoopError> { .build(&event_loop) .unwrap(); - let clipboard = unsafe { PlatformClipboard::connect(&window) } - .expect("Connect to clipboard"); + let clipboard = + unsafe { Clipboard::connect(&window) }.expect("Connect to clipboard"); event_loop.run(move |event, elwt| match event { Event::AboutToWait => { diff --git a/examples/write.rs b/examples/write.rs index 49dc505..40e6263 100644 --- a/examples/write.rs +++ b/examples/write.rs @@ -1,4 +1,4 @@ -use window_clipboard::PlatformClipboard; +use window_clipboard::Clipboard; use winit::{ error::EventLoopError, event::{Event, WindowEvent}, @@ -14,8 +14,8 @@ fn main() -> Result<(), EventLoopError> { .build(&event_loop) .unwrap(); - let mut clipboard = unsafe { PlatformClipboard::connect(&window) } - .expect("Connect to clipboard"); + let mut clipboard = + unsafe { Clipboard::connect(&window) }.expect("Connect to clipboard"); clipboard .write(String::from("Hello, world!")) diff --git a/macos/src/lib.rs b/macos/src/lib.rs index deeb52f..ca9047e 100644 --- a/macos/src/lib.rs +++ b/macos/src/lib.rs @@ -15,11 +15,11 @@ extern crate objc; use objc::runtime::{Class, Object}; -use objc_foundation::{ - INSArray, INSObject, INSString, NSArray, NSDictionary, NSObject, NSString, -}; +use objc_foundation::{INSArray, INSObject, INSString}; +use objc_foundation::{NSArray, NSDictionary, NSObject, NSString}; use objc_id::{Id, Owned}; -use std::{error::Error, mem::transmute}; +use std::error::Error; +use std::mem::transmute; pub struct Clipboard { pasteboard: Id, diff --git a/mime/Cargo.toml b/mime/Cargo.toml deleted file mode 100644 index 259b4f0..0000000 --- a/mime/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "mime" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="emscripten", target_os="ios", target_os="redox"))))'.dependencies] -smithay-clipboard = { path = "../../smithay-clipboard" } diff --git a/mime/src/lib.rs b/mime/src/lib.rs deleted file mode 100644 index 983827d..0000000 --- a/mime/src/lib.rs +++ /dev/null @@ -1,69 +0,0 @@ -pub mod platform; - -// need a type that can implement traits for storing custom data - -use std::{borrow::Cow, error, fmt}; - -/// Raw data from the clipboard -pub struct ClipboardData(pub Vec, pub String); - -impl AllowedMimeTypes for ClipboardData { - fn allowed() -> Cow<'static, [String]> { - Cow::Owned(vec![]) - } -} - -impl TryFrom<(Vec, String)> for ClipboardData { - type Error = Error; - - fn try_from((data, mime): (Vec, String)) -> Result { - Ok(ClipboardData(data, mime)) - } -} - -/// Data that can be loaded from the clipboard. -pub struct ClipboardLoadData(pub T); - -/// Describes the mime types which are accepted. -pub trait AllowedMimeTypes: - TryFrom<(Vec, String)> + Send + Sync + 'static -{ - /// List allowed mime types for the type to convert from a byte slice. - /// - /// Allowed mime types should be listed in order of decreasing preference, - /// most preferred first. - fn allowed() -> Cow<'static, [String]>; -} - -/// Can be converted to data with the available mime types. -pub trait AsMimeTypes { - /// List available mime types for this data to convert to a byte slice. - fn available(&self) -> Cow<'static, [String]>; - - /// Converts a type to a byte slice for the given mime type if possible. - fn as_bytes(&self, mime_type: &str) -> Option>; -} - -impl AsMimeTypes for Box { - fn available(&self) -> Cow<'static, [String]> { - self.as_ref().available() - } - - fn as_bytes(&self, mime_type: &str) -> Option> { - self.as_ref().as_bytes(mime_type) - } -} - -/// Data that can be stored to the clipboard. -pub struct ClipboardStoreData(pub T); - -#[derive(Debug, Clone, Copy)] -pub struct Error; - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Unsupported mime type") - } -} - -impl error::Error for Error {} diff --git a/mime/src/platform/linux.rs b/mime/src/platform/linux.rs deleted file mode 100644 index 1da9698..0000000 --- a/mime/src/platform/linux.rs +++ /dev/null @@ -1,47 +0,0 @@ -use smithay_clipboard::mime::{AllowedMimeTypes, AsMimeTypes, MimeType}; - -use crate::{ClipboardLoadData, ClipboardStoreData}; - -impl AsMimeTypes for ClipboardStoreData { - fn available(&self) -> std::borrow::Cow<'static, [MimeType]> { - self.0 - .available() - .into_iter() - .map(|m| MimeType::Other(m.clone().into())) - .collect() - } - - fn as_bytes( - &self, - mime_type: &MimeType, - ) -> Option> { - self.0.as_bytes(mime_type.as_ref()) - } -} - -impl AllowedMimeTypes for ClipboardLoadData { - // TODO select text variants if string matches... - fn allowed() -> std::borrow::Cow<'static, [MimeType]> { - T::allowed() - .into_iter() - .map(|s| MimeType::Other(s.clone().into())) - .collect() - } -} - -impl TryFrom<(Vec, MimeType)> for ClipboardLoadData -where - T: for<'b> TryFrom<(Vec, String)>, - T: 'static, -{ - type Error = crate::Error; - - fn try_from( - (value, mime): (Vec, MimeType), - ) -> Result { - let mime = mime.to_string(); - Ok(ClipboardLoadData( - T::try_from((value, mime)).map_err(|_| crate::Error)?, - )) - } -} diff --git a/mime/src/platform/mod.rs b/mime/src/platform/mod.rs deleted file mode 100644 index 10c3ec9..0000000 --- a/mime/src/platform/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(all( - unix, - not(any( - target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "emscripten", - target_os = "redox" - )) -))] -pub mod linux; diff --git a/src/dnd/mod.rs b/src/dnd/mod.rs deleted file mode 100644 index b145ca0..0000000 --- a/src/dnd/mod.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::borrow::Cow; - -use ::dnd::{DndAction, DndDestinationRectangle, Sender}; -use dnd::{DndSurface, Icon}; -use mime::{AllowedMimeTypes, AsMimeTypes}; - -pub trait DndProvider { - /// Set up DnD operations for the Clipboard - fn init_dnd( - &self, - _tx: Box + Send + Sync + 'static>, - ) { - } - - /// Start a DnD operation on the given surface with some data - fn start_dnd( - &self, - _internal: bool, - _source_surface: DndSurface, - _icon_surface: Option, - _content: D, - _actions: DndAction, - ) { - } - - /// End the current DnD operation, if there is one - fn end_dnd(&self) {} - - /// Register a surface for receiving DnD offers - /// Rectangles should be provided in order of decreasing priority. - /// This method can be called multiple time for a single surface if the - /// rectangles change. - fn register_dnd_destination( - &self, - _surface: DndSurface, - _rectangles: Vec, - ) { - } - - /// Set the final action after presenting the user with a choice - fn set_action(&self, _action: DndAction) {} - - /// Peek at the contents of a DnD offer - fn peek_offer( - &self, - _mime_type: Option>, - ) -> std::io::Result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "DnD not supported", - )) - } -} - -impl DndProvider for crate::PlatformClipboard { - fn init_dnd( - &self, - tx: Box + Send + Sync + 'static>, - ) { - self.raw.init_dnd(tx); - } - - fn start_dnd( - &self, - internal: bool, - source_surface: DndSurface, - icon_surface: Option, - content: D, - actions: DndAction, - ) { - self.raw.start_dnd( - internal, - source_surface, - icon_surface, - content, - actions, - ); - } - - fn end_dnd(&self) { - self.raw.end_dnd(); - } - - fn register_dnd_destination( - &self, - surface: DndSurface, - rectangles: Vec, - ) { - self.raw.register_dnd_destination(surface, rectangles); - } - - fn set_action(&self, action: DndAction) { - self.raw.set_action(action); - } - - fn peek_offer( - &self, - mime_type: Option>, - ) -> std::io::Result { - self.raw.peek_offer::(mime_type) - } -} diff --git a/src/lib.rs b/src/lib.rs index 54d330f..a9857e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -pub use mime; - #[cfg(all( unix, not(any( @@ -48,26 +46,21 @@ mod platform; #[path = "platform/dummy.rs"] mod platform; -pub mod dnd; - -use mime::ClipboardStoreData; use raw_window_handle::HasDisplayHandle; use std::error::Error; -pub type Clipboard = PlatformClipboard; - -pub struct PlatformClipboard { - raw: C, +pub struct Clipboard { + raw: Box, } -impl PlatformClipboard { +impl Clipboard { /// Safety: the display handle must be valid for the lifetime of `Clipboard` - pub unsafe fn connect( + pub unsafe fn connect( window: &W, ) -> Result> { - Ok(PlatformClipboard { - raw: platform::connect(window)?, - }) + let raw = platform::connect(window)?; + + Ok(Clipboard { raw }) } pub fn read(&self) -> Result> { @@ -79,67 +72,14 @@ impl PlatformClipboard { } } -impl PlatformClipboard { +impl Clipboard { pub fn read_primary(&self) -> Option>> { self.raw.read_primary() } - pub fn write_primary( - &mut self, - contents: String, - ) -> Option>> { + pub fn write_primary(&mut self, contents: String) -> Option>> { self.raw.write_primary(contents) } - - pub fn read_data(&self) -> Option>> - where - T: mime::AllowedMimeTypes, - { - self.raw.read_data() - } - - pub fn write_data( - &mut self, - contents: ClipboardStoreData, - ) -> Option>> - where - T: mime::AsMimeTypes, - { - self.raw.write_data(contents) - } - - pub fn read_primary_data( - &self, - ) -> Option>> - where - T: mime::AllowedMimeTypes, - { - self.raw.read_primary_data() - } - - pub fn read_primary_raw( - &self, - allowed: Vec, - ) -> Option, String), Box>> { - self.raw.read_primary_raw(allowed) - } - - pub fn read_raw( - &self, - allowed: Vec, - ) -> Option, String), Box>> { - self.raw.read_raw(allowed) - } - - pub fn write_primary_data( - &mut self, - contents: ClipboardStoreData, - ) -> Option>> - where - T: mime::AsMimeTypes, - { - self.raw.write_primary_data(contents) - } } pub trait ClipboardProvider { @@ -151,58 +91,7 @@ pub trait ClipboardProvider { None } - fn write_primary( - &mut self, - _contents: String, - ) -> Option>> { - None - } - - fn read_data(&self) -> Option>> - where - T: mime::AllowedMimeTypes, - { - None - } - - fn write_data( - &mut self, - _contents: ClipboardStoreData, - ) -> Option>> - where - T: mime::AsMimeTypes, - { - None - } - - fn read_primary_data(&self) -> Option>> - where - T: mime::AllowedMimeTypes, - { - None - } - - fn read_primary_raw( - &self, - _allowed: Vec, - ) -> Option, String), Box>> { - None - } - - fn read_raw( - &self, - _allowed: Vec, - ) -> Option, String), Box>> { - None - } - - fn write_primary_data( - &mut self, - _contents: ClipboardStoreData, - ) -> Option>> - where - T: mime::AsMimeTypes, - { + fn write_primary(&mut self, _contents: String) -> Option>> { None } } diff --git a/src/platform/android.rs b/src/platform/android.rs index 885f80d..b0ac8b6 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -1,15 +1,12 @@ use crate::ClipboardProvider; -use crate::dnd::DndProvider; -use dnd::{DndAction, DndDestinationRectangle, DndSurface, Icon}; -use mime::{AllowedMimeTypes, AsMimeTypes}; use raw_window_handle::HasDisplayHandle; -use std::{borrow::Cow, error::Error}; +use std::error::Error; pub fn connect( _window: &W, -) -> Result> { - Clipboard::new() +) -> Result, Box> { + Ok(Box::new(Clipboard::new()?)) } pub struct Clipboard; @@ -39,46 +36,7 @@ impl ClipboardProvider for Clipboard { Err(Box::new(AndroidClipboardError::Unimplemented)) } - fn write(&mut self, _contents: String) -> Result<(), Box> { + fn write(&mut self, contents: String) -> Result<(), Box> { Err(Box::new(AndroidClipboardError::Unimplemented)) } } - -impl DndProvider for Clipboard { - fn init_dnd( - &self, - _tx: Box + Send + Sync + 'static>, - ) { - } - - fn start_dnd( - &self, - _internal: bool, - _source_surface: DndSurface, - _icon_surface: Option, - _content: D, - _actions: DndAction, - ) { - } - - fn end_dnd(&self) {} - - fn register_dnd_destination( - &self, - _surface: DndSurface, - _rectangles: Vec, - ) { - } - - fn set_action(&self, _action: DndAction) {} - - fn peek_offer( - &self, - _mime_type: Option>, - ) -> std::io::Result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "DnD not supported", - )) - } -} diff --git a/src/platform/dummy.rs b/src/platform/dummy.rs index c86bcbf..8cf7418 100644 --- a/src/platform/dummy.rs +++ b/src/platform/dummy.rs @@ -1,19 +1,16 @@ -use crate::{dnd::DndProvider, ClipboardProvider}; +use crate::ClipboardProvider; -use dnd::{DndAction, DndDestinationRectangle, DndSurface, Icon}; -use mime::{AllowedMimeTypes, AsMimeTypes}; use raw_window_handle::HasDisplayHandle; -use std::borrow::Cow; -pub struct Clipboard; +struct Dummy; -pub fn connect( +pub fn connect( _window: &W, -) -> Result> { - Ok(Clipboard) +) -> Result, Box> { + Ok(Box::new(Dummy)) } -impl ClipboardProvider for Clipboard { +impl ClipboardProvider for Dummy { fn read(&self) -> Result> { Err(Box::new(Error::Unimplemented)) } @@ -26,45 +23,6 @@ impl ClipboardProvider for Clipboard { } } -impl DndProvider for Clipboard { - fn init_dnd( - &self, - _tx: Box + Send + Sync + 'static>, - ) { - } - - fn start_dnd( - &self, - _internal: bool, - _source_surface: DndSurface, - _icon_surface: Option, - _content: D, - _actions: DndAction, - ) { - } - - fn end_dnd(&self) {} - - fn register_dnd_destination( - &self, - _surface: DndSurface, - _rectangles: Vec, - ) { - } - - fn set_action(&self, _action: DndAction) {} - - fn peek_offer( - &self, - _mime_type: Option>, - ) -> std::io::Result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "DnD not supported", - )) - } -} - #[derive(Debug, Clone, Copy, thiserror::Error)] enum Error { #[error("unimplemented")] diff --git a/src/platform/ios.rs b/src/platform/ios.rs index fd961c7..84ae06a 100644 --- a/src/platform/ios.rs +++ b/src/platform/ios.rs @@ -3,10 +3,10 @@ use crate::ClipboardProvider; use raw_window_handle::HasDisplayHandle; use std::error::Error; -pub fn connect( +pub fn connect( _window: &W, -) -> Result> { - Clipboard::new() +) -> Result, Box> { + Ok(Box::new(Clipboard::new()?)) } pub struct Clipboard; diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 755dfb9..12d8c67 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -1,241 +1,56 @@ -use crate::{ - dnd::DndProvider, - mime::{ClipboardLoadData, ClipboardStoreData}, - ClipboardProvider, -}; +use crate::ClipboardProvider; -use dnd::{DndAction, DndDestinationRectangle, DndSurface, Icon}; -use mime::{AllowedMimeTypes, AsMimeTypes}; use raw_window_handle::{HasDisplayHandle, RawDisplayHandle}; -use std::{borrow::Cow, error::Error, sync::Arc}; -use wayland::DndSender; +use std::error::Error; pub use clipboard_wayland as wayland; -#[cfg(feature = "x11")] pub use clipboard_x11 as x11; -pub enum Clipboard { - Wayland(wayland::Clipboard), - #[cfg(feature = "x11")] - X11(x11::Clipboard), -} - -impl ClipboardProvider for Clipboard { - fn read(&self) -> Result> { - match self { - Clipboard::Wayland(c) => c.read(), - #[cfg(feature = "x11")] - Clipboard::X11(c) => c.read().map_err(Box::from), - } - } - - fn write(&mut self, contents: String) -> Result<(), Box> { - match self { - Clipboard::Wayland(c) => c.write(contents), - #[cfg(feature = "x11")] - Clipboard::X11(c) => c.write(contents).map_err(Box::from), - } - } - - fn read_primary(&self) -> Option>> { - match self { - Clipboard::Wayland(c) => Some(c.read_primary()), - #[cfg(feature = "x11")] - Clipboard::X11(c) => Some(c.read_primary().map_err(Box::from)), - } - } - - fn write_primary( - &mut self, - contents: String, - ) -> Option>> { - match self { - Clipboard::Wayland(c) => Some(c.write_primary(contents)), - #[cfg(feature = "x11")] - Clipboard::X11(c) => { - Some(c.write_primary(contents).map_err(Box::from)) - } - } - } - - fn read_data(&self) -> Option>> - where - T: mime::AllowedMimeTypes, - { - match self { - Clipboard::Wayland(c) => { - let ret = c.read_data::>(); - Some(ret.map(|ret| ret.0)) - } - #[cfg(feature = "x11")] - Clipboard::X11(_) => None, - } - } - - fn write_data( - &mut self, - contents: ClipboardStoreData, - ) -> Option>> - where - T: mime::AsMimeTypes, - { - match self { - Clipboard::Wayland(c) => { - Some(c.write_data::>(contents)) - } - #[cfg(feature = "x11")] - Clipboard::X11(_) => None, - } - } - - fn read_primary_data(&self) -> Option>> - where - T: mime::AllowedMimeTypes, - { - match self { - Clipboard::Wayland(c) => { - let ret = c.read_primary_data::>(); - Some(ret.map(|ret| ret.0)) - } - #[cfg(feature = "x11")] - Clipboard::X11(_) => None, - } - } - - fn read_primary_raw( - &self, - allowed: Vec, - ) -> Option, String), Box>> { - match self { - Clipboard::Wayland(c) => Some(c.read_primary_raw(allowed)), - #[cfg(feature = "x11")] - Clipboard::X11(_) => None, - } - } - - fn read_raw( - &self, - allowed: Vec, - ) -> Option, String), Box>> { - match self { - Clipboard::Wayland(c) => Some(c.read_raw(allowed)), - #[cfg(feature = "x11")] - Clipboard::X11(_) => None, - } - } - - fn write_primary_data( - &mut self, - contents: ClipboardStoreData, - ) -> Option>> - where - T: mime::AsMimeTypes, - { - match self { - Clipboard::Wayland(c) => { - Some(c.write_primary_data::>(contents)) - } - #[cfg(feature = "x11")] - Clipboard::X11(_) => None, - } - } -} - -impl DndProvider for Clipboard { - fn init_dnd( - &self, - tx: Box + Send + Sync + 'static>, - ) { - match self { - Clipboard::Wayland(c) => c.init_dnd(DndSender(Arc::from(tx))), - #[cfg(feature = "x11")] - Clipboard::X11(_) => {} - } - } - - fn start_dnd( - &self, - internal: bool, - source_surface: DndSurface, - icon_surface: Option, - content: D, - actions: DndAction, - ) { - match self { - Clipboard::Wayland(c) => c.start_dnd( - internal, - source_surface, - icon_surface, - content, - actions, - ), - #[cfg(feature = "x11")] - Clipboard::X11(_) => {} - } - } - - fn end_dnd(&self) { - match self { - Clipboard::Wayland(c) => c.end_dnd(), - #[cfg(feature = "x11")] - Clipboard::X11(_) => {} - } - } - - fn register_dnd_destination( - &self, - surface: DndSurface, - rectangles: Vec, - ) { - match self { - Clipboard::Wayland(c) => { - c.register_dnd_destination(surface, rectangles) - } - #[cfg(feature = "x11")] - Clipboard::X11(_) => {} - } - } - - fn set_action(&self, action: DndAction) { - match self { - Clipboard::Wayland(c) => c.set_action(action), - #[cfg(feature = "x11")] - Clipboard::X11(_) => {} - } - } - - fn peek_offer( - &self, - mime_type: Option>, - ) -> std::io::Result { - match self { - Clipboard::Wayland(c) => c.peek_offer::(mime_type), - #[cfg(feature = "x11")] - Clipboard::X11(_) => Err(std::io::Error::new( - std::io::ErrorKind::Other, - "DnD not supported", - )), - } - } -} - -pub unsafe fn connect( +pub unsafe fn connect( window: &W, -) -> Result> { +) -> Result, Box> { let clipboard = match window.display_handle()?.as_raw() { - RawDisplayHandle::Wayland(handle) => Clipboard::Wayland( - wayland::Clipboard::connect(handle.display.as_ptr()), - ) as _, - #[cfg(feature = "x11")] - _ => Clipboard::X11(x11::Clipboard::connect()?) as _, - #[cfg(not(feature = "x11"))] - _ => { - return Err(Box::from( - "Yoda window_clipboard: X11 feature disabled; \ - non-Wayland display handles are not supported", - )) + RawDisplayHandle::Wayland(handle) => { + Box::new(wayland::Clipboard::connect(handle.display.as_ptr())) as _ } + _ => Box::new(x11::Clipboard::connect()?) as _, }; Ok(clipboard) } + +impl ClipboardProvider for wayland::Clipboard { + fn read(&self) -> Result> { + self.read() + } + + fn read_primary(&self) -> Option>> { + Some(self.read_primary()) + } + + fn write(&mut self, contents: String) -> Result<(), Box> { + self.write(contents) + } + + fn write_primary(&mut self, contents: String) -> Option>> { + Some(self.write_primary(contents)) + } +} + +impl ClipboardProvider for x11::Clipboard { + fn read(&self) -> Result> { + self.read().map_err(Box::from) + } + + fn read_primary(&self) -> Option>> { + Some(self.read_primary().map_err(Box::from)) + } + + fn write(&mut self, contents: String) -> Result<(), Box> { + self.write(contents).map_err(Box::from) + } + + fn write_primary(&mut self, contents: String) -> Option>> { + Some(self.write_primary(contents).map_err(Box::from)) + } +} diff --git a/src/platform/macos.rs b/src/platform/macos.rs index d89c446..5b399e0 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -1,58 +1,15 @@ use crate::ClipboardProvider; -use crate::dnd::DndProvider; -pub(crate) use clipboard_macos::Clipboard; -use dnd::{DndAction, DndDestinationRectangle, DndSurface, Icon}; -use mime::{AllowedMimeTypes, AsMimeTypes}; use raw_window_handle::HasDisplayHandle; -use std::{borrow::Cow, error::Error}; +use std::error::Error; -pub fn connect( +pub fn connect( _window: &W, -) -> Result> { - Clipboard::new() +) -> Result, Box> { + Ok(Box::new(clipboard_macos::Clipboard::new()?)) } -impl DndProvider for Clipboard { - fn init_dnd( - &self, - _tx: Box + Send + Sync + 'static>, - ) { - } - - fn start_dnd( - &self, - _internal: bool, - _source_surface: DndSurface, - _icon_surface: Option, - _content: D, - _actions: DndAction, - ) { - } - - fn end_dnd(&self) {} - - fn register_dnd_destination( - &self, - _surface: DndSurface, - _rectangles: Vec, - ) { - } - - fn set_action(&self, _action: DndAction) {} - - fn peek_offer( - &self, - _mime_type: Option>, - ) -> std::io::Result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "DnD not supported", - )) - } -} - -impl ClipboardProvider for Clipboard { +impl ClipboardProvider for clipboard_macos::Clipboard { fn read(&self) -> Result> { self.read() } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 81d1e73..a0c774b 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1,54 +1,14 @@ use crate::ClipboardProvider; -use crate::dnd::DndProvider; use clipboard_win::{get_clipboard_string, set_clipboard_string}; -use dnd::{DndAction, DndDestinationRectangle, DndSurface, Icon}; -use mime::{AllowedMimeTypes, AsMimeTypes}; use raw_window_handle::HasDisplayHandle; -use std::{borrow::Cow, error::Error}; -pub fn connect( +use std::error::Error; + +pub fn connect( _window: &W, -) -> Result> { - Ok(Clipboard) -} -impl DndProvider for Clipboard { - fn init_dnd( - &self, - _tx: Box + Send + Sync + 'static>, - ) { - } - - fn start_dnd( - &self, - _internal: bool, - _source_surface: DndSurface, - _icon_surface: Option, - _content: D, - _actions: DndAction, - ) { - } - - fn end_dnd(&self) {} - - fn register_dnd_destination( - &self, - _surface: DndSurface, - _rectangles: Vec, - ) { - } - - fn set_action(&self, _action: DndAction) {} - - fn peek_offer( - &self, - _mime_type: Option>, - ) -> std::io::Result { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "DnD not supported", - )) - } +) -> Result, Box> { + Ok(Box::new(Clipboard)) } pub struct Clipboard; diff --git a/wayland/Cargo.toml b/wayland/Cargo.toml index 615f76c..6853c9d 100644 --- a/wayland/Cargo.toml +++ b/wayland/Cargo.toml @@ -10,9 +10,4 @@ documentation = "https://docs.rs/clipboard_wayland" keywords = ["clipboard", "wayland"] [dependencies] - -smithay-clipboard = { path = "../../smithay-clipboard", features = [ - "dnd", -] } -mime = { path = "../mime" } -dnd = { path = "../dnd" } +smithay-clipboard = "0.7" diff --git a/wayland/src/lib.rs b/wayland/src/lib.rs index 298e87c..fdf62c0 100644 --- a/wayland/src/lib.rs +++ b/wayland/src/lib.rs @@ -12,99 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{ - borrow::Cow, - error::Error, - ffi::c_void, - sync::{mpsc::SendError, Arc, Mutex}, -}; - -use dnd::{ - DataWrapper, DndAction, DndDestinationRectangle, DndSurface, Sender, -}; -use mime::ClipboardData; -use smithay_clipboard::dnd::{Icon, Rectangle}; -pub use smithay_clipboard::mime::{AllowedMimeTypes, AsMimeTypes, MimeType}; - -#[derive(Clone)] -pub struct DndSender(pub Arc + 'static + Send + Sync>); - -impl smithay_clipboard::dnd::Sender for DndSender { - fn send( - &self, - event: smithay_clipboard::dnd::DndEvent, - ) -> Result<(), SendError>> - { - _ = self.0.send(match event { - smithay_clipboard::dnd::DndEvent::Offer(id, e) => dnd::DndEvent::Offer( - id, - match e { - smithay_clipboard::dnd::OfferEvent::Enter { - x, - y, - mime_types, - surface, - } => dnd::OfferEvent::Enter { - x, - y, - mime_types: mime_types - .into_iter() - .map(|m| m.to_string()) - .collect(), - surface, - }, - smithay_clipboard::dnd::OfferEvent::Motion { x, y } => { - dnd::OfferEvent::Motion { x, y } - } - smithay_clipboard::dnd::OfferEvent::LeaveDestination => { - dnd::OfferEvent::LeaveDestination - } - smithay_clipboard::dnd::OfferEvent::Leave => { - dnd::OfferEvent::Leave - } - smithay_clipboard::dnd::OfferEvent::Drop => { - dnd::OfferEvent::Drop - } - smithay_clipboard::dnd::OfferEvent::SelectedAction( - action, - ) => dnd::OfferEvent::SelectedAction(action.into()), - smithay_clipboard::dnd::OfferEvent::Data { - data, - mime_type, - } => dnd::OfferEvent::Data { - data, - mime_type: mime_type.to_string(), - }, - }, - ), - smithay_clipboard::dnd::DndEvent::Source(e) => match e { - smithay_clipboard::dnd::SourceEvent::Finished => { - dnd::DndEvent::Source(dnd::SourceEvent::Finished) - } - smithay_clipboard::dnd::SourceEvent::Cancelled => { - dnd::DndEvent::Source(dnd::SourceEvent::Cancelled) - } - smithay_clipboard::dnd::SourceEvent::Action(action) => { - dnd::DndEvent::Source(dnd::SourceEvent::Action( - action.into(), - )) - } - smithay_clipboard::dnd::SourceEvent::Mime(mime) => { - dnd::DndEvent::Source(dnd::SourceEvent::Mime( - mime.map(|m| m.to_string()), - )) - } - smithay_clipboard::dnd::SourceEvent::Dropped => { - dnd::DndEvent::Source(dnd::SourceEvent::Dropped) - } - }, - }); - Ok(()) - } -} +use std::error::Error; +use std::ffi::c_void; +use std::sync::{Arc, Mutex}; pub struct Clipboard { - context: Arc>>, + context: Arc>, } impl Clipboard { @@ -117,173 +30,22 @@ impl Clipboard { } pub fn read(&self) -> Result> { - Ok(self.context.lock().unwrap().load_text()?) + Ok(self.context.lock().unwrap().load()?) } pub fn read_primary(&self) -> Result> { - Ok(self.context.lock().unwrap().load_primary_text()?) + Ok(self.context.lock().unwrap().load_primary()?) } pub fn write(&mut self, data: String) -> Result<(), Box> { - self.context.lock().unwrap().store_text(data); - - Ok(()) - } - - pub fn write_primary( - &mut self, - data: String, - ) -> Result<(), Box> { - self.context.lock().unwrap().store_primary_text(data); - - Ok(()) - } - - pub fn write_data( - &mut self, - data: T, - ) -> Result<(), Box> { self.context.lock().unwrap().store(data); Ok(()) } - pub fn write_primary_data( - &mut self, - data: T, - ) -> Result<(), Box> { + pub fn write_primary(&mut self, data: String) -> Result<(), Box> { self.context.lock().unwrap().store_primary(data); Ok(()) } - - pub fn read_data( - &self, - ) -> Result> { - Ok(self.context.lock().unwrap().load()?) - } - - pub fn read_primary_data( - &self, - ) -> Result> { - Ok(self.context.lock().unwrap().load_primary()?) - } - - pub fn read_primary_raw( - &self, - allowed: Vec, - ) -> Result<(Vec, String), Box> { - Ok(self - .context - .lock() - .unwrap() - .load_primary_mime::>( - allowed - .into_iter() - .map(|s| MimeType::from(Cow::Owned(s))) - .collect::>(), - ) - .map(|d| (d.0 .0, d.0 .1.to_string()))?) - } - - pub fn read_raw( - &self, - allowed: Vec, - ) -> Result<(Vec, String), Box> { - Ok(self - .context - .lock() - .unwrap() - .load_mime::>( - allowed - .into_iter() - .map(|s| MimeType::from(Cow::Owned(s))) - .collect::>(), - ) - .map(|d| (d.0 .0, d.0 .1))?) - } - - pub fn init_dnd(&self, tx: DndSender) { - _ = self.context.lock().unwrap().init_dnd(Box::new(tx)); - } - - /// Start a DnD operation on the given surface with some data - pub fn start_dnd( - &self, - internal: bool, - source_surface: DndSurface, - icon_surface: Option, - content: D, - actions: DndAction, - ) { - _ = self.context.lock().unwrap().start_dnd( - internal, - source_surface, - icon_surface.map(|i| Icon::::from(i)), - DataWrapper(content), - actions.into(), - ); - } - - /// End the current DnD operation, if there is one - pub fn end_dnd(&self) { - _ = self.context.lock().unwrap().end_dnd(); - } - - /// Register a surface for receiving DnD offers - /// Rectangles should be provided in order of decreasing priority. - /// This method can be called multiple time for a single surface if the - /// rectangles change. - pub fn register_dnd_destination( - &self, - surface: DndSurface, - rectangles: Vec, - ) { - _ = self.context.lock().unwrap().register_dnd_destination( - surface, - rectangles - .into_iter() - .map(|r| RectangleWrapper(r).into()) - .collect(), - ); - } - - /// Set the final action after presenting the user with a choice - pub fn set_action(&self, action: DndAction) { - self.context.lock().unwrap().set_action(action.into()); - } - - /// Peek at the contents of a DnD offer - pub fn peek_offer( - &self, - mime_type: Option>, - ) -> std::io::Result { - let d = self - .context - .lock() - .unwrap() - .peek_offer::>(mime_type.map(MimeType::from)); - d.map(|d| d.0) - } -} - -pub struct RectangleWrapper(pub DndDestinationRectangle); - -impl From - for smithay_clipboard::dnd::DndDestinationRectangle -{ - fn from(RectangleWrapper(d): RectangleWrapper) -> Self { - smithay_clipboard::dnd::DndDestinationRectangle { - id: d.id, - rectangle: Rectangle { - x: d.rectangle.x, - y: d.rectangle.y, - width: d.rectangle.width, - height: d.rectangle.height, - }, - mime_types: d.mime_types.into_iter().map(MimeType::from).collect(), - actions: d.actions.into(), - preferred: d.preferred.into(), - } - } } diff --git a/x11/src/error.rs b/x11/src/error.rs index a08b07a..cf04d2f 100644 --- a/x11/src/error.rs +++ b/x11/src/error.rs @@ -1,7 +1,5 @@ -use x11rb::{ - errors::{ConnectError, ConnectionError, ReplyError}, - protocol::xproto::Atom, -}; +use x11rb::errors::{ConnectError, ConnectionError, ReplyError}; +use x11rb::protocol::xproto::Atom; use std::sync::mpsc; diff --git a/x11/src/lib.rs b/x11/src/lib.rs index f951252..0a1e310 100644 --- a/x11/src/lib.rs +++ b/x11/src/lib.rs @@ -3,23 +3,17 @@ mod error; pub use error::Error; -use x11rb::{ - connection::Connection as _, - errors::ConnectError, - protocol::{ - xproto::{self, Atom, AtomEnum, EventMask, Window}, - Event, - }, - rust_connection::RustConnection as Connection, - wrapper::ConnectionExt, -}; +use x11rb::connection::Connection as _; +use x11rb::errors::ConnectError; +use x11rb::protocol::xproto::{self, Atom, AtomEnum, EventMask, Window}; +use x11rb::protocol::Event; +use x11rb::rust_connection::RustConnection as Connection; +use x11rb::wrapper::ConnectionExt; -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, - thread, - time::{Duration, Instant}, -}; +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; +use std::thread; +use std::time::{Duration, Instant}; const POLL_DURATION: std::time::Duration = Duration::from_micros(50); @@ -66,16 +60,13 @@ impl Clipboard { self.read_selection(self.reader.atoms.clipboard) } + /// Read the current PRIMARY [`Clipboard`] value. pub fn read_primary(&self) -> Result { self.read_selection(self.reader.atoms.primary) } - fn write_selection( - &mut self, - selection: Atom, - contents: String, - ) -> Result<(), Error> { + fn write_selection(&mut self, selection: Atom, contents: String) -> Result<(), Error> { let target = self.writer.atoms.utf8_string; self.selections @@ -133,13 +124,9 @@ impl Clipboard { selection, target, property, - x11rb::CURRENT_TIME, /* FIXME ^ - * Clients should not use CurrentTime for - * the time argument of a ConvertSelection - * request. - * Instead, they should use the timestamp - * of the event that caused the request to - * be made. */ + x11rb::CURRENT_TIME, // FIXME ^ + // Clients should not use CurrentTime for the time argument of a ConvertSelection request. + // Instead, they should use the timestamp of the event that caused the request to be made. )?; let _ = self.reader.connection.flush()?; @@ -199,9 +186,8 @@ impl Clipboard { continue; }; - // Note that setting the property argument to None indicates - // that the conversion requested could - // not be made. + // Note that setting the property argument to None indicates that the + // conversion requested could not be made. if event.property == AtomEnum::NONE.into() { break; }