huge opti

This commit is contained in:
2026-05-20 23:49:53 +02:00
parent 8ea259531e
commit fc085a8a83
7 changed files with 355 additions and 220 deletions

1
rklipd/Cargo.lock generated
View File

@ -1445,6 +1445,7 @@ dependencies = [
"serde_json",
"uuid",
"wayland-clipboard-listener",
"x11rb",
]
[[package]]

View File

@ -15,6 +15,7 @@ serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
base64 = "0.22.1"
aes-gcm = "0.10.3"
x11rb = "0.13.2"
[features]
x11 = []

View File

@ -8,6 +8,11 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, SystemTime};
use uuid::Uuid;
use x11rb::connection::Connection;
use x11rb::protocol::Event;
use x11rb::protocol::xfixes::{ConnectionExt as XfixesExt, SelectionEventMask};
use x11rb::protocol::xproto::{ConnectionExt as XprotoExt, CreateWindowAux, WindowClass};
use x11rb::rust_connection::RustConnection;
const MAX_IMAGE_PIXELS: usize = 3840 * 2160;
@ -18,81 +23,128 @@ fn hash_bytes(data: &[u8]) -> u64 {
}
pub fn start(db: Arc<Mutex<Database>>, mut clipboard: Clipboard) -> Result<(), Box<dyn Error>> {
println!("Clipboard monitor started (X11 polling mode)...");
let (conn, screen_num) =
RustConnection::connect(None).map_err(|e| format!("Connexion X11 impossible : {e}"))?;
let root = conn.setup().roots[screen_num].root;
let win = conn.generate_id()?;
conn.create_window(
0,
win,
root,
0,
0,
1,
1,
0,
WindowClass::INPUT_ONLY,
0,
&CreateWindowAux::new(),
)?
.check()?;
conn.xfixes_query_version(5, 0)
.map_err(|e| format!("Extension XFIXES indisponible : {e}"))?
.reply()?;
let clipboard_atom = conn.intern_atom(false, b"CLIPBOARD")?.reply()?.atom;
conn.xfixes_select_selection_input(
win,
clipboard_atom,
SelectionEventMask::SET_SELECTION_OWNER,
)?
.check()?;
conn.flush()?;
println!("Clipboard monitor démarré (X11 XFIXES — zéro polling)");
let mut last_text: Option<String> = None;
let mut last_image_hash: Option<u64> = None;
loop {
thread::sleep(Duration::from_millis(500));
let event = conn.wait_for_event()?;
match clipboard.get_text() {
Ok(raw) => {
let text = raw.trim_end_matches('\n').to_string();
if text.is_empty() || Some(&text) == last_text.as_ref() {
continue;
}
if let Event::XfixesSelectionNotify(_) = event {
thread::sleep(Duration::from_millis(50));
handle_clipboard_event(&mut clipboard, &db, &mut last_text, &mut last_image_hash);
}
}
}
last_text = Some(text.clone());
last_image_hash = None;
println!("Clipboard update (text)!");
fn handle_clipboard_event(
clipboard: &mut Clipboard,
db: &Arc<Mutex<Database>>,
last_text: &mut Option<String>,
last_image_hash: &mut Option<u64>,
) {
match clipboard.get_text() {
Ok(raw) => {
let text = raw.trim_end_matches('\n').to_string();
if text.is_empty() || Some(&text) == last_text.as_ref() {
return;
}
*last_text = Some(text.clone());
*last_image_hash = None;
println!("Clipboard update (texte)");
let entry = ClipboardEntry {
spawn_db_write(
Arc::clone(db),
ClipboardEntry {
content: ClipboardData::Text(text),
timestamp: SystemTime::now(),
};
spawn_db_write(Arc::clone(&db), entry);
},
);
}
Err(_) => {
let Ok(img_data) = clipboard.get_image() else {
return;
};
let pixel_count = img_data.width * img_data.height;
if pixel_count > MAX_IMAGE_PIXELS {
eprintln!(
"Image ignorée : {}×{} ({} Mpx > limite 4K)",
img_data.width,
img_data.height,
pixel_count / 1_000_000
);
*last_image_hash = Some(pixel_count as u64);
*last_text = None;
return;
}
Err(_) => {
let Ok(img_data) = clipboard.get_image() else {
continue;
};
let hash = hash_bytes(&img_data.bytes);
if Some(hash) == *last_image_hash {
return;
}
*last_image_hash = Some(hash);
*last_text = None;
println!("Clipboard update (image)");
let pixel_count = img_data.width * img_data.height;
if pixel_count > MAX_IMAGE_PIXELS {
eprintln!(
"Image ignorée : {}×{} ({} Mpx > limite {}×{})",
img_data.width,
img_data.height,
pixel_count / 1_000_000,
3840,
2160
);
last_image_hash = Some(pixel_count as u64);
last_text = None;
continue;
}
let hash = hash_bytes(&img_data.bytes);
if Some(hash) == last_image_hash {
continue;
}
last_image_hash = Some(hash);
last_text = None;
println!("Clipboard update (image)!");
let entry = ClipboardEntry {
content: ClipboardData::Image(Image {
spawn_db_write(
Arc::clone(db),
ClipboardEntry {
content: ClipboardData::Image(crate::models::Image {
raw_pixels: Some(img_data.bytes.into_owned()),
width: img_data.width as u32,
height: img_data.height as u32,
id: Uuid::new_v4(),
}),
timestamp: SystemTime::now(),
};
spawn_db_write(Arc::clone(&db), entry);
}
},
);
}
}
}
fn spawn_db_write(db: Arc<Mutex<Database>>, entry: ClipboardEntry) {
thread::spawn(move || {
let db_lock = db.lock().unwrap();
if let Err(e) = db_lock.append(entry) {
eprintln!("SQLite writing error: {}", e);
let lock = db.lock().unwrap();
if let Err(e) = lock.append(entry) {
eprintln!("SQLite write error: {e}");
} else {
println!("SQLite updated!");
}