Skip to content

Commit

Permalink
feat: use wl-copy to copy data into wayland clipboards that do not su…
Browse files Browse the repository at this point in the history
…pport wlroots
  • Loading branch information
dnut committed Nov 11, 2024
1 parent a79e6ad commit 943e49e
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 24 deletions.
61 changes: 41 additions & 20 deletions src/clipboard.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::{env, io::Read, process::Command, thread::sleep, time::Duration};
use std::{env, io::Read, process::Command};
use terminal_clipboard::Clipboard as TerminalClipboard;
use wl_clipboard_rs::copy::{MimeType as CopyMimeType, Options, Source};
use wl_clipboard_rs::paste::{
Expand All @@ -11,17 +11,17 @@ use crate::error::{Generify, MyResult, Standardize};

pub trait Clipboard: std::fmt::Debug {
fn display(&self) -> String;

fn get(&self) -> MyResult<String>;

fn set(&self, value: &str) -> MyResult<()>;
fn watch(&self) -> MyResult<String> {
let start = self.get()?;
loop {
let now = self.get()?;
if now != start {
return Ok(now);
}
sleep(Duration::from_millis(1000));
}

fn should_poll(&self) -> bool {
true
}

fn rank(&self) -> u8 {
100
}
}

Expand All @@ -37,6 +37,14 @@ impl<T: Clipboard> Clipboard for Box<T> {
fn display(&self) -> String {
(**self).display()
}

fn should_poll(&self) -> bool {
(**self).should_poll()
}

fn rank(&self) -> u8 {
(**self).rank()
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -84,30 +92,45 @@ impl Clipboard for WlrClipboard {

Ok(result.standardize().generify()??)
}

fn rank(&self) -> u8 {
10
}
}

#[derive(Debug)]
pub struct CommandClipboard {
display: String,
pub struct WlCommandClipboard {
pub display: String,
}

impl Clipboard for CommandClipboard {
impl Clipboard for WlCommandClipboard {
fn display(&self) -> String {
self.display.clone()
}

fn get(&self) -> MyResult<String> {
env::set_var("WAYLAND_DISPLAY", self.display.clone());
let out = Command::new("wl-paste").output()?.stdout;
let out = Command::new("wl-paste")
.env("WAYLAND_DISPLAY", &self.display)
.output()?
.stdout;
Ok(String::from_utf8_lossy(&out).trim().to_string())
}

fn set(&self, value: &str) -> MyResult<()> {
env::set_var("WAYLAND_DISPLAY", self.display.clone());
Command::new("wl-copy").arg(value).spawn()?;

Command::new("wl-copy")
.arg(value)
.env("WAYLAND_DISPLAY", &self.display)
.spawn()?;
Ok(())
}

fn should_poll(&self) -> bool {
false
}

fn rank(&self) -> u8 {
200
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -181,7 +204,6 @@ impl Clipboard for X11Clipboard {
}

fn get(&self) -> MyResult<String> {
// env::set_var("DISPLAY", self.display.clone());
Ok(self
.backend
.0
Expand All @@ -191,7 +213,6 @@ impl Clipboard for X11Clipboard {
}

fn set(&self, value: &str) -> MyResult<()> {
// env::set_var("DISPLAY", self.display.clone());
self.backend
.0
.try_borrow_mut()?
Expand Down
30 changes: 26 additions & 4 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ pub fn get_clipboards() -> MyResult<Vec<Box<dyn Clipboard>>> {
let cb1 = &clipboards[i];
for (j, cb2) in clipboards.iter().enumerate().take(len).skip(i + 1) {
if are_same(&**cb1, &**cb2)? {
log::debug!("{cb1:?} is the same as {cb2:?}, removing {cb2:?}");
remove_me.insert(j);
if cb1.rank() < cb2.rank() {
log::debug!("dupe detected: {cb1:?} == {cb2:?} -> removing {cb2:?}");
remove_me.insert(j);
} else {
log::debug!("dupe detected: {cb1:?} == {cb2:?} -> removing {cb1:?}");
remove_me.insert(i);
}
}
}
}
Expand Down Expand Up @@ -208,8 +213,22 @@ fn get_wayland(n: u8) -> MyResult<Option<Box<dyn Clipboard>>> {
version: 1,
})) = attempt
{
log::warning!("{wl_display} does not support zwlr_data_control_manager_v1. If you are running gnome in wayland, that's OK because it provides an x11 clipboard, which will be used instead.");
return Ok(None);
log::warning!(
"{wl_display} does not support zwlr_data_control_manager_v1. If you are running \
gnome in wayland, that's OK because it provides an x11 clipboard, which will be used instead. \
Otherwise, `wl-copy` will be used to sync data *into* this clipboard, but it will not be possible \
to read data *from* this clipboard into other clipboards."
);
let command = WlCommandClipboard {
display: wl_display.clone(),
};
let Ok(gotten) = command.get() else {
return Ok(None);
};
let Ok(_) = command.set(&gotten) else {
return Ok(None);
};
return Ok(Some(Box::new(command)));
}
attempt?;

Expand All @@ -228,6 +247,9 @@ fn await_change(clipboards: &Vec<Box<dyn Clipboard>>) -> MyResult<String> {
let start = clipboards[0].get()?;
loop {
for c in clipboards {
if !c.should_poll() {
continue;
}
let new = c.get()?;
if new != start {
log::info!("clipboard updated from display {}", c.display());
Expand Down

0 comments on commit 943e49e

Please sign in to comment.