From d0ec997aad04f496614cabf3eed9dbaba4d57342 Mon Sep 17 00:00:00 2001 From: NikitaSkrynnik Date: Wed, 12 Mar 2025 18:11:26 +1100 Subject: [PATCH 1/2] add display handler Signed-off-by: NikitaSkrynnik --- crates/cef-ui/src/client.rs | 18 +- crates/cef-ui/src/display_handler.rs | 311 +++++++++++++++++++++++++++ crates/cef-ui/src/lib.rs | 2 + crates/cef-ui/src/types.rs | 227 ++++++++++++++++++- 4 files changed, 545 insertions(+), 13 deletions(-) create mode 100644 crates/cef-ui/src/display_handler.rs diff --git a/crates/cef-ui/src/client.rs b/crates/cef-ui/src/client.rs index c6fecfc..6afb507 100644 --- a/crates/cef-ui/src/client.rs +++ b/crates/cef-ui/src/client.rs @@ -1,6 +1,6 @@ use crate::{ - keyboard_handler::KeyboardHandler, ref_counted_ptr, ContextMenuHandler, LifeSpanHandler, - RefCountedPtr, RenderHandler, Wrappable, Wrapped + ContextMenuHandler, DisplayHandler, LifeSpanHandler, RefCountedPtr, RenderHandler, Wrappable, + Wrapped, keyboard_handler::KeyboardHandler, ref_counted_ptr }; use cef_ui_sys::{ cef_audio_handler_t, cef_browser_t, cef_client_t, cef_command_handler_t, @@ -34,9 +34,8 @@ pub trait ClientCallbacks: Send + Sync + 'static { // struct _cef_dialog_handler_t*(CEF_CALLBACK* get_dialog_handler)( // struct _cef_client_t* self); - // /// Return the handler for browser display state events. - // struct _cef_display_handler_t*(CEF_CALLBACK* get_display_handler)( - // struct _cef_client_t* self); + /// Return the handler for browser display state events. + fn get_display_handler(&mut self) -> Option; // /// Return the handler for download events. If no handler is returned // /// downloads will not be allowed. @@ -162,7 +161,12 @@ impl ClientWrapper { unsafe extern "C" fn c_get_display_handler( this: *mut cef_client_t ) -> *mut cef_display_handler_t { - todo!() + let this: &mut Self = Wrapped::wrappable(this); + + this.0 + .get_display_handler() + .map(|handler| handler.into_raw()) + .unwrap_or(null_mut()) } /// Return the handler for download events. If no handler is returned @@ -292,7 +296,7 @@ impl Wrappable for ClientWrapper { get_command_handler: None, get_context_menu_handler: Some(Self::c_get_context_menu_handler), get_dialog_handler: None, - get_display_handler: None, + get_display_handler: Some(Self::c_get_display_handler), get_download_handler: None, get_drag_handler: None, get_find_handler: None, diff --git a/crates/cef-ui/src/display_handler.rs b/crates/cef-ui/src/display_handler.rs new file mode 100644 index 0000000..d66db29 --- /dev/null +++ b/crates/cef-ui/src/display_handler.rs @@ -0,0 +1,311 @@ +use crate::{ + Browser, CefString, CursorInfo, CursorType, Frame, LogSeverity, RefCountedPtr, Size, Wrappable, + Wrapped, ref_counted_ptr +}; +use cef_ui_sys::{ + cef_browser_t, cef_cursor_info_t, cef_cursor_type_t, cef_display_handler_t, cef_frame_t, + cef_log_severity_t, cef_size_t, cef_string_list_t, cef_string_t +}; +use std::{ffi::c_int, mem::zeroed}; + +pub trait DisplayHandlerCallbacks: Send + Sync + 'static { + /// Called when a frame's address has changed. + fn on_address_change(&mut self, browser: Browser, frame: Frame, url: &str); + + /// Called when the page title changes. + fn on_title_change(&mut self, browser: Browser, title: &str); + + /// Called when the page icon changes. + fn on_favicon_urlchange(&mut self, browser: Browser, icon_urls: Vec); + + /// Called when web content in the page has toggled fullscreen mode. If + /// |fullscreen| is true (1) the content will automatically be sized to fill + /// the browser content area. If |fullscreen| is false (0) the content will + /// automatically return to its original size and position. With Alloy style + /// the client is responsible for triggering the fullscreen transition (for + /// example, by calling cef_window_t::SetFullscreen when using Views). With + /// Chrome style the fullscreen transition will be triggered automatically. + /// The cef_window_delegate_t::OnWindowFullscreenTransition function will be + /// called during the fullscreen transition for notification purposes. + fn on_fullscreen_mode_change(&mut self, browser: Browser, fullscreen: bool); + + /// Called when the browser is about to display a tooltip. |text| contains the + /// text that will be displayed in the tooltip. To handle the display of the + /// tooltip yourself return true (1). Otherwise, you can optionally modify + /// |text| and then return false (0) to allow the browser to display the + /// tooltip. When window rendering is disabled the application is responsible + /// for drawing tooltips and the return value is ignored. + fn on_tooltip(&mut self, browser: Browser, text: Option) -> bool; + + /// Called when the browser receives a status message. |value| contains the + /// text that will be displayed in the status message. + fn on_status_message(&mut self, browser: Browser, value: Option); + + /// Called to display a console message. Return true (1) to stop the message + /// from being output to the console. + fn on_console_message( + &mut self, + browser: Browser, + level: LogSeverity, + message: Option, + source: Option, + line: i32 + ) -> bool; + + /// Called when auto-resize is enabled via + /// cef_browser_host_t::SetAutoResizeEnabled and the contents have auto- + /// resized. |new_size| will be the desired size in view coordinates. Return + /// true (1) if the resize was handled or false (0) for default handling. + fn on_auto_resize(&mut self, browser: Browser, new_size: &Size) -> bool; + + /// Called when the overall page loading progress has changed. |progress| + /// ranges from 0.0 to 1.0. + fn on_loading_progress_change(&mut self, browser: Browser, progress: f64); + + /// Called when the browser's cursor has changed. If |type| is CT_CUSTOM then + /// |custom_cursor_info| will be populated with the custom cursor information. + /// Return true (1) if the cursor change was handled or false (0) for default + /// handling. + fn on_cursor_change( + &mut self, + browser: Browser, + cursor: u64, + cursor_type: CursorType, + custom_cursor_info: Option + ) -> bool; + + /// Called when the browser's access to an audio and/or video source has + /// changed. + fn on_media_access_change(&mut self, browser: Browser, has_video: bool, has_audio: bool); +} + +ref_counted_ptr!(DisplayHandler, cef_display_handler_t); + +impl DisplayHandler { + pub fn new(delegate: C) -> Self { + Self(DisplayHandlerWrapper::new(delegate).wrap()) + } +} + +struct DisplayHandlerWrapper(Box); + +impl DisplayHandlerWrapper { + pub fn new(delegate: C) -> Self { + Self(Box::new(delegate)) + } + + /// Called when a frame's address has changed. + unsafe extern "C" fn c_on_address_change( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + frame: *mut cef_frame_t, + url: *const cef_string_t + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + let frame = Frame::from_ptr_unchecked(frame); + let url: String = CefString::from_ptr_unchecked(url).into(); + + this.0 + .on_address_change(browser, frame, &url); + } + + /// Called when the page title changes. + unsafe extern "C" fn c_on_title_change( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + title: *const cef_string_t + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + let title: String = CefString::from_ptr_unchecked(title).into(); + + this.0 + .on_title_change(browser, &title); + } + + /// Called when the page icon changes. + unsafe extern "C" fn c_on_favicon_urlchange( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + _icon_urls: cef_string_list_t + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + // TODO: For some reason this line crashes CEF (Trace/breakpoint trap (core dumped)) + // let icon_urls = CefStringList::from_ptr(icon_urls).map_or(Vec::new(), |s| s.into()); + let icon_urls = Vec::new(); + + this.0 + .on_favicon_urlchange(browser, icon_urls); + } + + /// Called when web content in the page has toggled fullscreen mode. If + /// |fullscreen| is true (1) the content will automatically be sized to fill + /// the browser content area. If |fullscreen| is false (0) the content will + /// automatically return to its original size and position. With Alloy style + /// the client is responsible for triggering the fullscreen transition (for + /// example, by calling cef_window_t::SetFullscreen when using Views). With + /// Chrome style the fullscreen transition will be triggered automatically. + /// The cef_window_delegate_t::OnWindowFullscreenTransition function will be + /// called during the fullscreen transition for notification purposes. + unsafe extern "C" fn c_on_fullscreen_mode_change( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + fullscreen: c_int + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + + this.0 + .on_fullscreen_mode_change(browser, fullscreen != 0); + } + + /// Called when the browser is about to display a tooltip. |text| contains the + /// text that will be displayed in the tooltip. To handle the display of the + /// tooltip yourself return true (1). Otherwise, you can optionally modify + /// |text| and then return false (0) to allow the browser to display the + /// tooltip. When window rendering is disabled the application is responsible + /// for drawing tooltips and the return value is ignored. + unsafe extern "C" fn c_on_tooltip( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + text: *mut cef_string_t + ) -> ::std::os::raw::c_int { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + let text: Option = CefString::from_ptr(text).map(|s| s.into()); + + this.0.on_tooltip(browser, text) as ::std::os::raw::c_int + } + + /// Called when the browser receives a status message. |value| contains the + /// text that will be displayed in the status message. + unsafe extern "C" fn c_on_status_message( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + value: *const cef_string_t + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + let value: Option = CefString::from_ptr(value).map(|s| s.into()); + + this.0 + .on_status_message(browser, value); + } + + /// Called to display a console message. Return true (1) to stop the message + /// from being output to the console. + unsafe extern "C" fn c_on_console_message( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + level: cef_log_severity_t, + message: *const cef_string_t, + source: *const cef_string_t, + line: ::std::os::raw::c_int + ) -> ::std::os::raw::c_int { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + let message: Option = CefString::from_ptr(message).map(|s| s.into()); + let source: Option = CefString::from_ptr(source).map(|s| s.into()); + + this.0 + .on_console_message(browser, level.into(), message, source, line) + as ::std::os::raw::c_int + } + + /// Called when auto-resize is enabled via + /// cef_browser_host_t::SetAutoResizeEnabled and the contents have auto- + /// resized. |new_size| will be the desired size in view coordinates. Return + /// true (1) if the resize was handled or false (0) for default handling. + unsafe extern "C" fn c_on_auto_resize( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + new_size: *const cef_size_t + ) -> ::std::os::raw::c_int { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + + let new_size: Size = (*new_size).into(); + this.0 + .on_auto_resize(browser, &new_size) as ::std::os::raw::c_int + } + + /// Called when the overall page loading progress has changed. |progress| + /// ranges from 0.0 to 1.0. + unsafe extern "C" fn c_on_loading_progress_change( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + progress: f64 + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + + this.0 + .on_loading_progress_change(browser, progress); + } + + /// Called when the browser's cursor has changed. If |type| is CT_CUSTOM then + /// |custom_cursor_info| will be populated with the custom cursor information. + /// Return true (1) if the cursor change was handled or false (0) for default + /// handling. + unsafe extern "C" fn c_on_cursor_change( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + cursor: ::std::os::raw::c_ulong, + cursor_type: cef_cursor_type_t, + custom_cursor_info: *const cef_cursor_info_t + ) -> ::std::os::raw::c_int { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + let cursor_type: CursorType = cursor_type.into(); + let custom_cursor_info: Option = if cursor_type == CursorType::Custom { + Some((*custom_cursor_info).into()) + } else { + None + }; + + this.0 + .on_cursor_change(browser, cursor, cursor_type, custom_cursor_info) + as ::std::os::raw::c_int + } + + /// Called when the browser's access to an audio and/or video source has + /// changed. + unsafe extern "C" fn c_on_media_access_change( + this: *mut cef_display_handler_t, + browser: *mut cef_browser_t, + has_video_access: ::std::os::raw::c_int, + has_audio_access: ::std::os::raw::c_int + ) { + let this: &mut Self = Wrapped::wrappable(this); + let browser = Browser::from_ptr_unchecked(browser); + + this.0 + .on_media_access_change(browser, has_video_access != 0, has_audio_access != 0); + } +} + +impl Wrappable for DisplayHandlerWrapper { + type Cef = cef_display_handler_t; + + fn wrap(self) -> RefCountedPtr { + RefCountedPtr::wrap( + cef_display_handler_t { + base: unsafe { zeroed() }, + on_address_change: Some(Self::c_on_address_change), + on_title_change: Some(Self::c_on_title_change), + on_favicon_urlchange: Some(Self::c_on_favicon_urlchange), + on_fullscreen_mode_change: Some(Self::c_on_fullscreen_mode_change), + on_tooltip: Some(Self::c_on_tooltip), + on_status_message: Some(Self::c_on_status_message), + on_console_message: Some(Self::c_on_console_message), + on_auto_resize: Some(Self::c_on_auto_resize), + on_loading_progress_change: Some(Self::c_on_loading_progress_change), + on_cursor_change: Some(Self::c_on_cursor_change), + on_media_access_change: Some(Self::c_on_media_access_change) + }, + self + ) + } +} diff --git a/crates/cef-ui/src/lib.rs b/crates/cef-ui/src/lib.rs index 756feb6..5ffe743 100644 --- a/crates/cef-ui/src/lib.rs +++ b/crates/cef-ui/src/lib.rs @@ -8,6 +8,7 @@ mod color; mod command_line; mod context; mod context_menu_handler; +mod display_handler; mod drag; mod events; mod extension; @@ -48,6 +49,7 @@ pub use color::*; pub use command_line::*; pub use context::*; pub use context_menu_handler::*; +pub use display_handler::*; pub use drag::*; pub use events::*; pub use extension::*; diff --git a/crates/cef-ui/src/types.rs b/crates/cef-ui/src/types.rs index e2dda99..3cc269d 100644 --- a/crates/cef-ui/src/types.rs +++ b/crates/cef-ui/src/types.rs @@ -1,17 +1,20 @@ use bitflags::bitflags; use cef_ui_sys::{ - cef_errorcode_t, cef_horizontal_alignment_t, cef_insets_t, cef_log_items_t, cef_log_severity_t, - cef_paint_element_type_t, cef_point_t, cef_range_t, cef_rect_t, cef_referrer_policy_t, - cef_resource_type_t, cef_screen_info_t, cef_size_t, cef_state_t, cef_termination_status_t, - cef_text_input_mode_t, cef_touch_handle_state_flags_t, - cef_touch_handle_state_flags_t_CEF_THS_FLAG_ALPHA, + cef_cursor_info_t, cef_cursor_type_t, cef_errorcode_t, cef_horizontal_alignment_t, + cef_insets_t, cef_log_items_t, cef_log_severity_t, cef_paint_element_type_t, cef_point_t, + cef_range_t, cef_rect_t, cef_referrer_policy_t, cef_resource_type_t, cef_screen_info_t, + cef_size_t, cef_state_t, cef_termination_status_t, cef_text_input_mode_t, + cef_touch_handle_state_flags_t, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ALPHA, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ENABLED, cef_touch_handle_state_flags_t_CEF_THS_FLAG_NONE, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ORIENTATION, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ORIGIN, cef_touch_handle_state_t, cef_window_open_disposition_t, cef_zoom_command_t }; -use std::ffi::c_int; +use std::{ + ffi::{c_int, c_void}, + slice::from_raw_parts +}; /// These are #define's and cannot be generated by bindgen. /// They are lifted from include/chrome_command_ids.h. @@ -3113,3 +3116,215 @@ impl From<&TouchHandleState> for cef_touch_handle_state_t { } } } + +/// Represents different types of cursor types in CEF. +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(u32)] +pub enum CursorType { + Pointer = 0, + Cross = 1, + Hand = 2, + IBeam = 3, + Wait = 4, + Help = 5, + EastResize = 6, + NorthResize = 7, + NorthEastResize = 8, + NorthWestResize = 9, + SouthResize = 10, + SouthEastResize = 11, + SouthWestResize = 12, + WestResize = 13, + NorthSouthResize = 14, + EastWestResize = 15, + NorthEastSouthWestResize = 16, + NorthWestSouthEastResize = 17, + ColumnResize = 18, + RowResize = 19, + MiddlePanning = 20, + EastPanning = 21, + NorthPanning = 22, + NorthEastPanning = 23, + NorthWestPanning = 24, + SouthPanning = 25, + SouthEastPanning = 26, + SouthWestPanning = 27, + WestPanning = 28, + Move = 29, + VerticalText = 30, + Cell = 31, + ContextMenu = 32, + Alias = 33, + Progress = 34, + NoDrop = 35, + Copy = 36, + None = 37, + NotAllowed = 38, + ZoomIn = 39, + ZoomOut = 40, + Grab = 41, + Grabbing = 42, + MiddlePanningVertical = 43, + MiddlePanningHorizontal = 44, + Custom = 45, + DndNone = 46, + DndMove = 47, + DndCopy = 48, + DndLink = 49 +} + +impl From for CursorType { + fn from(value: cef_cursor_type_t) -> Self { + match value { + cef_cursor_type_t::CT_POINTER => Self::Pointer, + cef_cursor_type_t::CT_CROSS => Self::Cross, + cef_cursor_type_t::CT_HAND => Self::Hand, + cef_cursor_type_t::CT_IBEAM => Self::IBeam, + cef_cursor_type_t::CT_WAIT => Self::Wait, + cef_cursor_type_t::CT_HELP => Self::Help, + cef_cursor_type_t::CT_EASTRESIZE => Self::EastResize, + cef_cursor_type_t::CT_NORTHRESIZE => Self::NorthResize, + cef_cursor_type_t::CT_NORTHEASTRESIZE => Self::NorthEastResize, + cef_cursor_type_t::CT_NORTHWESTRESIZE => Self::NorthWestResize, + cef_cursor_type_t::CT_SOUTHRESIZE => Self::SouthResize, + cef_cursor_type_t::CT_SOUTHEASTRESIZE => Self::SouthEastResize, + cef_cursor_type_t::CT_SOUTHWESTRESIZE => Self::SouthWestResize, + cef_cursor_type_t::CT_WESTRESIZE => Self::WestResize, + cef_cursor_type_t::CT_NORTHSOUTHRESIZE => Self::NorthSouthResize, + cef_cursor_type_t::CT_EASTWESTRESIZE => Self::EastWestResize, + cef_cursor_type_t::CT_NORTHEASTSOUTHWESTRESIZE => Self::NorthEastSouthWestResize, + cef_cursor_type_t::CT_NORTHWESTSOUTHEASTRESIZE => Self::NorthWestSouthEastResize, + cef_cursor_type_t::CT_COLUMNRESIZE => Self::ColumnResize, + cef_cursor_type_t::CT_ROWRESIZE => Self::RowResize, + cef_cursor_type_t::CT_MIDDLEPANNING => Self::MiddlePanning, + cef_cursor_type_t::CT_EASTPANNING => Self::EastPanning, + cef_cursor_type_t::CT_NORTHPANNING => Self::NorthPanning, + cef_cursor_type_t::CT_NORTHEASTPANNING => Self::NorthEastPanning, + cef_cursor_type_t::CT_NORTHWESTPANNING => Self::NorthWestPanning, + cef_cursor_type_t::CT_SOUTHPANNING => Self::SouthPanning, + cef_cursor_type_t::CT_SOUTHEASTPANNING => Self::SouthEastPanning, + cef_cursor_type_t::CT_SOUTHWESTPANNING => Self::SouthWestPanning, + cef_cursor_type_t::CT_WESTPANNING => Self::WestPanning, + cef_cursor_type_t::CT_MOVE => Self::Move, + cef_cursor_type_t::CT_VERTICALTEXT => Self::VerticalText, + cef_cursor_type_t::CT_CELL => Self::Cell, + cef_cursor_type_t::CT_CONTEXTMENU => Self::ContextMenu, + cef_cursor_type_t::CT_ALIAS => Self::Alias, + cef_cursor_type_t::CT_PROGRESS => Self::Progress, + cef_cursor_type_t::CT_NODROP => Self::NoDrop, + cef_cursor_type_t::CT_COPY => Self::Copy, + cef_cursor_type_t::CT_NONE => Self::None, + cef_cursor_type_t::CT_NOTALLOWED => Self::NotAllowed, + cef_cursor_type_t::CT_ZOOMIN => Self::ZoomIn, + cef_cursor_type_t::CT_ZOOMOUT => Self::ZoomOut, + cef_cursor_type_t::CT_GRAB => Self::Grab, + cef_cursor_type_t::CT_GRABBING => Self::Grabbing, + cef_cursor_type_t::CT_MIDDLE_PANNING_VERTICAL => Self::MiddlePanningVertical, + cef_cursor_type_t::CT_MIDDLE_PANNING_HORIZONTAL => Self::MiddlePanningHorizontal, + cef_cursor_type_t::CT_CUSTOM => Self::Custom, + cef_cursor_type_t::CT_DND_NONE => Self::DndNone, + cef_cursor_type_t::CT_DND_MOVE => Self::DndMove, + cef_cursor_type_t::CT_DND_COPY => Self::DndCopy, + cef_cursor_type_t::CT_DND_LINK => Self::DndLink + } + } +} + +impl From for cef_cursor_type_t { + fn from(value: CursorType) -> Self { + match value { + CursorType::Pointer => Self::CT_POINTER, + CursorType::Cross => Self::CT_CROSS, + CursorType::Hand => Self::CT_HAND, + CursorType::IBeam => Self::CT_IBEAM, + CursorType::Wait => Self::CT_WAIT, + CursorType::Help => Self::CT_HELP, + CursorType::EastResize => Self::CT_EASTRESIZE, + CursorType::NorthResize => Self::CT_NORTHRESIZE, + CursorType::NorthEastResize => Self::CT_NORTHEASTRESIZE, + CursorType::NorthWestResize => Self::CT_NORTHWESTRESIZE, + CursorType::SouthResize => Self::CT_SOUTHRESIZE, + CursorType::SouthEastResize => Self::CT_SOUTHEASTRESIZE, + CursorType::SouthWestResize => Self::CT_SOUTHWESTRESIZE, + CursorType::WestResize => Self::CT_WESTRESIZE, + CursorType::NorthSouthResize => Self::CT_NORTHSOUTHRESIZE, + CursorType::EastWestResize => Self::CT_EASTWESTRESIZE, + CursorType::NorthEastSouthWestResize => Self::CT_NORTHEASTSOUTHWESTRESIZE, + CursorType::NorthWestSouthEastResize => Self::CT_NORTHWESTSOUTHEASTRESIZE, + CursorType::ColumnResize => Self::CT_COLUMNRESIZE, + CursorType::RowResize => Self::CT_ROWRESIZE, + CursorType::MiddlePanning => Self::CT_MIDDLEPANNING, + CursorType::EastPanning => Self::CT_EASTPANNING, + CursorType::NorthPanning => Self::CT_NORTHPANNING, + CursorType::NorthEastPanning => Self::CT_NORTHEASTPANNING, + CursorType::NorthWestPanning => Self::CT_NORTHWESTPANNING, + CursorType::SouthPanning => Self::CT_SOUTHPANNING, + CursorType::SouthEastPanning => Self::CT_SOUTHEASTPANNING, + CursorType::SouthWestPanning => Self::CT_SOUTHWESTPANNING, + CursorType::WestPanning => Self::CT_WESTPANNING, + CursorType::Move => Self::CT_MOVE, + CursorType::VerticalText => Self::CT_VERTICALTEXT, + CursorType::Cell => Self::CT_CELL, + CursorType::ContextMenu => Self::CT_CONTEXTMENU, + CursorType::Alias => Self::CT_ALIAS, + CursorType::Progress => Self::CT_PROGRESS, + CursorType::NoDrop => Self::CT_NODROP, + CursorType::Copy => Self::CT_COPY, + CursorType::None => Self::CT_NONE, + CursorType::NotAllowed => Self::CT_NOTALLOWED, + CursorType::ZoomIn => Self::CT_ZOOMIN, + CursorType::ZoomOut => Self::CT_ZOOMOUT, + CursorType::Grab => Self::CT_GRAB, + CursorType::Grabbing => Self::CT_GRABBING, + CursorType::MiddlePanningVertical => Self::CT_MIDDLE_PANNING_VERTICAL, + CursorType::MiddlePanningHorizontal => Self::CT_MIDDLE_PANNING_HORIZONTAL, + CursorType::Custom => Self::CT_CUSTOM, + CursorType::DndNone => Self::CT_DND_NONE, + CursorType::DndMove => Self::CT_DND_MOVE, + CursorType::DndCopy => Self::CT_DND_COPY, + CursorType::DndLink => Self::CT_DND_LINK + } + } +} + +pub struct CursorInfo<'a> { + pub hotspot: Point, + pub image_scale_factor: f32, + pub buffer: &'a [u8], + pub size: Size +} + +impl<'a> From for CursorInfo<'a> { + fn from(value: cef_cursor_info_t) -> Self { + Self::from(&value) + } +} + +impl<'a> From<&cef_cursor_info_t> for CursorInfo<'a> { + fn from(value: &cef_cursor_info_t) -> Self { + let len = (value.size.width * value.size.height * 4) as usize; + Self { + hotspot: value.hotspot.into(), + image_scale_factor: value.image_scale_factor, + buffer: unsafe { from_raw_parts(value.buffer as *const u8, len) }, + size: value.size.into() + } + } +} + +impl<'a> From> for cef_cursor_info_t { + fn from(value: CursorInfo) -> Self { + Self::from(&value) + } +} + +impl<'a> From<&CursorInfo<'a>> for cef_cursor_info_t { + fn from(value: &CursorInfo) -> Self { + Self { + hotspot: value.hotspot.into(), + image_scale_factor: value.image_scale_factor, + buffer: value.buffer.as_ptr() as *mut c_void, + size: value.size.into() + } + } +} From 61fc06aad11519c19ebf2683d1aac48493e3796c Mon Sep 17 00:00:00 2001 From: NikitaSkrynnik Date: Thu, 13 Mar 2025 22:11:13 +1100 Subject: [PATCH 2/2] fix CursorHandle issue on different platforms (TODO) Signed-off-by: NikitaSkrynnik --- crates/cef-ui/src/display_handler.rs | 15 ++++++++------- crates/cef-ui/src/types.rs | 20 +++++++++++++++----- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/crates/cef-ui/src/display_handler.rs b/crates/cef-ui/src/display_handler.rs index d66db29..f602515 100644 --- a/crates/cef-ui/src/display_handler.rs +++ b/crates/cef-ui/src/display_handler.rs @@ -1,10 +1,11 @@ use crate::{ - Browser, CefString, CursorInfo, CursorType, Frame, LogSeverity, RefCountedPtr, Size, Wrappable, - Wrapped, ref_counted_ptr + Browser, CefString, CursorHandle, CursorInfo, CursorType, Frame, LogSeverity, RefCountedPtr, + Size, Wrappable, Wrapped, ref_counted_ptr }; use cef_ui_sys::{ - cef_browser_t, cef_cursor_info_t, cef_cursor_type_t, cef_display_handler_t, cef_frame_t, - cef_log_severity_t, cef_size_t, cef_string_list_t, cef_string_t + cef_browser_t, cef_cursor_handle_t, cef_cursor_info_t, cef_cursor_type_t, + cef_display_handler_t, cef_frame_t, cef_log_severity_t, cef_size_t, cef_string_list_t, + cef_string_t }; use std::{ffi::c_int, mem::zeroed}; @@ -69,7 +70,7 @@ pub trait DisplayHandlerCallbacks: Send + Sync + 'static { fn on_cursor_change( &mut self, browser: Browser, - cursor: u64, + cursor: CursorHandle, cursor_type: CursorType, custom_cursor_info: Option ) -> bool; @@ -252,7 +253,7 @@ impl DisplayHandlerWrapper { unsafe extern "C" fn c_on_cursor_change( this: *mut cef_display_handler_t, browser: *mut cef_browser_t, - cursor: ::std::os::raw::c_ulong, + cursor: cef_cursor_handle_t, cursor_type: cef_cursor_type_t, custom_cursor_info: *const cef_cursor_info_t ) -> ::std::os::raw::c_int { @@ -266,7 +267,7 @@ impl DisplayHandlerWrapper { }; this.0 - .on_cursor_change(browser, cursor, cursor_type, custom_cursor_info) + .on_cursor_change(browser, cursor.into(), cursor_type, custom_cursor_info) as ::std::os::raw::c_int } diff --git a/crates/cef-ui/src/types.rs b/crates/cef-ui/src/types.rs index 3cc269d..3f6deef 100644 --- a/crates/cef-ui/src/types.rs +++ b/crates/cef-ui/src/types.rs @@ -1,10 +1,11 @@ use bitflags::bitflags; use cef_ui_sys::{ - cef_cursor_info_t, cef_cursor_type_t, cef_errorcode_t, cef_horizontal_alignment_t, - cef_insets_t, cef_log_items_t, cef_log_severity_t, cef_paint_element_type_t, cef_point_t, - cef_range_t, cef_rect_t, cef_referrer_policy_t, cef_resource_type_t, cef_screen_info_t, - cef_size_t, cef_state_t, cef_termination_status_t, cef_text_input_mode_t, - cef_touch_handle_state_flags_t, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ALPHA, + cef_cursor_handle_t, cef_cursor_info_t, cef_cursor_type_t, cef_errorcode_t, + cef_horizontal_alignment_t, cef_insets_t, cef_log_items_t, cef_log_severity_t, + cef_paint_element_type_t, cef_point_t, cef_range_t, cef_rect_t, cef_referrer_policy_t, + cef_resource_type_t, cef_screen_info_t, cef_size_t, cef_state_t, cef_termination_status_t, + cef_text_input_mode_t, cef_touch_handle_state_flags_t, + cef_touch_handle_state_flags_t_CEF_THS_FLAG_ALPHA, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ENABLED, cef_touch_handle_state_flags_t_CEF_THS_FLAG_NONE, cef_touch_handle_state_flags_t_CEF_THS_FLAG_ORIENTATION, @@ -3287,6 +3288,15 @@ impl From for cef_cursor_type_t { } } +// TODO: How to handle CursorHandle? it's different on Windows, Linux and MacOS. +pub struct CursorHandle; + +impl From for CursorHandle { + fn from(_value: cef_cursor_handle_t) -> Self { + Self + } +} + pub struct CursorInfo<'a> { pub hotspot: Point, pub image_scale_factor: f32,