From 94e5c8fc05113e667a87c328ae7643a46ae2187a Mon Sep 17 00:00:00 2001 From: Timon Date: Sat, 29 Nov 2025 01:08:43 +0100 Subject: [PATCH] Desktop: Prevent CEF context menu to fix crashing by right-clicking a text field (#3429) * add dummy context menu handler to prevent some crashes * some cleanup correcting cef handler impl names using std::ffi::c_int --- desktop/src/cef/internal.rs | 8 +-- .../cef/internal/browser_process_client.rs | 15 +++-- .../cef/internal/browser_process_handler.rs | 2 +- .../src/cef/internal/context_menu_handler.rs | 66 +++++++++++++++++++ desktop/src/cef/internal/display_handler.rs | 11 +--- ...e_span_handler.rs => life_span_handler.rs} | 20 +++--- ...rocess_load_handler.rs => load_handler.rs} | 2 +- desktop/src/cef/internal/render_handler.rs | 4 +- .../cef/internal/render_process_handler.rs | 6 +- .../cef/internal/render_process_v8_handler.rs | 14 ++-- 10 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 desktop/src/cef/internal/context_menu_handler.rs rename desktop/src/cef/internal/{browser_process_life_span_handler.rs => life_span_handler.rs} (74%) rename desktop/src/cef/internal/{browser_process_load_handler.rs => load_handler.rs} (92%) diff --git a/desktop/src/cef/internal.rs b/desktop/src/cef/internal.rs index e07a28d2..a71e3089 100644 --- a/desktop/src/cef/internal.rs +++ b/desktop/src/cef/internal.rs @@ -1,18 +1,18 @@ mod browser_process_app; mod browser_process_client; mod browser_process_handler; -mod browser_process_life_span_handler; -mod browser_process_load_handler; mod render_process_app; mod render_process_handler; mod render_process_v8_handler; +mod context_menu_handler; +mod display_handler; +mod life_span_handler; +mod load_handler; mod resource_handler; mod scheme_handler_factory; -mod display_handler; - pub(super) mod render_handler; #[cfg(not(target_os = "macos"))] diff --git a/desktop/src/cef/internal/browser_process_client.rs b/desktop/src/cef/internal/browser_process_client.rs index 549373f5..5c7d1084 100644 --- a/desktop/src/cef/internal/browser_process_client.rs +++ b/desktop/src/cef/internal/browser_process_client.rs @@ -1,13 +1,14 @@ use cef::rc::{Rc, RcImpl}; use cef::sys::{_cef_client_t, cef_base_ref_counted_t}; -use cef::{DisplayHandler, ImplClient, LifeSpanHandler, LoadHandler, RenderHandler, WrapClient}; +use cef::{ContextMenuHandler, DisplayHandler, ImplClient, LifeSpanHandler, LoadHandler, RenderHandler, WrapClient}; use crate::cef::CefEventHandler; use crate::cef::ipc::{MessageType, UnpackMessage, UnpackedMessage}; -use super::browser_process_life_span_handler::BrowserProcessLifeSpanHandlerImpl; -use super::browser_process_load_handler::LoadHandlerImpl; +use super::context_menu_handler::ContextMenuHandlerImpl; use super::display_handler::DisplayHandlerImpl; +use super::life_span_handler::LifeSpanHandlerImpl; +use super::load_handler::LoadHandlerImpl; use super::render_handler::RenderHandlerImpl; pub(crate) struct BrowserProcessClientImpl { @@ -36,7 +37,7 @@ impl ImplClient for BrowserProcessClientImpl { _frame: Option<&mut cef::Frame>, _source_process: cef::ProcessId, message: Option<&mut cef::ProcessMessage>, - ) -> ::std::os::raw::c_int { + ) -> std::ffi::c_int { let unpacked_message = unsafe { message.and_then(|m| m.unpack()) }; match unpacked_message { Some(UnpackedMessage { @@ -65,13 +66,17 @@ impl ImplClient for BrowserProcessClientImpl { } fn life_span_handler(&self) -> Option { - Some(LifeSpanHandler::new(BrowserProcessLifeSpanHandlerImpl::new())) + Some(LifeSpanHandler::new(LifeSpanHandlerImpl::new())) } fn display_handler(&self) -> Option { Some(self.display_handler.clone()) } + fn context_menu_handler(&self) -> Option { + Some(ContextMenuHandler::new(ContextMenuHandlerImpl::new())) + } + fn get_raw(&self) -> *mut _cef_client_t { self.object.cast() } diff --git a/desktop/src/cef/internal/browser_process_handler.rs b/desktop/src/cef/internal/browser_process_handler.rs index 71c0e995..3560483b 100644 --- a/desktop/src/cef/internal/browser_process_handler.rs +++ b/desktop/src/cef/internal/browser_process_handler.rs @@ -24,7 +24,7 @@ impl ImplBrowserProcessHandler for BrowserProcessHandlerImpl self.event_handler.schedule_cef_message_loop_work(Instant::now() + Duration::from_millis(delay_ms as u64)); } - fn on_already_running_app_relaunch(&self, _command_line: Option<&mut cef::CommandLine>, _current_directory: Option<&CefString>) -> ::std::os::raw::c_int { + fn on_already_running_app_relaunch(&self, _command_line: Option<&mut cef::CommandLine>, _current_directory: Option<&CefString>) -> std::ffi::c_int { 1 // Return 1 to prevent default behavior of opening a empty browser window } diff --git a/desktop/src/cef/internal/context_menu_handler.rs b/desktop/src/cef/internal/context_menu_handler.rs new file mode 100644 index 00000000..e49cfd2f --- /dev/null +++ b/desktop/src/cef/internal/context_menu_handler.rs @@ -0,0 +1,66 @@ +use cef::rc::{Rc, RcImpl}; +use cef::sys::{_cef_context_menu_handler_t, cef_base_ref_counted_t}; +use cef::{ImplContextMenuHandler, WrapContextMenuHandler}; + +pub(crate) struct ContextMenuHandlerImpl { + object: *mut RcImpl<_cef_context_menu_handler_t, Self>, +} +impl ContextMenuHandlerImpl { + pub(crate) fn new() -> Self { + Self { object: std::ptr::null_mut() } + } +} + +impl ImplContextMenuHandler for ContextMenuHandlerImpl { + fn run_context_menu( + &self, + _browser: Option<&mut cef::Browser>, + _frame: Option<&mut cef::Frame>, + _params: Option<&mut cef::ContextMenuParams>, + _model: Option<&mut cef::MenuModel>, + _callback: Option<&mut cef::RunContextMenuCallback>, + ) -> std::ffi::c_int { + // Prevent context menu + 1 + } + + fn run_quick_menu( + &self, + _browser: Option<&mut cef::Browser>, + _frame: Option<&mut cef::Frame>, + _location: Option<&cef::Point>, + _size: Option<&cef::Size>, + _edit_state_flags: cef::QuickMenuEditStateFlags, + _callback: Option<&mut cef::RunQuickMenuCallback>, + ) -> std::ffi::c_int { + // Prevent quick menu + 1 + } + + fn get_raw(&self) -> *mut _cef_context_menu_handler_t { + self.object.cast() + } +} + +impl Clone for ContextMenuHandlerImpl { + fn clone(&self) -> Self { + unsafe { + let rc_impl = &mut *self.object; + rc_impl.interface.add_ref(); + } + Self { object: self.object } + } +} +impl Rc for ContextMenuHandlerImpl { + fn as_base(&self) -> &cef_base_ref_counted_t { + unsafe { + let base = &*self.object; + std::mem::transmute(&base.cef_object) + } + } +} +impl WrapContextMenuHandler for ContextMenuHandlerImpl { + fn wrap_rc(&mut self, object: *mut RcImpl<_cef_context_menu_handler_t, Self>) { + self.object = object; + } +} diff --git a/desktop/src/cef/internal/display_handler.rs b/desktop/src/cef/internal/display_handler.rs index a42d9815..2bc3b35b 100644 --- a/desktop/src/cef/internal/display_handler.rs +++ b/desktop/src/cef/internal/display_handler.rs @@ -25,7 +25,7 @@ type CefCursorHandle = cef::CursorHandle; type CefCursorHandle = *mut u8; impl ImplDisplayHandler for DisplayHandlerImpl { - fn on_cursor_change(&self, _browser: Option<&mut cef::Browser>, _cursor: CefCursorHandle, cursor_type: cef::CursorType, _custom_cursor_info: Option<&cef::CursorInfo>) -> ::std::os::raw::c_int { + fn on_cursor_change(&self, _browser: Option<&mut cef::Browser>, _cursor: CefCursorHandle, cursor_type: cef::CursorType, _custom_cursor_info: Option<&cef::CursorInfo>) -> std::ffi::c_int { let cursor = match cursor_type.into() { CT_POINTER => CursorIcon::Default, CT_CROSS => CursorIcon::Crosshair, @@ -86,14 +86,7 @@ impl ImplDisplayHandler for DisplayHandlerImpl { 1 // We handled the cursor change. } - fn on_console_message( - &self, - _browser: Option<&mut cef::Browser>, - level: cef::LogSeverity, - message: Option<&CefString>, - source: Option<&CefString>, - line: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int { + fn on_console_message(&self, _browser: Option<&mut cef::Browser>, level: cef::LogSeverity, message: Option<&CefString>, source: Option<&CefString>, line: std::ffi::c_int) -> std::ffi::c_int { let message = message.map(|m| m.to_string()).unwrap_or_default(); let source = source.map(|s| s.to_string()).unwrap_or_default(); let line = line as i64; diff --git a/desktop/src/cef/internal/browser_process_life_span_handler.rs b/desktop/src/cef/internal/life_span_handler.rs similarity index 74% rename from desktop/src/cef/internal/browser_process_life_span_handler.rs rename to desktop/src/cef/internal/life_span_handler.rs index 3fce0b5e..4a501cc0 100644 --- a/desktop/src/cef/internal/browser_process_life_span_handler.rs +++ b/desktop/src/cef/internal/life_span_handler.rs @@ -2,32 +2,32 @@ use cef::rc::{Rc, RcImpl}; use cef::sys::{_cef_life_span_handler_t, cef_base_ref_counted_t}; use cef::{ImplLifeSpanHandler, WrapLifeSpanHandler}; -pub(crate) struct BrowserProcessLifeSpanHandlerImpl { +pub(crate) struct LifeSpanHandlerImpl { object: *mut RcImpl<_cef_life_span_handler_t, Self>, } -impl BrowserProcessLifeSpanHandlerImpl { +impl LifeSpanHandlerImpl { pub(crate) fn new() -> Self { Self { object: std::ptr::null_mut() } } } -impl ImplLifeSpanHandler for BrowserProcessLifeSpanHandlerImpl { +impl ImplLifeSpanHandler for LifeSpanHandlerImpl { fn on_before_popup( &self, _browser: Option<&mut cef::Browser>, _frame: Option<&mut cef::Frame>, - _popup_id: ::std::os::raw::c_int, + _popup_id: std::ffi::c_int, target_url: Option<&cef::CefString>, _target_frame_name: Option<&cef::CefString>, _target_disposition: cef::WindowOpenDisposition, - _user_gesture: ::std::os::raw::c_int, + _user_gesture: std::ffi::c_int, _popup_features: Option<&cef::PopupFeatures>, _window_info: Option<&mut cef::WindowInfo>, _client: Option<&mut Option>, _settings: Option<&mut cef::BrowserSettings>, _extra_info: Option<&mut Option>, - _no_javascript_access: Option<&mut ::std::os::raw::c_int>, - ) -> ::std::os::raw::c_int { + _no_javascript_access: Option<&mut std::ffi::c_int>, + ) -> std::ffi::c_int { let target = target_url.map(|url| url.to_string()).unwrap_or("unknown".to_string()); tracing::error!("Browser tried to open a popup at URL: {}", target); @@ -40,7 +40,7 @@ impl ImplLifeSpanHandler for BrowserProcessLifeSpanHandlerImpl { } } -impl Clone for BrowserProcessLifeSpanHandlerImpl { +impl Clone for LifeSpanHandlerImpl { fn clone(&self) -> Self { unsafe { let rc_impl = &mut *self.object; @@ -49,7 +49,7 @@ impl Clone for BrowserProcessLifeSpanHandlerImpl { Self { object: self.object } } } -impl Rc for BrowserProcessLifeSpanHandlerImpl { +impl Rc for LifeSpanHandlerImpl { fn as_base(&self) -> &cef_base_ref_counted_t { unsafe { let base = &*self.object; @@ -57,7 +57,7 @@ impl Rc for BrowserProcessLifeSpanHandlerImpl { } } } -impl WrapLifeSpanHandler for BrowserProcessLifeSpanHandlerImpl { +impl WrapLifeSpanHandler for LifeSpanHandlerImpl { fn wrap_rc(&mut self, object: *mut RcImpl<_cef_life_span_handler_t, Self>) { self.object = object; } diff --git a/desktop/src/cef/internal/browser_process_load_handler.rs b/desktop/src/cef/internal/load_handler.rs similarity index 92% rename from desktop/src/cef/internal/browser_process_load_handler.rs rename to desktop/src/cef/internal/load_handler.rs index 92973a32..c23352ae 100644 --- a/desktop/src/cef/internal/browser_process_load_handler.rs +++ b/desktop/src/cef/internal/load_handler.rs @@ -18,7 +18,7 @@ impl LoadHandlerImpl { } impl ImplLoadHandler for LoadHandlerImpl { - fn on_loading_state_change(&self, browser: Option<&mut cef::Browser>, is_loading: ::std::os::raw::c_int, _can_go_back: ::std::os::raw::c_int, _can_go_forward: ::std::os::raw::c_int) { + fn on_loading_state_change(&self, browser: Option<&mut cef::Browser>, is_loading: std::ffi::c_int, _can_go_back: std::ffi::c_int, _can_go_forward: std::ffi::c_int) { let view_info = self.event_handler.view_info(); if let Some(browser) = browser diff --git a/desktop/src/cef/internal/render_handler.rs b/desktop/src/cef/internal/render_handler.rs index ff691b88..6d61b102 100644 --- a/desktop/src/cef/internal/render_handler.rs +++ b/desktop/src/cef/internal/render_handler.rs @@ -38,8 +38,8 @@ impl ImplRenderHandler for RenderHandlerImpl { _dirty_rect_count: usize, _dirty_rects: Option<&Rect>, buffer: *const u8, - width: ::std::os::raw::c_int, - height: ::std::os::raw::c_int, + width: std::ffi::c_int, + height: std::ffi::c_int, ) { let buffer_size = (width * height * 4) as usize; let buffer_slice = unsafe { std::slice::from_raw_parts(buffer, buffer_size) }; diff --git a/desktop/src/cef/internal/render_process_handler.rs b/desktop/src/cef/internal/render_process_handler.rs index 78feadc1..45ce66cf 100644 --- a/desktop/src/cef/internal/render_process_handler.rs +++ b/desktop/src/cef/internal/render_process_handler.rs @@ -4,7 +4,7 @@ use cef::{CefString, ImplFrame, ImplRenderProcessHandler, ImplV8Context, ImplV8V use crate::cef::ipc::{MessageType, UnpackMessage, UnpackedMessage}; -use super::render_process_v8_handler::BrowserProcessV8HandlerImpl; +use super::render_process_v8_handler::RenderProcessV8HandlerImpl; pub(crate) struct RenderProcessHandlerImpl { object: *mut RcImpl, @@ -22,7 +22,7 @@ impl ImplRenderProcessHandler for RenderProcessHandlerImpl { frame: Option<&mut cef::Frame>, _source_process: cef::ProcessId, message: Option<&mut cef::ProcessMessage>, - ) -> ::std::os::raw::c_int { + ) -> std::ffi::c_int { let unpacked_message = unsafe { message.and_then(|m| m.unpack()) }; match unpacked_message { Some(UnpackedMessage { @@ -77,7 +77,7 @@ impl ImplRenderProcessHandler for RenderProcessHandlerImpl { fn on_context_created(&self, _browser: Option<&mut cef::Browser>, _frame: Option<&mut cef::Frame>, context: Option<&mut cef::V8Context>) { let register_js_function = |context: &mut cef::V8Context, name: &'static str| { - let mut v8_handler = V8Handler::new(BrowserProcessV8HandlerImpl::new()); + let mut v8_handler = V8Handler::new(RenderProcessV8HandlerImpl::new()); let Some(mut function) = v8_value_create_function(Some(&CefString::from(name)), Some(&mut v8_handler)) else { tracing::error!("Failed to create V8 function {name}"); return; diff --git a/desktop/src/cef/internal/render_process_v8_handler.rs b/desktop/src/cef/internal/render_process_v8_handler.rs index 0ea935a1..2ff18e47 100644 --- a/desktop/src/cef/internal/render_process_v8_handler.rs +++ b/desktop/src/cef/internal/render_process_v8_handler.rs @@ -2,16 +2,16 @@ use cef::{ImplV8Handler, ImplV8Value, V8Value, WrapV8Handler, rc::Rc, v8_context use crate::cef::ipc::{MessageType, SendMessage}; -pub struct BrowserProcessV8HandlerImpl { +pub struct RenderProcessV8HandlerImpl { object: *mut cef::rc::RcImpl, } -impl BrowserProcessV8HandlerImpl { +impl RenderProcessV8HandlerImpl { pub(crate) fn new() -> Self { Self { object: std::ptr::null_mut() } } } -impl ImplV8Handler for BrowserProcessV8HandlerImpl { +impl ImplV8Handler for RenderProcessV8HandlerImpl { fn execute( &self, name: Option<&cef::CefString>, @@ -19,7 +19,7 @@ impl ImplV8Handler for BrowserProcessV8HandlerImpl { arguments: Option<&[Option]>, _retval: Option<&mut Option>, _exception: Option<&mut cef::CefString>, - ) -> ::std::os::raw::c_int { + ) -> std::ffi::c_int { match name.map(|s| s.to_string()).unwrap_or_default().as_str() { "initializeNativeCommunication" => { v8_context_get_current_context().send_message(MessageType::Initialized, vec![0u8].as_slice()); @@ -62,7 +62,7 @@ impl ImplV8Handler for BrowserProcessV8HandlerImpl { } } -impl Clone for BrowserProcessV8HandlerImpl { +impl Clone for RenderProcessV8HandlerImpl { fn clone(&self) -> Self { unsafe { let rc_impl = &mut *self.object; @@ -71,7 +71,7 @@ impl Clone for BrowserProcessV8HandlerImpl { Self { object: self.object } } } -impl Rc for BrowserProcessV8HandlerImpl { +impl Rc for RenderProcessV8HandlerImpl { fn as_base(&self) -> &cef::sys::cef_base_ref_counted_t { unsafe { let base = &*self.object; @@ -79,7 +79,7 @@ impl Rc for BrowserProcessV8HandlerImpl { } } } -impl WrapV8Handler for BrowserProcessV8HandlerImpl { +impl WrapV8Handler for RenderProcessV8HandlerImpl { fn wrap_rc(&mut self, object: *mut cef::rc::RcImpl) { self.object = object; }