@@ -397,6 +397,16 @@ pub(crate) struct WinitCefApp<T: UserEvent> {
397397 exit_code : Arc < std:: sync:: atomic:: AtomicI32 > ,
398398}
399399
400+ /// Stands in for the scheduling callbacks `external_message_pump` would provide.
401+ #[ cfg( any(
402+ target_os = "linux" ,
403+ target_os = "dragonfly" ,
404+ target_os = "freebsd" ,
405+ target_os = "netbsd" ,
406+ target_os = "openbsd"
407+ ) ) ]
408+ const CEF_WORK_INTERVAL : std:: time:: Duration = std:: time:: Duration :: from_millis ( 4 ) ;
409+
400410impl < T : UserEvent > WinitCefApp < T > {
401411 fn new (
402412 context : RuntimeContext < T > ,
@@ -842,11 +852,10 @@ impl<T: UserEvent> WinitCefApp<T> {
842852 }
843853 }
844854
845- /// Service the default GLib main context so the external message pump's GLib
846- /// timeout (and any GTK work CEF schedules) gets dispatched, then arm winit to
847- /// wake when the next tick is due. CEF is driven by that timeout firing, not
848- /// from here. Windows/macOS need no equivalent: their pump timers live on the
849- /// native loop winit already runs.
855+ /// Without `external_message_pump` nothing tells us when Chromium has work, so
856+ /// poll it. The GLib iteration only covers GTK work CEF schedules itself:
857+ /// `MessagePumpGlib`'s sources return early unless the pump is inside `Run()`,
858+ /// which only `do_message_loop_work` enters.
850859 #[ cfg( any(
851860 target_os = "linux" ,
852861 target_os = "dragonfly" ,
@@ -859,9 +868,11 @@ impl<T: UserEvent> WinitCefApp<T> {
859868 while context. pending ( ) {
860869 context. iteration ( false ) ;
861870 }
862- if let Some ( deadline) = self . context . cef_pump . next_deadline ( ) {
863- event_loop. set_control_flow ( winit:: event_loop:: ControlFlow :: WaitUntil ( deadline) ) ;
864- }
871+
872+ cef:: do_message_loop_work ( ) ;
873+ event_loop. set_control_flow ( winit:: event_loop:: ControlFlow :: WaitUntil (
874+ std:: time:: Instant :: now ( ) + CEF_WORK_INTERVAL ,
875+ ) ) ;
865876 }
866877}
867878
@@ -1495,10 +1506,30 @@ impl<T: UserEvent> CefRuntime<T> {
14951506 "CEF browser process unexpectedly returned from execute_process"
14961507 ) ;
14971508
1509+ // CEF's `MessagePumpExternal::Run` is a 10ms time slice with a no-op `Quit`,
1510+ // so nested run loops end immediately — HTML5 drag and native context menus
1511+ // both need one that lasts. Chromium's own `MessagePumpGlib` is a real loop.
1512+ #[ cfg( any(
1513+ target_os = "linux" ,
1514+ target_os = "dragonfly" ,
1515+ target_os = "freebsd" ,
1516+ target_os = "netbsd" ,
1517+ target_os = "openbsd"
1518+ ) ) ]
1519+ const EXTERNAL_MESSAGE_PUMP : i32 = 0 ;
1520+ #[ cfg( not( any(
1521+ target_os = "linux" ,
1522+ target_os = "dragonfly" ,
1523+ target_os = "freebsd" ,
1524+ target_os = "netbsd" ,
1525+ target_os = "openbsd"
1526+ ) ) ) ]
1527+ const EXTERNAL_MESSAGE_PUMP : i32 = 1 ;
1528+
14981529 let settings = cef:: Settings {
14991530 no_sandbox : !cfg ! ( feature = "sandbox" ) as i32 ,
15001531 cache_path : cache_path. to_string_lossy ( ) . to_string ( ) . as_str ( ) . into ( ) ,
1501- external_message_pump : 1 ,
1532+ external_message_pump : EXTERNAL_MESSAGE_PUMP ,
15021533 // Comma-delimited; empty keeps CEF's http/https-only default. The
15031534 // defaults stay included because exclude_defaults is left 0.
15041535 cookieable_schemes_list : cef_config. cookieable_schemes . join ( "," ) . as_str ( ) . into ( ) ,
0 commit comments