2019-05-01 17:03:30 -06:00
use std ::{
2021-03-08 19:56:39 +01:00
any ::Any ,
2024-02-28 04:33:47 +01:00
cell ::Cell ,
2021-03-08 19:56:39 +01:00
collections ::VecDeque ,
marker ::PhantomData ,
os ::raw ::c_void ,
2024-02-28 04:33:47 +01:00
panic ::{ catch_unwind , resume_unwind , RefUnwindSafe , UnwindSafe } ,
2023-04-11 12:50:52 +01:00
ptr ,
2021-03-08 19:56:39 +01:00
rc ::{ Rc , Weak } ,
2019-08-23 12:30:53 +03:00
sync ::mpsc ,
2023-07-23 23:27:38 +01:00
time ::{ Duration , Instant } ,
2019-05-01 17:03:30 -06:00
} ;
2022-09-08 21:03:25 +02:00
use core_foundation ::base ::{ CFIndex , CFRelease } ;
use core_foundation ::runloop ::{
kCFRunLoopCommonModes , CFRunLoopAddSource , CFRunLoopGetMain , CFRunLoopSourceContext ,
CFRunLoopSourceCreate , CFRunLoopSourceRef , CFRunLoopSourceSignal , CFRunLoopWakeUp ,
} ;
2022-09-08 16:45:29 +02:00
use objc2 ::{ msg_send_id , ClassType } ;
2023-12-23 23:07:55 +01:00
use objc2 ::{
rc ::{ autoreleasepool , Id } ,
runtime ::ProtocolObject ,
2023-12-23 20:58:38 +01:00
} ;
2024-04-18 17:34:19 +02:00
use objc2_app_kit ::{ NSApplication , NSApplicationActivationPolicy , NSWindow } ;
use objc2_foundation ::{ MainThreadMarker , NSObjectProtocol } ;
2023-12-23 23:07:55 +01:00
use super ::event ::dummy_event ;
2024-01-14 03:37:53 +01:00
use super ::{
app ::WinitApplication ,
2024-01-25 05:26:50 +01:00
app_delegate ::{ ApplicationDelegate , HandlePendingUserEvents } ,
2024-01-14 03:37:53 +01:00
monitor ::{ self , MonitorHandle } ,
observer ::setup_control_flow_observers ,
} ;
2024-02-03 07:27:17 +04:00
use crate ::platform_impl ::platform ::cursor ::CustomCursor ;
use crate ::window ::{ CustomCursor as RootCustomCursor , CustomCursorSource } ;
2019-06-18 02:27:00 +08:00
use crate ::{
2023-08-13 23:20:09 +04:00
error ::EventLoopError ,
2019-05-01 17:03:30 -06:00
event ::Event ,
2024-01-31 17:29:59 +04:00
event_loop ::{ ActiveEventLoop as RootWindowTarget , ControlFlow , DeviceEvents , EventLoopClosed } ,
2023-06-18 12:10:09 +01:00
platform ::{ macos ::ActivationPolicy , pump_events ::PumpStatus } ,
2019-05-01 17:03:30 -06:00
} ;
2021-03-08 19:56:39 +01:00
#[ derive(Default) ]
pub struct PanicInfo {
inner : Cell < Option < Box < dyn Any + Send + 'static > > > ,
}
// WARNING:
// As long as this struct is used through its `impl`, it is UnwindSafe.
// (If `get_mut` is called on `inner`, unwind safety may get broken.)
impl UnwindSafe for PanicInfo { }
impl RefUnwindSafe for PanicInfo { }
impl PanicInfo {
pub fn is_panicking ( & self ) -> bool {
let inner = self . inner . take ( ) ;
let result = inner . is_some ( ) ;
self . inner . set ( inner ) ;
result
}
/// Overwrites the curret state if the current state is not panicking
pub fn set_panic ( & self , p : Box < dyn Any + Send + 'static > ) {
if ! self . is_panicking ( ) {
self . inner . set ( Some ( p ) ) ;
}
}
pub fn take ( & self ) -> Option < Box < dyn Any + Send + 'static > > {
self . inner . take ( )
}
}
2023-08-27 17:04:39 +02:00
#[ derive(Debug) ]
2024-01-31 17:29:59 +04:00
pub struct ActiveEventLoop {
2024-01-14 03:37:53 +01:00
delegate : Id < ApplicationDelegate > ,
2024-01-14 05:19:23 +01:00
pub ( super ) mtm : MainThreadMarker ,
2017-02-03 23:05:57 +11:00
}
2024-01-31 17:29:59 +04:00
impl ActiveEventLoop {
2024-02-28 04:33:47 +01:00
pub ( super ) fn new_root ( delegate : Id < ApplicationDelegate > ) -> RootWindowTarget {
let mtm = MainThreadMarker ::from ( & * delegate ) ;
let p = Self { delegate , mtm } ;
RootWindowTarget {
p ,
_marker : PhantomData ,
}
}
2024-02-03 07:27:17 +04:00
pub fn create_custom_cursor ( & self , source : CustomCursorSource ) -> RootCustomCursor {
RootCustomCursor {
inner : CustomCursor ::new ( source . inner ) ,
}
}
2020-07-04 15:46:41 -04:00
#[ inline ]
pub fn available_monitors ( & self ) -> VecDeque < MonitorHandle > {
monitor ::available_monitors ( )
}
#[ inline ]
2022-09-21 10:04:28 +02:00
pub fn primary_monitor ( & self ) -> Option < MonitorHandle > {
2020-09-07 20:20:47 +03:00
let monitor = monitor ::primary_monitor ( ) ;
2022-09-21 10:04:28 +02:00
Some ( monitor )
2020-07-04 15:46:41 -04:00
}
2022-07-21 22:22:36 +03:00
2023-09-01 23:14:16 +02:00
#[ inline ]
pub fn listen_device_events ( & self , _allowed : DeviceEvents ) { }
2023-10-14 19:07:39 -07:00
#[ cfg(feature = " rwh_05 " ) ]
2022-07-21 22:22:36 +03:00
#[ inline ]
2023-10-14 19:07:39 -07:00
pub fn raw_display_handle_rwh_05 ( & self ) -> rwh_05 ::RawDisplayHandle {
rwh_05 ::RawDisplayHandle ::AppKit ( rwh_05 ::AppKitDisplayHandle ::empty ( ) )
}
#[ cfg(feature = " rwh_06 " ) ]
#[ inline ]
pub fn raw_display_handle_rwh_06 (
& self ,
) -> Result < rwh_06 ::RawDisplayHandle , rwh_06 ::HandleError > {
Ok ( rwh_06 ::RawDisplayHandle ::AppKit (
rwh_06 ::AppKitDisplayHandle ::new ( ) ,
) )
2022-07-21 22:22:36 +03:00
}
2023-09-07 08:25:04 +02:00
pub ( crate ) fn set_control_flow ( & self , control_flow : ControlFlow ) {
2024-01-14 03:37:53 +01:00
self . delegate . set_control_flow ( control_flow )
2023-09-07 08:25:04 +02:00
}
pub ( crate ) fn control_flow ( & self ) -> ControlFlow {
2024-01-14 03:37:53 +01:00
self . delegate . control_flow ( )
2023-09-07 08:25:04 +02:00
}
pub ( crate ) fn exit ( & self ) {
2024-01-14 03:37:53 +01:00
self . delegate . exit ( )
2023-09-07 08:25:04 +02:00
}
2023-12-22 20:00:20 +04:00
pub ( crate ) fn clear_exit ( & self ) {
2024-01-14 03:37:53 +01:00
self . delegate . clear_exit ( )
2023-12-22 20:00:20 +04:00
}
2023-09-07 08:25:04 +02:00
pub ( crate ) fn exiting ( & self ) -> bool {
2024-01-14 03:37:53 +01:00
self . delegate . exiting ( )
2023-09-07 08:25:04 +02:00
}
2024-01-15 11:58:11 -08:00
pub ( crate ) fn owned_display_handle ( & self ) -> OwnedDisplayHandle {
OwnedDisplayHandle
}
2020-07-04 15:46:41 -04:00
}
2024-01-31 17:29:59 +04:00
impl ActiveEventLoop {
2021-12-01 12:20:56 +01:00
pub ( crate ) fn hide_application ( & self ) {
2023-12-23 23:07:55 +01:00
NSApplication ::sharedApplication ( self . mtm ) . hide ( None )
2021-12-01 12:20:56 +01:00
}
pub ( crate ) fn hide_other_applications ( & self ) {
2023-12-23 23:07:55 +01:00
NSApplication ::sharedApplication ( self . mtm ) . hideOtherApplications ( None )
2021-12-01 12:20:56 +01:00
}
2023-07-13 15:55:51 +00:00
pub ( crate ) fn set_allows_automatic_window_tabbing ( & self , enabled : bool ) {
2023-12-23 23:07:55 +01:00
NSWindow ::setAllowsAutomaticWindowTabbing ( enabled , self . mtm )
2023-07-13 15:55:51 +00:00
}
pub ( crate ) fn allows_automatic_window_tabbing ( & self ) -> bool {
2023-12-23 23:07:55 +01:00
NSWindow ::allowsAutomaticWindowTabbing ( self . mtm )
2023-07-13 15:55:51 +00:00
}
2021-12-01 12:20:56 +01:00
}
2024-01-25 05:26:50 +01:00
fn map_user_event < T : 'static > (
mut handler : impl FnMut ( Event < T > , & RootWindowTarget ) ,
receiver : Rc < mpsc ::Receiver < T > > ,
) -> impl FnMut ( Event < HandlePendingUserEvents > , & RootWindowTarget ) {
move | event , window_target | match event . map_nonuser_event ( ) {
Ok ( event ) = > ( handler ) ( event , window_target ) ,
Err ( _ ) = > {
for event in receiver . try_iter ( ) {
( handler ) ( Event ::UserEvent ( event ) , window_target ) ;
}
}
}
}
2019-05-01 17:03:30 -06:00
pub struct EventLoop < T : 'static > {
2023-08-27 17:04:39 +02:00
/// Store a reference to the application for convenience.
2023-08-30 15:19:30 +02:00
///
2024-02-19 11:58:44 +07:00
/// We intentionally don't store `WinitApplication` since we want to have
/// the possibility of swapping that out at some point.
2023-08-30 15:19:30 +02:00
app : Id < NSApplication > ,
2024-01-14 03:37:53 +01:00
/// The application delegate that we've registered.
///
/// The delegate is only weakly referenced by NSApplication, so we must
/// keep it around here as well.
delegate : Id < ApplicationDelegate > ,
2021-04-30 11:31:28 +02:00
2023-08-27 17:04:39 +02:00
// Event sender and receiver, used for EventLoopProxy.
2023-08-14 21:19:57 +02:00
sender : mpsc ::Sender < T > ,
2023-08-27 17:04:39 +02:00
receiver : Rc < mpsc ::Receiver < T > > ,
2024-02-28 04:33:47 +01:00
window_target : RootWindowTarget ,
2021-03-08 19:56:39 +01:00
panic_info : Rc < PanicInfo > ,
2017-06-09 22:13:30 +10:00
}
2022-06-10 13:43:33 +03:00
#[ derive(Debug, Copy, Clone, PartialEq, Eq, Hash) ]
2022-02-16 22:09:03 +01:00
pub ( crate ) struct PlatformSpecificEventLoopAttributes {
pub ( crate ) activation_policy : ActivationPolicy ,
pub ( crate ) default_menu : bool ,
2022-11-23 14:42:46 +02:00
pub ( crate ) activate_ignoring_other_apps : bool ,
2022-02-16 22:09:03 +01:00
}
impl Default for PlatformSpecificEventLoopAttributes {
fn default ( ) -> Self {
Self {
activation_policy : Default ::default ( ) , // Regular
default_menu : true ,
2022-11-23 14:42:46 +02:00
activate_ignoring_other_apps : true ,
2022-02-16 22:09:03 +01:00
}
}
}
2019-05-01 17:03:30 -06:00
impl < T > EventLoop < T > {
2023-08-13 23:20:09 +04:00
pub ( crate ) fn new (
attributes : & PlatformSpecificEventLoopAttributes ,
) -> Result < Self , EventLoopError > {
2023-08-14 21:19:57 +02:00
let mtm = MainThreadMarker ::new ( )
2023-08-30 15:19:30 +02:00
. expect ( " on macOS, `EventLoop` must be created on the main thread! " ) ;
2017-06-09 22:13:30 +10:00
2023-08-30 15:19:30 +02:00
let app : Id < NSApplication > =
2022-09-08 16:45:29 +02:00
unsafe { msg_send_id! [ WinitApplication ::class ( ) , sharedApplication ] } ;
2023-08-30 15:19:30 +02:00
if ! app . is_kind_of ::< WinitApplication > ( ) {
panic! ( " `winit` requires control over the principal class. You must create the event loop before other parts of your application initialize NSApplication " ) ;
}
2022-09-08 16:45:29 +02:00
let activation_policy = match attributes . activation_policy {
2024-04-18 17:34:19 +02:00
ActivationPolicy ::Regular = > NSApplicationActivationPolicy ::Regular ,
ActivationPolicy ::Accessory = > NSApplicationActivationPolicy ::Accessory ,
ActivationPolicy ::Prohibited = > NSApplicationActivationPolicy ::Prohibited ,
2019-05-01 17:03:30 -06:00
} ;
2022-11-23 14:42:46 +02:00
let delegate = ApplicationDelegate ::new (
2023-12-23 23:07:55 +01:00
mtm ,
2022-11-23 14:42:46 +02:00
activation_policy ,
attributes . default_menu ,
attributes . activate_ignoring_other_apps ,
) ;
2022-09-08 16:45:29 +02:00
autoreleasepool ( | _ | {
2023-12-23 23:07:55 +01:00
app . setDelegate ( Some ( ProtocolObject ::from_ref ( & * delegate ) ) ) ;
2022-09-08 16:45:29 +02:00
} ) ;
2021-03-08 19:56:39 +01:00
let panic_info : Rc < PanicInfo > = Default ::default ( ) ;
setup_control_flow_observers ( Rc ::downgrade ( & panic_info ) ) ;
2023-08-14 21:19:57 +02:00
let ( sender , receiver ) = mpsc ::channel ( ) ;
2023-08-13 23:20:09 +04:00
Ok ( EventLoop {
2023-08-27 17:04:39 +02:00
app ,
2024-01-14 03:37:53 +01:00
delegate : delegate . clone ( ) ,
2023-08-14 21:19:57 +02:00
sender ,
2023-08-27 17:04:39 +02:00
receiver : Rc ::new ( receiver ) ,
2024-02-28 04:33:47 +01:00
window_target : RootWindowTarget {
2024-01-31 17:29:59 +04:00
p : ActiveEventLoop { delegate , mtm } ,
2019-05-01 17:03:30 -06:00
_marker : PhantomData ,
2024-02-28 04:33:47 +01:00
} ,
2021-03-08 19:56:39 +01:00
panic_info ,
2023-08-13 23:20:09 +04:00
} )
2017-06-09 22:13:30 +10:00
}
2017-02-05 12:51:09 +11:00
2024-01-13 21:36:53 +01:00
pub fn window_target ( & self ) -> & RootWindowTarget {
2019-05-01 17:03:30 -06:00
& self . window_target
2017-02-05 12:51:09 +11:00
}
2024-02-28 04:33:47 +01:00
pub fn run < F > ( mut self , handler : F ) -> Result < ( ) , EventLoopError >
2019-06-21 11:33:15 -04:00
where
2024-01-13 21:36:53 +01:00
F : FnMut ( Event < T > , & RootWindowTarget ) ,
2019-08-23 12:30:53 +03:00
{
2024-02-28 04:33:47 +01:00
self . run_on_demand ( handler )
2019-08-23 12:30:53 +03:00
}
2023-06-18 12:10:09 +01:00
// NB: we don't base this on `pump_events` because for `MacOs` we can't support
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
// time and so a layered implementation would end up using a lot of CPU due to
// redundant wake ups.
2024-02-28 04:33:47 +01:00
pub fn run_on_demand < F > ( & mut self , handler : F ) -> Result < ( ) , EventLoopError >
2023-06-18 12:10:09 +01:00
where
2024-01-13 21:36:53 +01:00
F : FnMut ( Event < T > , & RootWindowTarget ) ,
2023-06-18 12:10:09 +01:00
{
2024-02-28 04:33:47 +01:00
let handler = map_user_event ( handler , self . receiver . clone ( ) ) ;
2021-03-08 19:56:39 +01:00
2024-02-28 04:33:47 +01:00
self . delegate . set_event_handler ( handler , | | {
autoreleasepool ( | _ | {
2023-07-23 23:27:38 +01:00
// clear / normalize pump_events state
2024-01-14 03:37:53 +01:00
self . delegate . set_wait_timeout ( None ) ;
self . delegate . set_stop_before_wait ( false ) ;
self . delegate . set_stop_after_wait ( false ) ;
self . delegate . set_stop_on_redraw ( false ) ;
if self . delegate . is_launched ( ) {
debug_assert! ( ! self . delegate . is_running ( ) ) ;
self . delegate . set_is_running ( true ) ;
self . delegate . dispatch_init_events ( ) ;
2023-06-18 12:10:09 +01:00
}
2024-02-28 04:33:47 +01:00
// SAFETY: We do not run the application re-entrantly
2023-08-27 17:04:39 +02:00
unsafe { self . app . run ( ) } ;
2023-06-18 12:10:09 +01:00
// While the app is running it's possible that we catch a panic
// to avoid unwinding across an objective-c ffi boundary, which
2023-12-23 23:07:55 +01:00
// will lead to us stopping the `NSApplication` and saving the
2023-06-18 12:10:09 +01:00
// `PanicInfo` so that we can resume the unwind at a controlled,
// safe point in time.
if let Some ( panic ) = self . panic_info . take ( ) {
resume_unwind ( panic ) ;
}
2024-01-14 03:37:53 +01:00
self . delegate . internal_exit ( )
2024-02-28 04:33:47 +01:00
} )
2021-05-27 17:38:41 +02:00
} ) ;
2022-01-11 01:23:20 +01:00
2023-09-07 08:25:04 +02:00
Ok ( ( ) )
2023-06-18 12:10:09 +01:00
}
2024-02-28 04:33:47 +01:00
pub fn pump_events < F > ( & mut self , timeout : Option < Duration > , handler : F ) -> PumpStatus
2023-06-18 12:10:09 +01:00
where
2024-01-13 21:36:53 +01:00
F : FnMut ( Event < T > , & RootWindowTarget ) ,
2023-06-18 12:10:09 +01:00
{
2024-02-28 04:33:47 +01:00
let handler = map_user_event ( handler , self . receiver . clone ( ) ) ;
2023-06-18 12:10:09 +01:00
2024-02-28 04:33:47 +01:00
self . delegate . set_event_handler ( handler , | | {
autoreleasepool ( | _ | {
2023-12-23 23:07:55 +01:00
// As a special case, if the application hasn't been launched yet then we at least run
2023-06-18 12:10:09 +01:00
// the loop until it has fully launched.
2024-01-14 03:37:53 +01:00
if ! self . delegate . is_launched ( ) {
debug_assert! ( ! self . delegate . is_running ( ) ) ;
2023-06-18 12:10:09 +01:00
2024-01-14 03:37:53 +01:00
self . delegate . set_stop_on_launch ( ) ;
2024-02-28 04:33:47 +01:00
// SAFETY: We do not run the application re-entrantly
unsafe { self . app . run ( ) } ;
2023-06-18 12:10:09 +01:00
2023-12-23 23:07:55 +01:00
// Note: we dispatch `NewEvents(Init)` + `Resumed` events after the application has launched
2024-01-14 03:37:53 +01:00
} else if ! self . delegate . is_running ( ) {
2023-12-23 23:07:55 +01:00
// Even though the application may have been launched, it's possible we aren't running
2023-06-18 12:10:09 +01:00
// if the `EventLoop` was run before and has since exited. This indicates that
// we just starting to re-run the same `EventLoop` again.
2024-01-14 03:37:53 +01:00
self . delegate . set_is_running ( true ) ;
self . delegate . dispatch_init_events ( ) ;
2023-06-18 12:10:09 +01:00
} else {
2023-12-23 23:07:55 +01:00
// Only run for as long as the given `Duration` allows so we don't block the external loop.
2023-07-23 23:27:38 +01:00
match timeout {
Some ( Duration ::ZERO ) = > {
2024-01-14 03:37:53 +01:00
self . delegate . set_wait_timeout ( None ) ;
self . delegate . set_stop_before_wait ( true ) ;
2023-07-23 23:27:38 +01:00
}
Some ( duration ) = > {
2024-01-14 03:37:53 +01:00
self . delegate . set_stop_before_wait ( false ) ;
2023-07-23 23:27:38 +01:00
let timeout = Instant ::now ( ) + duration ;
2024-01-14 03:37:53 +01:00
self . delegate . set_wait_timeout ( Some ( timeout ) ) ;
self . delegate . set_stop_after_wait ( true ) ;
2023-07-23 23:27:38 +01:00
}
None = > {
2024-01-14 03:37:53 +01:00
self . delegate . set_wait_timeout ( None ) ;
self . delegate . set_stop_before_wait ( false ) ;
self . delegate . set_stop_after_wait ( true ) ;
2023-07-23 23:27:38 +01:00
}
}
2024-01-14 03:37:53 +01:00
self . delegate . set_stop_on_redraw ( true ) ;
2024-02-28 04:33:47 +01:00
// SAFETY: We do not run the application re-entrantly
unsafe { self . app . run ( ) } ;
2023-06-18 12:10:09 +01:00
}
// While the app is running it's possible that we catch a panic
// to avoid unwinding across an objective-c ffi boundary, which
2023-12-23 23:07:55 +01:00
// will lead to us stopping the application and saving the
2023-06-18 12:10:09 +01:00
// `PanicInfo` so that we can resume the unwind at a controlled,
// safe point in time.
if let Some ( panic ) = self . panic_info . take ( ) {
resume_unwind ( panic ) ;
}
2024-01-14 03:37:53 +01:00
if self . delegate . exiting ( ) {
self . delegate . internal_exit ( ) ;
2023-09-07 08:25:04 +02:00
PumpStatus ::Exit ( 0 )
2023-06-18 12:10:09 +01:00
} else {
PumpStatus ::Continue
}
2024-02-28 04:33:47 +01:00
} )
2023-06-18 12:10:09 +01:00
} )
2017-02-03 23:05:57 +11:00
}
2022-03-18 14:09:39 +01:00
pub fn create_proxy ( & self ) -> EventLoopProxy < T > {
2023-08-14 21:19:57 +02:00
EventLoopProxy ::new ( self . sender . clone ( ) )
2019-05-01 17:03:30 -06:00
}
}
2017-02-04 00:51:38 +11:00
2024-01-15 11:58:11 -08:00
#[ derive(Clone) ]
pub ( crate ) struct OwnedDisplayHandle ;
impl OwnedDisplayHandle {
#[ cfg(feature = " rwh_05 " ) ]
#[ inline ]
pub fn raw_display_handle_rwh_05 ( & self ) -> rwh_05 ::RawDisplayHandle {
rwh_05 ::AppKitDisplayHandle ::empty ( ) . into ( )
}
#[ cfg(feature = " rwh_06 " ) ]
#[ inline ]
pub fn raw_display_handle_rwh_06 (
& self ,
) -> Result < rwh_06 ::RawDisplayHandle , rwh_06 ::HandleError > {
Ok ( rwh_06 ::AppKitDisplayHandle ::new ( ) . into ( ) )
}
}
2024-01-14 03:37:53 +01:00
pub ( super ) fn stop_app_immediately ( app : & NSApplication ) {
autoreleasepool ( | _ | {
app . stop ( None ) ;
// To stop event loop immediately, we need to post some event here.
// See: https://stackoverflow.com/questions/48041279/stopping-the-nsapplication-main-event-loop/48064752#48064752
app . postEvent_atStart ( & dummy_event ( ) . unwrap ( ) , true ) ;
} ) ;
}
2021-03-08 19:56:39 +01:00
/// Catches panics that happen inside `f` and when a panic
/// happens, stops the `sharedApplication`
#[ inline ]
pub fn stop_app_on_panic < F : FnOnce ( ) -> R + UnwindSafe , R > (
2023-12-23 23:07:55 +01:00
mtm : MainThreadMarker ,
2021-03-08 19:56:39 +01:00
panic_info : Weak < PanicInfo > ,
f : F ,
) -> Option < R > {
match catch_unwind ( f ) {
Ok ( r ) = > Some ( r ) ,
Err ( e ) = > {
// It's important that we set the panic before requesting a `stop`
// because some callback are still called during the `stop` message
// and we need to know in those callbacks if the application is currently
// panicking
{
let panic_info = panic_info . upgrade ( ) . unwrap ( ) ;
panic_info . set_panic ( e ) ;
}
2023-12-23 23:07:55 +01:00
let app = NSApplication ::sharedApplication ( mtm ) ;
2024-01-14 03:37:53 +01:00
stop_app_immediately ( & app ) ;
2021-03-08 19:56:39 +01:00
None
}
}
}
2022-03-18 14:09:39 +01:00
pub struct EventLoopProxy < T > {
2019-05-01 17:03:30 -06:00
sender : mpsc ::Sender < T > ,
source : CFRunLoopSourceRef ,
}
2017-02-04 00:51:38 +11:00
2022-03-18 14:09:39 +01:00
unsafe impl < T : Send > Send for EventLoopProxy < T > { }
2024-02-01 14:27:44 +01:00
unsafe impl < T : Send > Sync for EventLoopProxy < T > { }
2017-02-04 00:51:38 +11:00
2022-03-18 14:09:39 +01:00
impl < T > Drop for EventLoopProxy < T > {
2020-04-20 23:48:42 +02:00
fn drop ( & mut self ) {
unsafe {
CFRelease ( self . source as _ ) ;
}
}
}
2022-03-18 14:09:39 +01:00
impl < T > Clone for EventLoopProxy < T > {
2019-08-06 05:51:42 +09:00
fn clone ( & self ) -> Self {
2022-03-18 14:09:39 +01:00
EventLoopProxy ::new ( self . sender . clone ( ) )
2019-08-06 05:51:42 +09:00
}
}
2022-03-18 14:09:39 +01:00
impl < T > EventLoopProxy < T > {
2019-05-01 17:03:30 -06:00
fn new ( sender : mpsc ::Sender < T > ) -> Self {
unsafe {
2019-07-13 01:05:07 +02:00
// just wake up the eventloop
2022-09-08 21:03:25 +02:00
extern " C " fn event_loop_proxy_handler ( _ : * const c_void ) { }
2019-05-01 17:03:30 -06:00
// adding a Source to the main CFRunLoop lets us wake it up and
// process user events through the normal OS EventLoop mechanisms.
let rl = CFRunLoopGetMain ( ) ;
2022-09-08 21:03:25 +02:00
let mut context = CFRunLoopSourceContext {
version : 0 ,
info : ptr ::null_mut ( ) ,
retain : None ,
release : None ,
copyDescription : None ,
equal : None ,
hash : None ,
schedule : None ,
cancel : None ,
perform : event_loop_proxy_handler ,
} ;
2019-06-21 11:33:15 -04:00
let source =
CFRunLoopSourceCreate ( ptr ::null_mut ( ) , CFIndex ::max_value ( ) - 1 , & mut context ) ;
2019-05-01 17:03:30 -06:00
CFRunLoopAddSource ( rl , source , kCFRunLoopCommonModes ) ;
CFRunLoopWakeUp ( rl ) ;
2022-03-18 14:09:39 +01:00
EventLoopProxy { sender , source }
2017-02-03 23:05:57 +11:00
}
}
2019-12-07 18:22:03 +01:00
pub fn send_event ( & self , event : T ) -> Result < ( ) , EventLoopClosed < T > > {
self . sender
. send ( event )
. map_err ( | mpsc ::SendError ( x ) | EventLoopClosed ( x ) ) ? ;
2017-05-31 15:00:49 +10:00
unsafe {
2019-05-01 17:03:30 -06:00
// let the main thread know there's a new event
CFRunLoopSourceSignal ( self . source ) ;
let rl = CFRunLoopGetMain ( ) ;
CFRunLoopWakeUp ( rl ) ;
2017-05-31 15:00:49 +10:00
}
Ok ( ( ) )
}
2017-02-03 23:05:57 +11:00
}