Avoid panic on dispatch failure (#23)
Prevent crash when calling unwrap on either sync_roundtrip or dispatch_pending, and handle such case by replying downstream that clipboard is dead.
This commit is contained in:
parent
2aea170962
commit
8a81be7c0a
4 changed files with 43 additions and 10 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
- Fixed clipboard crashing, when seat has neither keyboard nor pointer focus
|
- Fixed clipboard crashing, when seat has neither keyboard nor pointer focus
|
||||||
- Advertise UTF8_STRING mimetype
|
- Advertise UTF8_STRING mimetype
|
||||||
|
- Fixed crash when writing data to the server fails
|
||||||
- Fixed fd leaking from keymap updates
|
- Fixed fd leaking from keymap updates
|
||||||
|
|
||||||
## 0.5.1 -- 2020-07-10
|
## 0.5.1 -- 2020-07-10
|
||||||
|
|
|
||||||
22
src/lib.rs
22
src/lib.rs
|
|
@ -43,10 +43,17 @@ impl Clipboard {
|
||||||
/// Loads content from a clipboard on a last observed seat.
|
/// Loads content from a clipboard on a last observed seat.
|
||||||
pub fn load(&self) -> Result<String> {
|
pub fn load(&self) -> Result<String> {
|
||||||
let _ = self.request_sender.send(worker::Command::Load);
|
let _ = self.request_sender.send(worker::Command::Load);
|
||||||
self.request_receiver.recv().unwrap()
|
|
||||||
|
if let Ok(reply) = self.request_receiver.recv() {
|
||||||
|
reply
|
||||||
|
} else {
|
||||||
|
// The clipboard thread is dead, however we shouldn't crash downstream, so
|
||||||
|
// propogating an error.
|
||||||
|
Err(std::io::Error::new(std::io::ErrorKind::Other, "clipboard is dead."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store to a clipboard
|
/// Store to a clipboard.
|
||||||
///
|
///
|
||||||
/// Stores to a clipboard on a last observed seat.
|
/// Stores to a clipboard on a last observed seat.
|
||||||
pub fn store<T: Into<String>>(&self, text: T) {
|
pub fn store<T: Into<String>>(&self, text: T) {
|
||||||
|
|
@ -59,7 +66,14 @@ impl Clipboard {
|
||||||
/// Loads content from a primary clipboard on a last observed seat.
|
/// Loads content from a primary clipboard on a last observed seat.
|
||||||
pub fn load_primary(&self) -> Result<String> {
|
pub fn load_primary(&self) -> Result<String> {
|
||||||
let _ = self.request_sender.send(worker::Command::LoadPrimary);
|
let _ = self.request_sender.send(worker::Command::LoadPrimary);
|
||||||
self.request_receiver.recv().unwrap()
|
|
||||||
|
if let Ok(reply) = self.request_receiver.recv() {
|
||||||
|
reply
|
||||||
|
} else {
|
||||||
|
// The clipboard thread is dead, however we shouldn't crash downstream, so
|
||||||
|
// propogating an error.
|
||||||
|
Err(std::io::Error::new(std::io::ErrorKind::Other, "clipboard is dead."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store to a primary clipboard.
|
/// Store to a primary clipboard.
|
||||||
|
|
@ -74,7 +88,7 @@ impl Clipboard {
|
||||||
impl Drop for Clipboard {
|
impl Drop for Clipboard {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Shutdown smithay-clipboard.
|
// Shutdown smithay-clipboard.
|
||||||
self.request_sender.send(worker::Command::Exit).unwrap();
|
let _ = self.request_sender.send(worker::Command::Exit);
|
||||||
if let Some(clipboard_thread) = self.clipboard_thread.take() {
|
if let Some(clipboard_thread) = self.clipboard_thread.take() {
|
||||||
let _ = clipboard_thread.join();
|
let _ = clipboard_thread.join();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,12 @@ macro_rules! handle_load {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()).unwrap();
|
// If we fail here, it means that we likely won't be able
|
||||||
|
// to read clipboard anyway, so return and reply to prevent block/crash.
|
||||||
|
if $queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()).is_err() {
|
||||||
|
handlers::reply_error(&$tx, "failed to access clipboard.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
let result = reader.read_to_string(&mut contents).map(|_| {
|
let result = reader.read_to_string(&mut contents).map(|_| {
|
||||||
|
|
@ -52,7 +57,7 @@ macro_rules! handle_load {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$tx.send(result).unwrap();
|
let _ = $tx.send(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send back that we've failed to load data from the clipboard.
|
// Send back that we've failed to load data from the clipboard.
|
||||||
|
|
@ -86,7 +91,7 @@ macro_rules! handle_store {
|
||||||
|
|
||||||
/// Reply an error to a clipboard master.
|
/// Reply an error to a clipboard master.
|
||||||
pub fn reply_error(tx: &Sender<Result<String>>, description: &str) {
|
pub fn reply_error(tx: &Sender<Result<String>>, description: &str) {
|
||||||
tx.send(Err(std::io::Error::new(std::io::ErrorKind::Other, description))).unwrap();
|
let _ = tx.send(Err(std::io::Error::new(std::io::ErrorKind::Other, description)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update seat and serial on pointer events.
|
/// Update seat and serial on pointer events.
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,12 @@ fn worker_impl(display: Display, request_rx: Receiver<Command>, reply_tx: Sender
|
||||||
|
|
||||||
let env = Environment::init(&display_proxy, SmithayClipboard::new());
|
let env = Environment::init(&display_proxy, SmithayClipboard::new());
|
||||||
let req = queue.sync_roundtrip(&mut (), |_, _, _| unreachable!());
|
let req = queue.sync_roundtrip(&mut (), |_, _, _| unreachable!());
|
||||||
let _ = req.and_then(|_| queue.sync_roundtrip(&mut (), |_, _, _| unreachable!())).unwrap();
|
let req = req.and_then(|_| queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()));
|
||||||
|
|
||||||
|
// We shouldn't crash the application if we've failed to dispatch.
|
||||||
|
if req.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get data device manager.
|
// Get data device manager.
|
||||||
let data_device_manager = env.get_global::<WlDataDeviceManager>();
|
let data_device_manager = env.get_global::<WlDataDeviceManager>();
|
||||||
|
|
@ -209,7 +214,12 @@ fn worker_impl(display: Display, request_rx: Receiver<Command>, reply_tx: Sender
|
||||||
// Reset the time we're sleeping.
|
// Reset the time we're sleeping.
|
||||||
sa_tracker.reset_sleep();
|
sa_tracker.reset_sleep();
|
||||||
|
|
||||||
queue.sync_roundtrip(&mut dispatch_data, |_, _, _| unimplemented!()).unwrap();
|
if queue.sync_roundtrip(&mut dispatch_data, |_, _, _| unimplemented!()).is_err() {
|
||||||
|
if request == Command::LoadPrimary || request == Command::Load {
|
||||||
|
handlers::reply_error(&reply_tx, "primary clipboard is not available.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get latest observed seat and serial.
|
// Get latest observed seat and serial.
|
||||||
let (seat, serial) = match dispatch_data.last_seat() {
|
let (seat, serial) = match dispatch_data.last_seat() {
|
||||||
|
|
@ -270,7 +280,10 @@ fn worker_impl(display: Display, request_rx: Receiver<Command>, reply_tx: Sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending_events = queue.dispatch_pending(&mut dispatch_data, |_, _, _| {}).unwrap();
|
let pending_events = match queue.dispatch_pending(&mut dispatch_data, |_, _, _| {}) {
|
||||||
|
Ok(pending_events) => pending_events,
|
||||||
|
Err(_) => break,
|
||||||
|
};
|
||||||
|
|
||||||
// If some application is trying to spam us when there're no seats, it's likely that
|
// If some application is trying to spam us when there're no seats, it's likely that
|
||||||
// someone is trying to paste from us.
|
// someone is trying to paste from us.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue