rdw: fix primary/clipboard serials

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2021-08-14 01:19:55 +04:00
parent fb517a13db
commit 70c9e81515

View File

@ -25,26 +25,29 @@ impl Handler {
.await .await
.expect("Failed to listen to the clipboard"); .expect("Failed to listen to the clipboard");
let proxy = ctxt.proxy.clone(); let proxy = ctxt.proxy.clone();
let serial = Rc::new(Cell::new(0)); let serials = Rc::new([Cell::new(0), Cell::new(0)]);
let current_serial = serial.clone(); let current_serials = serials.clone();
let rx = rx.attach(None, move |evt| { let rx = rx.attach(None, move |evt| {
use ClipboardEvent::*; use ClipboardEvent::*;
log::debug!("Clipboard event: {:?}", evt); log::debug!("Clipboard event: {:?}", evt);
match evt { match evt {
Register | Unregister => { Register | Unregister => {
current_serial.set(0); current_serials[0].set(0);
} current_serials[1].set(0);
Grab { serial, .. } if serial < current_serial.get() => {
log::debug!("Ignored peer grab: {} < {}", serial, current_serial.get());
} }
Grab { Grab {
selection, selection,
serial, serial,
mimes, mimes,
} => { } => {
current_serial.set(serial); if let Some((clipboard, idx)) = clipboard_from_selection(selection) {
if let Some(clipboard) = clipboard_from_selection(selection) { if serial < current_serials[idx].get() {
log::debug!("Ignored peer grab: {} < {}", serial, current_serials[idx].get());
return Continue(true);
}
current_serials[idx].set(serial);
let m: Vec<_> = mimes.iter().map(|s|s.as_str()).collect(); let m: Vec<_> = mimes.iter().map(|s|s.as_str()).collect();
let p = proxy.clone(); let p = proxy.clone();
let content = rdw::ContentProvider::new(&m, move |mime, stream, prio| { let content = rdw::ContentProvider::new(&m, move |mime, stream, prio| {
@ -73,7 +76,7 @@ impl Handler {
} }
} }
Release { selection } => { Release { selection } => {
if let Some(clipboard) = clipboard_from_selection(selection) { if let Some((clipboard, _)) = clipboard_from_selection(selection) {
// TODO: track if the outside/app changed the clipboard // TODO: track if the outside/app changed the clipboard
if let Err(e) = clipboard.set_content(gdk::NONE_CONTENT_PROVIDER) { if let Err(e) = clipboard.set_content(gdk::NONE_CONTENT_PROVIDER) {
log::warn!("Failed to release clipboard: {}", e); log::warn!("Failed to release clipboard: {}", e);
@ -81,7 +84,7 @@ impl Handler {
} }
} }
Request { selection, mimes, tx } => { Request { selection, mimes, tx } => {
if let Some(clipboard) = clipboard_from_selection(selection) { if let Some((clipboard, _)) = clipboard_from_selection(selection) {
glib::MainContext::default().spawn_local(async move { glib::MainContext::default().spawn_local(async move {
let m: Vec<_> = mimes.iter().map(|s|s.as_str()).collect(); let m: Vec<_> = mimes.iter().map(|s|s.as_str()).collect();
let res = clipboard.read_async_future(&m, glib::Priority::default()).await; let res = clipboard.read_async_future(&m, glib::Priority::default()).await;
@ -118,12 +121,12 @@ impl Handler {
let cb_handler = watch_clipboard( let cb_handler = watch_clipboard(
ctxt.proxy.clone(), ctxt.proxy.clone(),
ClipboardSelection::Clipboard, ClipboardSelection::Clipboard,
serial.clone(), serials.clone(),
); );
let cb_primary_handler = watch_clipboard( let cb_primary_handler = watch_clipboard(
ctxt.proxy.clone(), ctxt.proxy.clone(),
ClipboardSelection::Primary, ClipboardSelection::Primary,
serial.clone(), serials.clone(),
); );
ctxt.register().await?; ctxt.register().await?;
@ -138,10 +141,10 @@ impl Handler {
fn watch_clipboard( fn watch_clipboard(
proxy: AsyncClipboardProxy<'static>, proxy: AsyncClipboardProxy<'static>,
selection: ClipboardSelection, selection: ClipboardSelection,
serial: Rc<Cell<u32>>, serials: Rc<[Cell<u32>; 2]>,
) -> Option<SignalHandlerId> { ) -> Option<SignalHandlerId> {
let clipboard = match clipboard_from_selection(selection) { let (clipboard, idx) = match clipboard_from_selection(selection) {
Some(clipboard) => clipboard, Some(it) => it,
None => return None, None => return None,
}; };
@ -153,16 +156,16 @@ fn watch_clipboard(
if let Some(formats) = clipboard.formats() { if let Some(formats) = clipboard.formats() {
let types = formats.mime_types(); let types = formats.mime_types();
log::debug!(">clipboard-changed({:?}): {:?}", selection, types); log::debug!(">clipboard-changed({:?}): {:?}", selection, types);
let proxy_clone = proxy.clone(); let proxy = proxy.clone();
let serial = serial.clone(); let serials = serials.clone();
glib::MainContext::default().spawn_local(async move { glib::MainContext::default().spawn_local(async move {
if types.is_empty() { if types.is_empty() {
let _ = proxy_clone.release(selection).await; let _ = proxy.release(selection).await;
} else { } else {
let mimes: Vec<_> = types.iter().map(|s| s.as_str()).collect(); let mimes: Vec<_> = types.iter().map(|s| s.as_str()).collect();
let ser = serial.get(); let ser = serials[idx].get();
let _ = proxy_clone.grab(selection, ser, &mimes).await; let _ = proxy.grab(selection, ser, &mimes).await;
serial.set(ser + 1); serials[idx].set(ser + 1);
} }
}); });
} }
@ -170,15 +173,15 @@ fn watch_clipboard(
Some(id) Some(id)
} }
fn clipboard_from_selection(selection: ClipboardSelection) -> Option<gdk::Clipboard> { fn clipboard_from_selection(selection: ClipboardSelection) -> Option<(gdk::Clipboard, usize)> {
let display = match gdk::Display::default() { let display = match gdk::Display::default() {
Some(display) => display, Some(display) => display,
None => return None, None => return None,
}; };
match selection { match selection {
ClipboardSelection::Clipboard => Some(display.clipboard()), ClipboardSelection::Clipboard => Some((display.clipboard(), 0)),
ClipboardSelection::Primary => Some(display.primary_clipboard()), ClipboardSelection::Primary => Some((display.primary_clipboard(), 1)),
_ => { _ => {
log::warn!("Unsupport clipboard selection: {:?}", selection); log::warn!("Unsupport clipboard selection: {:?}", selection);
None None