Skip to main content

wl_clipboard_rs/
lib.rs

1//! A safe Rust crate for working with the Wayland clipboard.
2//!
3//! This crate is intended to be used by terminal applications, clipboard managers and other
4//! utilities which don't spawn Wayland surfaces (windows). If your application has a window,
5//! please use the appropriate Wayland protocols for interacting with the Wayland clipboard
6//! (`wl_data_device` from the core Wayland protocol, the `primary_selection` protocol for the
7//! primary selection), for example via the
8//! [smithay-clipboard](https://crates.io/crates/smithay-clipboard) crate.
9//!
10//! The protocol used for clipboard interaction is `ext-data-control` or `wlr-data-control`. When
11//! using the regular clipboard, the compositor must support any version of either protocol. When
12//! using the "primary" clipboard, the compositor must support any version of `ext-data-control`,
13//! or the second version of the `wlr-data-control` protocol.
14//!
15//! For example applications using these features, see `wl-clipboard-rs-tools/src/bin/wl_copy.rs`
16//! and `wl-clipboard-rs-tools/src/bin/wl_paste.rs` which implement terminal apps similar to
17//! [wl-clipboard](https://github.com/bugaevc/wl-clipboard) or
18//! `wl-clipboard-rs-tools/src/bin/wl_clip.rs` which implements a Wayland version of `xclip`.
19//!
20//! The Rust implementation of the Wayland client is used by default; use the `native_lib` feature
21//! to link to `libwayland-client.so` for communication instead. A `dlopen` feature is also
22//! available for loading `libwayland-client.so` dynamically at runtime rather than linking to it.
23//!
24//! The code of the crate itself (and the code of the example utilities) is 100% safe Rust. This
25//! doesn't include the dependencies.
26//!
27//! # Examples
28//!
29//! Copying to the regular clipboard:
30//! ```no_run
31//! # extern crate wl_clipboard_rs;
32//! # fn foo() -> Result<(), Box<dyn std::error::Error>> {
33//! use wl_clipboard_rs::copy::{MimeType, Options, Source};
34//!
35//! let opts = Options::new();
36//! opts.copy(
37//!     Source::Bytes("Hello world!".to_string().into_bytes().into()),
38//!     MimeType::Autodetect,
39//! )?;
40//! # Ok(())
41//! # }
42//! ```
43//!
44//! Pasting plain text from the regular clipboard:
45//! ```no_run
46//! # extern crate wl_clipboard_rs;
47//! # fn foo() -> Result<(), Box<dyn std::error::Error>> {
48//! use std::io::Read;
49//!
50//! use wl_clipboard_rs::paste::{get_contents, ClipboardType, Error, MimeType, Seat};
51//!
52//! let result = get_contents(ClipboardType::Regular, Seat::Unspecified, MimeType::Text);
53//! match result {
54//!     Ok((mut pipe, _)) => {
55//!         let mut contents = vec![];
56//!         pipe.read_to_end(&mut contents)?;
57//!         println!("Pasted: {}", String::from_utf8_lossy(&contents));
58//!     }
59//!
60//!     Err(Error::NoSeats) | Err(Error::ClipboardEmpty) | Err(Error::NoMimeType) => {
61//!         // The clipboard is empty or doesn't contain text, nothing to worry about.
62//!     }
63//!
64//!     Err(err) => Err(err)?,
65//! }
66//! # Ok(())
67//! # }
68//! ```
69//!
70//! Watching the regular clipboard for selection changes and reading each new text selection:
71//! ```no_run
72//! # extern crate wl_clipboard_rs;
73//! # fn foo() -> Result<(), Box<dyn std::error::Error>> {
74//! use std::io::Read;
75//!
76//! use wl_clipboard_rs::paste::Seat;
77//! use wl_clipboard_rs::watch::{ClipboardEvent, ClipboardType, Watcher};
78//!
79//! let mut watcher = Watcher::new(ClipboardType::Regular, Seat::Unspecified)?;
80//! while let Some(event) = watcher.next_event()? {
81//!     match event {
82//!         ClipboardEvent::Changed {
83//!             mime_types,
84//!             mut offer,
85//!             ..
86//!         } if mime_types.iter().any(|m| m == "text/plain") => {
87//!             let mut contents = String::new();
88//!             offer.receive("text/plain")?.read_to_string(&mut contents)?;
89//!             println!("Clipboard changed: {contents}");
90//!         }
91//!         ClipboardEvent::Changed { .. } => {}
92//!         ClipboardEvent::Cleared { .. } => println!("Clipboard cleared"),
93//!     }
94//! }
95//! # Ok(())
96//! # }
97//! ```
98//!
99//! Obtain a [`watch::CancelHandle`] from [`watch::Watcher::cancel_handle`] to stop a watcher
100//! blocked in [`watch::Watcher::next_event`] from another thread.
101//!
102//! Checking if the "primary" clipboard is supported (note that this might be unnecessary depending
103//! on your crate usage, the regular copying and pasting functions do report if the primary
104//! selection is unsupported when it is requested):
105//!
106//! ```no_run
107//! # extern crate wl_clipboard_rs;
108//! # fn foo() -> Result<(), Box<dyn std::error::Error>> {
109//! use wl_clipboard_rs::utils::{is_primary_selection_supported, PrimarySelectionCheckError};
110//!
111//! match is_primary_selection_supported() {
112//!     Ok(supported) => {
113//!         // We have our definitive result. False means that ext/wlr-data-control is present
114//!         // and did not signal the primary selection support, or that only wlr-data-control
115//!         // version 1 is present (which does not support primary selection).
116//!     }
117//!     Err(PrimarySelectionCheckError::NoSeats) => {
118//!         // Impossible to give a definitive result. Primary selection may or may not be
119//!         // supported.
120//!
121//!         // The required protocol (ext-data-control, or wlr-data-control version 2) is there,
122//!         // but there are no seats. Unfortunately, at least one seat is needed to check for the
123//!         // primary clipboard support.
124//!     }
125//!     Err(PrimarySelectionCheckError::MissingProtocol) => {
126//!         // The data-control protocol (required for wl-clipboard-rs operation) is not
127//!         // supported by the compositor.
128//!     }
129//!     Err(_) => {
130//!         // Some communication error occurred.
131//!     }
132//! }
133//! # Ok(())
134//! # }
135//! ```
136//!
137//! # Included terminal utilities
138//!
139//! - `wl-paste`: implements `wl-paste` from
140//!   [wl-clipboard](https://github.com/bugaevc/wl-clipboard).
141//! - `wl-copy`: implements `wl-copy` from [wl-clipboard](https://github.com/bugaevc/wl-clipboard).
142//! - `wl-clip`: a Wayland version of `xclip`.
143
144#![doc(html_root_url = "https://docs.rs/wl-clipboard-rs/0.9.4")]
145#![deny(unsafe_code)]
146
147mod common;
148mod data_control;
149mod seat_data;
150
151#[cfg(test)]
152#[allow(unsafe_code)] // It's more convenient for testing some stuff.
153mod tests;
154
155pub mod copy;
156pub mod paste;
157pub mod utils;
158pub mod watch;