@@ -671,7 +671,7 @@ impl LinuxClient for WaylandClient {
return;
};
if state.mouse_focused_window.is_some() || state.keyboard_focused_window.is_some() {
- state.clipboard.set_primary(item.text);
+ state.clipboard.set_primary(item);
let serial = state.serial_tracker.get(SerialKind::KeyPress);
let data_source = primary_selection_manager.create_source(&state.globals.qh, ());
data_source.offer(state.clipboard.self_mime());
@@ -689,7 +689,7 @@ impl LinuxClient for WaylandClient {
return;
};
if state.mouse_focused_window.is_some() || state.keyboard_focused_window.is_some() {
- state.clipboard.set(item.text);
+ state.clipboard.set(item);
let serial = state.serial_tracker.get(SerialKind::KeyPress);
let data_source = data_device_manager.create_data_source(&state.globals.qh, ());
data_source.offer(state.clipboard.self_mime());
@@ -699,25 +699,11 @@ impl LinuxClient for WaylandClient {
}
fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
- self.0
- .borrow_mut()
- .clipboard
- .read_primary()
- .map(|s| crate::ClipboardItem {
- text: s,
- metadata: None,
- })
+ self.0.borrow_mut().clipboard.read_primary()
}
fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
- self.0
- .borrow_mut()
- .clipboard
- .read()
- .map(|s| crate::ClipboardItem {
- text: s,
- metadata: None,
- })
+ self.0.borrow_mut().clipboard.read()
}
fn active_window(&self) -> Option<AnyWindowHandle> {
@@ -9,7 +9,7 @@ use filedescriptor::Pipe;
use wayland_client::{protocol::wl_data_offer::WlDataOffer, Connection};
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1;
-use crate::{platform::linux::platform::read_fd, WaylandClientStatePtr};
+use crate::{platform::linux::platform::read_fd, ClipboardItem, WaylandClientStatePtr};
pub(crate) const TEXT_MIME_TYPE: &str = "text/plain;charset=utf-8";
pub(crate) const FILE_LIST_MIME_TYPE: &str = "text/uri-list";
@@ -23,13 +23,13 @@ pub(crate) struct Clipboard {
self_mime: String,
// Internal clipboard
- contents: Option<String>,
- primary_contents: Option<String>,
+ contents: Option<ClipboardItem>,
+ primary_contents: Option<ClipboardItem>,
// External clipboard
- cached_read: Option<String>,
+ cached_read: Option<ClipboardItem>,
current_offer: Option<DataOffer<WlDataOffer>>,
- cached_primary_read: Option<String>,
+ cached_primary_read: Option<ClipboardItem>,
current_primary_offer: Option<DataOffer<ZwpPrimarySelectionOfferV1>>,
}
@@ -89,12 +89,12 @@ impl Clipboard {
}
}
- pub fn set(&mut self, text: String) {
- self.contents = Some(text);
+ pub fn set(&mut self, item: ClipboardItem) {
+ self.contents = Some(item);
}
- pub fn set_primary(&mut self, text: String) {
- self.primary_contents = Some(text);
+ pub fn set_primary(&mut self, item: ClipboardItem) {
+ self.primary_contents = Some(item);
}
pub fn set_offer(&mut self, data_offer: Option<DataOffer<WlDataOffer>>) {
@@ -113,17 +113,17 @@ impl Clipboard {
pub fn send(&self, _mime_type: String, fd: OwnedFd) {
if let Some(contents) = &self.contents {
- self.send_internal(fd, contents.as_bytes().to_owned());
+ self.send_internal(fd, contents.text.as_bytes().to_owned());
}
}
pub fn send_primary(&self, _mime_type: String, fd: OwnedFd) {
if let Some(primary_contents) = &self.primary_contents {
- self.send_internal(fd, primary_contents.as_bytes().to_owned());
+ self.send_internal(fd, primary_contents.text.as_bytes().to_owned());
}
}
- pub fn read(&mut self) -> Option<String> {
+ pub fn read(&mut self) -> Option<ClipboardItem> {
let offer = self.current_offer.clone()?;
if let Some(cached) = self.cached_read.clone() {
return Some(cached);
@@ -145,8 +145,8 @@ impl Clipboard {
match unsafe { read_fd(fd) } {
Ok(v) => {
- self.cached_read = Some(v.clone());
- Some(v)
+ self.cached_read = Some(ClipboardItem::new(v));
+ self.cached_read.clone()
}
Err(err) => {
log::error!("error reading clipboard pipe: {err:?}");
@@ -155,7 +155,7 @@ impl Clipboard {
}
}
- pub fn read_primary(&mut self) -> Option<String> {
+ pub fn read_primary(&mut self) -> Option<ClipboardItem> {
let offer = self.current_primary_offer.clone()?;
if let Some(cached) = self.cached_primary_read.clone() {
return Some(cached);
@@ -177,8 +177,8 @@ impl Clipboard {
match unsafe { read_fd(fd) } {
Ok(v) => {
- self.cached_primary_read = Some(v.clone());
- Some(v)
+ self.cached_primary_read = Some(ClipboardItem::new(v.clone()));
+ self.cached_primary_read.clone()
}
Err(err) => {
log::error!("error reading clipboard pipe: {err:?}");
@@ -29,9 +29,9 @@ use xkbcommon::xkb as xkbc;
use crate::platform::linux::LinuxClient;
use crate::platform::{LinuxCommon, PlatformWindow};
use crate::{
- modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, CursorStyle, DisplayId,
- Keystroke, Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput, Point,
- ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
+ modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
+ DisplayId, Keystroke, Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput,
+ Point, ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
};
use super::{
@@ -129,6 +129,7 @@ pub struct X11ClientState {
pub(crate) common: LinuxCommon,
pub(crate) clipboard: x11_clipboard::Clipboard,
+ pub(crate) clipboard_item: Option<ClipboardItem>,
}
#[derive(Clone)]
@@ -413,6 +414,7 @@ impl X11Client {
scroll_y: None,
clipboard,
+ clipboard_item: None,
})))
}
@@ -1097,7 +1099,7 @@ impl LinuxClient for X11Client {
}
fn write_to_clipboard(&self, item: crate::ClipboardItem) {
- let state = self.0.borrow_mut();
+ let mut state = self.0.borrow_mut();
state
.clipboard
.store(
@@ -1106,6 +1108,7 @@ impl LinuxClient for X11Client {
item.text().as_bytes(),
)
.ok();
+ state.clipboard_item.replace(item);
}
fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
@@ -1127,6 +1130,20 @@ impl LinuxClient for X11Client {
fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
let state = self.0.borrow_mut();
+ // if the last copy was from this app, return our cached item
+ // which has metadata attached.
+ if state
+ .clipboard
+ .setter
+ .connection
+ .get_selection_owner(state.clipboard.setter.atoms.clipboard)
+ .ok()
+ .and_then(|r| r.reply().ok())
+ .map(|reply| reply.owner == state.clipboard.setter.window)
+ .unwrap_or(false)
+ {
+ return state.clipboard_item.clone();
+ }
state
.clipboard
.load(