From 6766d91af32bb7265ba4362317ed497cf523412a Mon Sep 17 00:00:00 2001 From: Federico Terzi <federicoterzi96@gmail.com> Date: Mon, 22 Jun 2020 19:09:51 +0200 Subject: [PATCH] Prevent espanso crash when an X11 exception occurs. Fix #312 --- native/liblinuxbridge/bridge.cpp | 14 ++++++++++++++ native/liblinuxbridge/bridge.h | 12 +++++++++++- src/bridge/linux.rs | 3 +++ src/context/linux.rs | 12 +++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/native/liblinuxbridge/bridge.cpp b/native/liblinuxbridge/bridge.cpp index 99f13e9..ec31d09 100644 --- a/native/liblinuxbridge/bridge.cpp +++ b/native/liblinuxbridge/bridge.cpp @@ -77,14 +77,20 @@ xdo_t * xdo_context; // Callback invoked when a new key event occur. void event_callback (XPointer, XRecordInterceptData*); +int error_callback(Display *display, XErrorEvent *error); KeypressCallback keypress_callback; +X11ErrorCallback x11_error_callback; void * context_instance; void register_keypress_callback(KeypressCallback callback) { keypress_callback = callback; } +void register_error_callback(X11ErrorCallback callback) { + x11_error_callback = callback; +} + int32_t check_x11() { Display *check_disp = XOpenDisplay(NULL); @@ -156,6 +162,9 @@ int32_t initialize(void * _context_instance) { xdo_context = xdo_new(NULL); + // Setup a custom error handler + XSetErrorHandler(&error_callback); + /** * Note: We might never get a MappingNotify event if the * modifier and keymap information was never cached in Xlib. @@ -272,6 +281,11 @@ void event_callback(XPointer p, XRecordInterceptData *hook) XRecordFreeData(hook); } +int error_callback(Display *display, XErrorEvent *error) { + x11_error_callback(context_instance, error->error_code, error->request_code, error->minor_code); + return 0; +} + void release_all_keys() { char keys[32]; XQueryKeymap(xdo_context->xdpy, keys); // Get the current status of the keyboard diff --git a/native/liblinuxbridge/bridge.h b/native/liblinuxbridge/bridge.h index 5e2c359..5102d0c 100644 --- a/native/liblinuxbridge/bridge.h +++ b/native/liblinuxbridge/bridge.h @@ -49,7 +49,6 @@ extern "C" void cleanup(); * while the second is the size of the array. */ typedef void (*KeypressCallback)(void * self, const char *buffer, int32_t len, int32_t event_type, int32_t key_code); - extern KeypressCallback keypress_callback; /* @@ -57,6 +56,17 @@ extern KeypressCallback keypress_callback; */ extern "C" void register_keypress_callback(KeypressCallback callback); +/* + * Called when a X11 error occurs + */ +typedef void (*X11ErrorCallback)(void * self, char error_code, char request_code, char minor_code); +extern X11ErrorCallback x11_error_callback; + +/* + * Register the callback that will be called when an X11 error occurs + */ +extern "C" void register_error_callback(X11ErrorCallback callback); + /* * Type the given string by simulating Key Presses */ diff --git a/src/bridge/linux.rs b/src/bridge/linux.rs index ef04d27..d7ceede 100644 --- a/src/bridge/linux.rs +++ b/src/bridge/linux.rs @@ -32,6 +32,9 @@ extern "C" { pub fn get_active_window_class(buffer: *mut c_char, size: i32) -> i32; pub fn get_active_window_executable(buffer: *mut c_char, size: i32) -> i32; pub fn is_current_window_special() -> i32; + pub fn register_error_callback( + cb: extern "C" fn(_self: *mut c_void, error_code: c_char, request_code: c_char, minor_code: c_char), + ); // Keyboard pub fn register_keypress_callback( diff --git a/src/context/linux.rs b/src/context/linux.rs index 6a4ddb1..c1acae9 100644 --- a/src/context/linux.rs +++ b/src/context/linux.rs @@ -21,7 +21,7 @@ use crate::bridge::linux::*; use crate::config::Configs; use crate::event::KeyModifier::*; use crate::event::*; -use log::{debug, error}; +use log::{debug, error, warn}; use std::ffi::CStr; use std::os::raw::{c_char, c_void}; use std::process::exit; @@ -59,6 +59,7 @@ impl LinuxContext { let context_ptr = &*context as *const LinuxContext as *const c_void; register_keypress_callback(keypress_callback); + register_error_callback(error_callback); let res = initialize(context_ptr); if res <= 0 { @@ -155,3 +156,12 @@ extern "C" fn keypress_callback( } } } + +extern "C" fn error_callback( + _self: *mut c_void, + error_code: c_char, + request_code: c_char, + minor_code: c_char, +) { + warn!("X11 reported an error code: {}, request_code: {} and minor_code: {}", error_code, request_code, minor_code); +}