Skip to content

Commit dc2cba9

Browse files
authored
Merge pull request #2240 from snaggen/primary
Add support for primary clipboard
2 parents 7615b22 + 3ac2902 commit dc2cba9

10 files changed

Lines changed: 110 additions & 46 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- `Themer` widget. [#2209](https://github.com/iced-rs/iced/pull/2209)
1818
- `Transform` primitive. [#2120](https://github.com/iced-rs/iced/pull/2120)
1919
- Cut functionality for `TextEditor`. [#2215](https://github.com/iced-rs/iced/pull/2215)
20-
- Disabled support for `Checkbox`. [#2109](https://github.com/iced-rs/iced/pull/2109)
20+
- Primary clipboard support. [#2240](https://github.com/iced-rs/iced/pull/2240)
21+
- Disabled state for `Checkbox`. [#2109](https://github.com/iced-rs/iced/pull/2109)
2122
- `skip_taskbar` window setting for Windows. [#2211](https://github.com/iced-rs/iced/pull/2211)
2223
- `fetch_maximized` and `fetch_minimized` commands in `window`. [#2189](https://github.com/iced-rs/iced/pull/2189)
2324
- `run_with_handle` command in `window`. [#2200](https://github.com/iced-rs/iced/pull/2200)
@@ -150,6 +151,7 @@ Many thanks to...
150151
- @nyurik
151152
- @Remmirad
152153
- @ripytide
154+
- @snaggen
153155
- @Tahinli
154156
- @tarkah
155157
- @tzemanovic

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,5 +160,5 @@ web-sys = "=0.3.67"
160160
web-time = "0.2"
161161
wgpu = "0.19"
162162
winapi = "0.3"
163-
window_clipboard = "0.4"
163+
window_clipboard = "0.4.1"
164164
winit = { git = "https://github.com/iced-rs/winit.git", rev = "b91e39ece2c0d378c3b80da7f3ab50e17bb798a5" }

core/src/clipboard.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@
44
/// applications.
55
pub trait Clipboard {
66
/// Reads the current content of the [`Clipboard`] as text.
7-
fn read(&self) -> Option<String>;
7+
fn read(&self, kind: Kind) -> Option<String>;
88

99
/// Writes the given text contents to the [`Clipboard`].
10-
fn write(&mut self, contents: String);
10+
fn write(&mut self, kind: Kind, contents: String);
11+
}
12+
13+
/// The kind of [`Clipboard`].
14+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15+
pub enum Kind {
16+
/// The standard clipboard.
17+
Standard,
18+
/// The primary clipboard.
19+
///
20+
/// Normally only present in X11 and Wayland.
21+
Primary,
1122
}
1223

1324
/// A null implementation of the [`Clipboard`] trait.
1425
#[derive(Debug, Clone, Copy)]
1526
pub struct Null;
1627

1728
impl Clipboard for Null {
18-
fn read(&self) -> Option<String> {
29+
fn read(&self, _kind: Kind) -> Option<String> {
1930
None
2031
}
2132

22-
fn write(&mut self, _contents: String) {}
33+
fn write(&mut self, _kind: Kind, _contents: String) {}
2334
}

runtime/src/clipboard.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Access the clipboard.
22
use crate::command::{self, Command};
3+
use crate::core::clipboard::Kind;
34
use crate::futures::MaybeSend;
45

56
use std::fmt;
@@ -9,10 +10,10 @@ use std::fmt;
910
/// [`Command`]: crate::Command
1011
pub enum Action<T> {
1112
/// Read the clipboard and produce `T` with the result.
12-
Read(Box<dyn Fn(Option<String>) -> T>),
13+
Read(Box<dyn Fn(Option<String>) -> T>, Kind),
1314

1415
/// Write the given contents to the clipboard.
15-
Write(String),
16+
Write(String, Kind),
1617
}
1718

1819
impl<T> Action<T> {
@@ -25,17 +26,19 @@ impl<T> Action<T> {
2526
T: 'static,
2627
{
2728
match self {
28-
Self::Read(o) => Action::Read(Box::new(move |s| f(o(s)))),
29-
Self::Write(content) => Action::Write(content),
29+
Self::Read(o, target) => {
30+
Action::Read(Box::new(move |s| f(o(s))), target)
31+
}
32+
Self::Write(content, target) => Action::Write(content, target),
3033
}
3134
}
3235
}
3336

3437
impl<T> fmt::Debug for Action<T> {
3538
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3639
match self {
37-
Self::Read(_) => write!(f, "Action::Read"),
38-
Self::Write(_) => write!(f, "Action::Write"),
40+
Self::Read(_, target) => write!(f, "Action::Read{target:?}"),
41+
Self::Write(_, target) => write!(f, "Action::Write({target:?})"),
3942
}
4043
}
4144
}
@@ -44,10 +47,34 @@ impl<T> fmt::Debug for Action<T> {
4447
pub fn read<Message>(
4548
f: impl Fn(Option<String>) -> Message + 'static,
4649
) -> Command<Message> {
47-
Command::single(command::Action::Clipboard(Action::Read(Box::new(f))))
50+
Command::single(command::Action::Clipboard(Action::Read(
51+
Box::new(f),
52+
Kind::Standard,
53+
)))
54+
}
55+
56+
/// Read the current contents of the primary clipboard.
57+
pub fn read_primary<Message>(
58+
f: impl Fn(Option<String>) -> Message + 'static,
59+
) -> Command<Message> {
60+
Command::single(command::Action::Clipboard(Action::Read(
61+
Box::new(f),
62+
Kind::Primary,
63+
)))
4864
}
4965

5066
/// Write the given contents to the clipboard.
5167
pub fn write<Message>(contents: String) -> Command<Message> {
52-
Command::single(command::Action::Clipboard(Action::Write(contents)))
68+
Command::single(command::Action::Clipboard(Action::Write(
69+
contents,
70+
Kind::Standard,
71+
)))
72+
}
73+
74+
/// Write the given contents to the primary clipboard.
75+
pub fn write_primary<Message>(contents: String) -> Command<Message> {
76+
Command::single(command::Action::Clipboard(Action::Write(
77+
contents,
78+
Kind::Primary,
79+
)))
5380
}

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ pub use crate::core::{
200200

201201
pub mod clipboard {
202202
//! Access the clipboard.
203-
pub use crate::runtime::clipboard::{read, write};
203+
pub use crate::runtime::clipboard::{
204+
read, read_primary, write, write_primary,
205+
};
204206
}
205207

206208
pub mod executor {

widget/src/text_editor.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Display a multi-line text input for text editing.
2+
use crate::core::clipboard::{self, Clipboard};
23
use crate::core::event::{self, Event};
34
use crate::core::keyboard;
45
use crate::core::keyboard::key;
@@ -10,7 +11,7 @@ use crate::core::text::highlighter::{self, Highlighter};
1011
use crate::core::text::{self, LineHeight};
1112
use crate::core::widget::{self, Widget};
1213
use crate::core::{
13-
Clipboard, Element, Length, Padding, Pixels, Rectangle, Shell, Size, Vector,
14+
Element, Length, Padding, Pixels, Rectangle, Shell, Size, Vector,
1415
};
1516

1617
use std::cell::RefCell;
@@ -448,17 +449,19 @@ where
448449
}
449450
Update::Copy => {
450451
if let Some(selection) = self.content.selection() {
451-
clipboard.write(selection);
452+
clipboard.write(clipboard::Kind::Standard, selection);
452453
}
453454
}
454455
Update::Cut => {
455456
if let Some(selection) = self.content.selection() {
456-
clipboard.write(selection.clone());
457+
clipboard.write(clipboard::Kind::Standard, selection);
457458
shell.publish(on_edit(Action::Edit(Edit::Delete)));
458459
}
459460
}
460461
Update::Paste => {
461-
if let Some(contents) = clipboard.read() {
462+
if let Some(contents) =
463+
clipboard.read(clipboard::Kind::Standard)
464+
{
462465
shell.publish(on_edit(Action::Edit(Edit::Paste(
463466
Arc::new(contents),
464467
))));

widget/src/text_input.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub use value::Value;
1212
use editor::Editor;
1313

1414
use crate::core::alignment;
15+
use crate::core::clipboard::{self, Clipboard};
1516
use crate::core::event::{self, Event};
1617
use crate::core::keyboard;
1718
use crate::core::keyboard::key;
@@ -26,8 +27,8 @@ use crate::core::widget::operation::{self, Operation};
2627
use crate::core::widget::tree::{self, Tree};
2728
use crate::core::window;
2829
use crate::core::{
29-
Clipboard, Element, Layout, Length, Padding, Pixels, Point, Rectangle,
30-
Shell, Size, Vector, Widget,
30+
Element, Layout, Length, Padding, Pixels, Point, Rectangle, Shell, Size,
31+
Vector, Widget,
3132
};
3233
use crate::runtime::Command;
3334

@@ -864,8 +865,10 @@ where
864865
if let Some((start, end)) =
865866
state.cursor.selection(value)
866867
{
867-
clipboard
868-
.write(value.select(start, end).to_string());
868+
clipboard.write(
869+
clipboard::Kind::Standard,
870+
value.select(start, end).to_string(),
871+
);
869872
}
870873
}
871874
keyboard::Key::Character("x")
@@ -874,8 +877,10 @@ where
874877
if let Some((start, end)) =
875878
state.cursor.selection(value)
876879
{
877-
clipboard
878-
.write(value.select(start, end).to_string());
880+
clipboard.write(
881+
clipboard::Kind::Standard,
882+
value.select(start, end).to_string(),
883+
);
879884
}
880885

881886
let mut editor = Editor::new(value, &mut state.cursor);
@@ -894,7 +899,7 @@ where
894899
Some(content) => content,
895900
None => {
896901
let content: String = clipboard
897-
.read()
902+
.read(clipboard::Kind::Standard)
898903
.unwrap_or_default()
899904
.chars()
900905
.filter(|c| !c.is_control())

winit/src/application.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -704,15 +704,15 @@ pub fn run_command<A, C, E>(
704704
runtime.run(stream);
705705
}
706706
command::Action::Clipboard(action) => match action {
707-
clipboard::Action::Read(tag) => {
708-
let message = tag(clipboard.read());
707+
clipboard::Action::Read(tag, kind) => {
708+
let message = tag(clipboard.read(kind));
709709

710710
proxy
711711
.send_event(message)
712712
.expect("Send message to event loop");
713713
}
714-
clipboard::Action::Write(contents) => {
715-
clipboard.write(contents);
714+
clipboard::Action::Write(contents, kind) => {
715+
clipboard.write(kind, contents);
716716
}
717717
},
718718
command::Action::Window(action) => match action {

winit/src/clipboard.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Access the clipboard.
22
3+
use crate::core::clipboard::Kind;
4+
35
/// A buffer for short-term storage and transfer within and between
46
/// applications.
57
#[allow(missing_debug_implementations)]
@@ -33,33 +35,45 @@ impl Clipboard {
3335
}
3436

3537
/// Reads the current content of the [`Clipboard`] as text.
36-
pub fn read(&self) -> Option<String> {
38+
pub fn read(&self, kind: Kind) -> Option<String> {
3739
match &self.state {
38-
State::Connected(clipboard) => clipboard.read().ok(),
40+
State::Connected(clipboard) => match kind {
41+
Kind::Standard => clipboard.read().ok(),
42+
Kind::Primary => clipboard.read_primary().and_then(Result::ok),
43+
},
3944
State::Unavailable => None,
4045
}
4146
}
4247

4348
/// Writes the given text contents to the [`Clipboard`].
44-
pub fn write(&mut self, contents: String) {
49+
pub fn write(&mut self, kind: Kind, contents: String) {
4550
match &mut self.state {
46-
State::Connected(clipboard) => match clipboard.write(contents) {
47-
Ok(()) => {}
48-
Err(error) => {
49-
log::warn!("error writing to clipboard: {error}");
51+
State::Connected(clipboard) => {
52+
let result = match kind {
53+
Kind::Standard => clipboard.write(contents),
54+
Kind::Primary => {
55+
clipboard.write_primary(contents).unwrap_or(Ok(()))
56+
}
57+
};
58+
59+
match result {
60+
Ok(()) => {}
61+
Err(error) => {
62+
log::warn!("error writing to clipboard: {error}");
63+
}
5064
}
51-
},
65+
}
5266
State::Unavailable => {}
5367
}
5468
}
5569
}
5670

5771
impl crate::core::Clipboard for Clipboard {
58-
fn read(&self) -> Option<String> {
59-
self.read()
72+
fn read(&self, kind: Kind) -> Option<String> {
73+
self.read(kind)
6074
}
6175

62-
fn write(&mut self, contents: String) {
63-
self.write(contents);
76+
fn write(&mut self, kind: Kind, contents: String) {
77+
self.write(kind, contents);
6478
}
6579
}

winit/src/multi_window.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -876,15 +876,15 @@ fn run_command<A, C, E>(
876876
runtime.run(Box::pin(stream));
877877
}
878878
command::Action::Clipboard(action) => match action {
879-
clipboard::Action::Read(tag) => {
880-
let message = tag(clipboard.read());
879+
clipboard::Action::Read(tag, kind) => {
880+
let message = tag(clipboard.read(kind));
881881

882882
proxy
883883
.send_event(message)
884884
.expect("Send message to event loop");
885885
}
886-
clipboard::Action::Write(contents) => {
887-
clipboard.write(contents);
886+
clipboard::Action::Write(contents, kind) => {
887+
clipboard.write(kind, contents);
888888
}
889889
},
890890
command::Action::Window(action) => match action {

0 commit comments

Comments
 (0)