signal json clipboard writing

This commit is contained in:
2026-03-06 18:33:47 +01:00
parent 62ba923d5f
commit bcee192e50
4 changed files with 211 additions and 18 deletions

View File

@ -3,25 +3,43 @@ use image::codecs::png::PngEncoder;
use image::{ExtendedColorType, ImageEncoder};
use serde::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use std::result::Result;
use std::sync::mpsc::Sender;
use std::{error::Error, time::SystemTime};
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ClipboardEntry {
pub content: ClipboardData,
#[serde(with = "serde_millis")]
pub timestamp: SystemTime,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ClipboardData {
Text(String),
#[serde(with = "base64_vec")]
Image(Vec<u8>),
}
// X11
use clipboard_master::{CallbackResult, ClipboardHandler};
pub struct Handler {
pub clipboard_tx: Sender<()>,
}
impl ClipboardHandler for Handler {
fn on_clipboard_change(&mut self) -> CallbackResult {
if let Err(e) = self.clipboard_tx.send(()) {
eprintln!("{}", e);
}
CallbackResult::Next
}
}
// X11 end
mod base64_vec {
use base64::{Engine as _, engine::general_purpose::STANDARD};
use serde::{Deserialize, Deserializer, Serializer};
@ -98,16 +116,46 @@ impl ClipboardEntry {
Ok(())
}
}
pub fn write_entry_json(&self, path: &str) -> Result<(), Box<dyn Error>> {
let json = serde_json::to_string_pretty(self)?;
let mut file = File::create(path)?;
file.write_all(json.as_bytes())?;
pub fn append_json(&self, path: &str) -> Result<(), Box<dyn Error>> {
let mut entries: Vec<ClipboardEntry> = if Path::new(path).exists() {
let data = fs::read_to_string(path)?;
if data.trim().is_empty() {
Vec::new()
} else {
serde_json::from_str(&data)?
}
} else {
Vec::new()
};
entries.push(self.clone());
let json = serde_json::to_string_pretty(&entries)?;
fs::write(path, json)?;
Ok(())
}
pub fn read_entry_json(path: &str) -> Result<Self, Box<dyn Error>> {
pub fn read_json(path: &str) -> Result<Vec<ClipboardEntry>, Box<dyn Error>> {
if !Path::new(path).exists() {
return Ok(Vec::new());
}
let data = fs::read_to_string(path)?;
let entry: ClipboardEntry = serde_json::from_str(&data)?;
Ok(entry)
if data.trim().is_empty() {
return Ok(Vec::new());
}
let entries: Vec<ClipboardEntry> = serde_json::from_str(&data)?;
Ok(entries)
}
// pub fn write_json(&self, path: &str) -> Result<(), Box<dyn Error>> {
// let json = serde_json::to_string_pretty(self)?;
// let mut file = File::create(path)?;
// file.write_all(json.as_bytes())?;
// Ok(())
// }
// pub fn read_json(path: &str) -> Result<Self, Box<dyn Error>> {
// let data = fs::read_to_string(path)?;
// let entry: ClipboardEntry = serde_json::from_str(&data)?;
// Ok(entry)
// }
}

View File

@ -1,17 +1,38 @@
use arboard::Clipboard;
use rklipd::ClipboardEntry;
use clipboard_master::Master;
use rklipd::{ClipboardEntry, Handler};
use std::error::Error;
use std::sync::mpsc::channel;
// X11
fn main() -> Result<(), Box<dyn Error>> {
let mut clipboard = Clipboard::new()?;
let entry = ClipboardEntry::new(&mut clipboard)?;
let path = "clipboard.json";
match ClipboardEntry::new_json(path) {
Ok(_) => println!("JSON file created {}", path),
Err(e) => println!("{}", e),
ClipboardEntry::new_json(path).unwrap_or(());
let (tx, rx) = channel();
let mut master = Master::new(Handler { clipboard_tx: tx })?;
// let shutdown = master.shutdown_channel();
std::thread::spawn(move || {
if let Err(e) = master.run() {
eprintln!("Clipboard monitor error : {}", e);
}
});
println!("Monitoring clipboard X11...");
for _ in rx {
println!("Clipboard changed!");
if let Ok(entry) = ClipboardEntry::new(&mut clipboard) {
if let Err(e) = entry.append_json(path) {
eprintln!("JSON writing error: {}", e);
} else {
println!("JSON edited!");
}
}
}
entry.write_entry_json(path)?;
let loaded_entry = ClipboardEntry::read_entry_json(path)?;
println!("{:#?}", loaded_entry);
Ok(())
}
// X11