From 25e67b760bea0393f574aa29f909025dbf4208e3 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 10 Mar 2021 21:28:59 +0100 Subject: [PATCH 1/2] More improvements --- Cargo.toml | 1 + examples/big_file.rs | 54 +++++++++++++++++++++ x11/src/lib.rs | 110 +------------------------------------------ 3 files changed, 57 insertions(+), 108 deletions(-) create mode 100644 examples/big_file.rs diff --git a/Cargo.toml b/Cargo.toml index 19e5e23..0173068 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ clipboard_x11 = { version = "0.2", path = "./x11" } clipboard_wayland = { version = "0.1", path = "./wayland" } [dev-dependencies] +rand = "0.8" winit = "0.23" [workspace] diff --git a/examples/big_file.rs b/examples/big_file.rs new file mode 100644 index 0000000..9584b72 --- /dev/null +++ b/examples/big_file.rs @@ -0,0 +1,54 @@ +use rand::distributions::{Alphanumeric, Distribution}; +use window_clipboard::Clipboard; +use winit::{ + event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; + +fn main() { + let mut rng = rand::thread_rng(); + + let data: String = Alphanumeric + .sample_iter(&mut rng) + .take(10_000_000) + .map(char::from) + .collect(); + + let event_loop = EventLoop::new(); + + let window = WindowBuilder::new() + .with_title("Press G to start the test!") + .build(&event_loop) + .unwrap(); + + let mut clipboard = + Clipboard::connect(&window).expect("Connect to clipboard"); + + clipboard.write(data.clone()).unwrap(); + + event_loop.run(move |event, _, control_flow| match event { + Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::G), + state: ElementState::Released, + .. + }, + .. + }, + .. + } => { + let new_data = clipboard.read().expect("Read data"); + assert_eq!(data, new_data, "Data is equal"); + println!("Data copied successfully!"); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id, + } if window_id == window.id() => *control_flow = ControlFlow::Exit, + _ => *control_flow = ControlFlow::Wait, + }); +} diff --git a/x11/src/lib.rs b/x11/src/lib.rs index 4b3b4b3..38d63e3 100644 --- a/x11/src/lib.rs +++ b/x11/src/lib.rs @@ -3,7 +3,7 @@ mod error; pub use error::Error; -use x11rb::connection::Connection as _; +use x11rb::connection::{Connection as _, RequestConnection}; use x11rb::errors::ConnectError; use x11rb::protocol::xproto::{self, Atom, AtomEnum, Window}; use x11rb::protocol::Event; @@ -11,7 +11,6 @@ use x11rb::rust_connection::RustConnection as Connection; use x11rb::wrapper::ConnectionExt; use std::collections::HashMap; -use std::sync::mpsc; use std::sync::{Arc, RwLock}; use std::thread; use std::time::{Duration, Instant}; @@ -23,7 +22,6 @@ pub struct Clipboard { reader: Context, writer: Arc, selections: Arc)>>>, - worker: mpsc::Sender, } impl Clipboard { @@ -32,12 +30,10 @@ impl Clipboard { let reader = Context::new(None)?; let writer = Arc::new(Context::new(None)?); let selections = Arc::new(RwLock::new(HashMap::new())); - let (sender, receiver) = mpsc::channel(); let worker = Worker { context: Arc::clone(&writer), selections: Arc::clone(&selections), - receiver, }; thread::spawn(move || worker.run()); @@ -46,7 +42,6 @@ impl Clipboard { reader, writer, selections, - worker: sender, }) } @@ -66,8 +61,6 @@ impl Clipboard { let selection = self.writer.atoms.clipboard; let target = self.writer.atoms.utf8_string; - let _ = self.worker.send(selection)?; - self.selections .write() .map_err(|_| Error::SelectionLocked)? @@ -344,34 +337,13 @@ impl Context { pub struct Worker { context: Arc, selections: Arc)>>>, - receiver: mpsc::Receiver, -} - -struct IncrState { - selection: Atom, - requestor: Atom, - property: Atom, - pos: usize, } impl Worker { pub const INCR_CHUNK_SIZE: usize = 4000; pub fn run(self) { - use x11rb::connection::RequestConnection; - - let mut incr_map = HashMap::new(); - let mut state_map = HashMap::new(); - - let max_length = self.context.connection.maximum_request_bytes() * 4; - while let Ok(event) = self.context.connection.wait_for_event() { - while let Ok(selection) = self.receiver.try_recv() { - if let Some(property) = incr_map.remove(&selection) { - state_map.remove(&property); - } - } - match event { Event::SelectionRequest(event) => { let selections = match self.selections.read().ok() { @@ -396,7 +368,7 @@ impl Worker { &data, ) .expect("Change property"); - } else if value.len() < max_length - 24 { + } else { let _ = self.context.connection.change_property8( xproto::PropMode::REPLACE, event.requestor, @@ -405,34 +377,6 @@ impl Worker { value, ) .expect("Change property"); - } else { - let _ = xproto::change_window_attributes( - &self.context.connection, - event.requestor, - &xproto::ChangeWindowAttributesAux::new() - .event_mask(xproto::EventMask::PROPERTY_CHANGE), - ) - .expect("Change window attributes"); - - self.context.connection.change_property32( - xproto::PropMode::REPLACE, - event.requestor, - event.property, - self.context.atoms.incr, - &[], - ) - .expect("Change property"); - - incr_map.insert(event.selection, event.property); - state_map.insert( - event.property, - IncrState { - selection: event.selection, - requestor: event.requestor, - property: event.property, - pos: 0, - }, - ); } let _ = xproto::send_event( @@ -454,57 +398,7 @@ impl Worker { let _ = self.context.connection.flush(); } - Event::PropertyNotify(event) => { - if event.state != xproto::Property::DELETE { - continue; - } - - let is_end = { - let state = match state_map.get_mut(&event.atom) { - Some(state) => state, - None => continue, - }; - - let selections = match self.selections.read().ok() { - Some(selections) => selections, - None => continue, - }; - - let &(target, ref value) = - match selections.get(&state.selection) { - Some(key_value) => key_value, - None => continue, - }; - - let len = std::cmp::min( - Self::INCR_CHUNK_SIZE, - value.len() - state.pos, - ); - - let _ = self.context.connection.change_property8( - xproto::PropMode::REPLACE, - state.requestor, - state.property, - target, - &value[state.pos..][..len], - ) - .expect("Change property"); - - state.pos += len; - len == 0 - }; - - if is_end { - state_map.remove(&event.atom); - } - - self.context.connection.flush().expect("Flush connection"); - } Event::SelectionClear(event) => { - if let Some(property) = incr_map.remove(&event.selection) { - state_map.remove(&property); - } - if let Ok(mut write_setmap) = self.selections.write() { write_setmap.remove(&event.selection); } From c12bb7e04c9e9a76cf24859ef6a5a862effb30e3 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 10 Mar 2021 22:16:41 +0100 Subject: [PATCH 2/2] Remove leftover --- x11/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x11/src/lib.rs b/x11/src/lib.rs index 38d63e3..0e2b54e 100644 --- a/x11/src/lib.rs +++ b/x11/src/lib.rs @@ -3,7 +3,7 @@ mod error; pub use error::Error; -use x11rb::connection::{Connection as _, RequestConnection}; +use x11rb::connection::Connection as _; use x11rb::errors::ConnectError; use x11rb::protocol::xproto::{self, Atom, AtomEnum, Window}; use x11rb::protocol::Event;