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
This commit is contained in:
Timon 2025-11-29 01:08:43 +01:00 committed by GitHub
parent bb4516e377
commit 94e5c8fc05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 106 additions and 42 deletions

View File

@ -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"))]

View File

@ -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<H: CefEventHandler> {
@ -36,7 +37,7 @@ impl<H: CefEventHandler> ImplClient for BrowserProcessClientImpl<H> {
_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<H: CefEventHandler> ImplClient for BrowserProcessClientImpl<H> {
}
fn life_span_handler(&self) -> Option<cef::LifeSpanHandler> {
Some(LifeSpanHandler::new(BrowserProcessLifeSpanHandlerImpl::new()))
Some(LifeSpanHandler::new(LifeSpanHandlerImpl::new()))
}
fn display_handler(&self) -> Option<cef::DisplayHandler> {
Some(self.display_handler.clone())
}
fn context_menu_handler(&self) -> Option<cef::ContextMenuHandler> {
Some(ContextMenuHandler::new(ContextMenuHandlerImpl::new()))
}
fn get_raw(&self) -> *mut _cef_client_t {
self.object.cast()
}

View File

@ -24,7 +24,7 @@ impl<H: CefEventHandler> 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
}

View File

@ -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;
}
}

View File

@ -25,7 +25,7 @@ type CefCursorHandle = cef::CursorHandle;
type CefCursorHandle = *mut u8;
impl<H: CefEventHandler> ImplDisplayHandler for DisplayHandlerImpl<H> {
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<H: CefEventHandler> ImplDisplayHandler for DisplayHandlerImpl<H> {
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;

View File

@ -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<cef::Client>>,
_settings: Option<&mut cef::BrowserSettings>,
_extra_info: Option<&mut Option<cef::DictionaryValue>>,
_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;
}

View File

@ -18,7 +18,7 @@ impl<H: CefEventHandler> LoadHandlerImpl<H> {
}
impl<H: CefEventHandler> ImplLoadHandler for LoadHandlerImpl<H> {
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

View File

@ -38,8 +38,8 @@ impl<H: CefEventHandler> ImplRenderHandler for RenderHandlerImpl<H> {
_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) };

View File

@ -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<cef_render_process_handler_t, Self>,
@ -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;

View File

@ -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<cef::sys::_cef_v8_handler_t, Self>,
}
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<V8Value>]>,
_retval: Option<&mut Option<V8Value>>,
_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<cef::sys::_cef_v8_handler_t, Self>) {
self.object = object;
}