2019-05-01 17:03:30 -06:00
use std ::{
2021-03-08 19:56:39 +01:00
any ::Any ,
cell ::{ Cell , RefCell } ,
collections ::VecDeque ,
marker ::PhantomData ,
mem ,
os ::raw ::c_void ,
2023-06-18 12:10:09 +01:00
panic ::{ catch_unwind , resume_unwind , AssertUnwindSafe , 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 ,
} ;
2023-12-23 23:07:55 +01:00
use icrate ::AppKit ::{
NSApplication , NSApplicationActivationPolicyAccessory , NSApplicationActivationPolicyProhibited ,
NSApplicationActivationPolicyRegular , NSWindow ,
} ;
use icrate ::Foundation ::{ MainThreadMarker , NSObjectProtocol } ;
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
} ;
2023-12-23 23:07:55 +01:00
use super ::event ::dummy_event ;
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 ,
2023-09-01 23:14:16 +02:00
event_loop ::{
ControlFlow , DeviceEvents , EventLoopClosed , EventLoopWindowTarget as RootWindowTarget ,
} ,
2023-06-18 12:10:09 +01:00
platform ::{ macos ::ActivationPolicy , pump_events ::PumpStatus } ,
2022-09-02 18:46:18 +02:00
platform_impl ::platform ::{
app ::WinitApplication ,
app_delegate ::ApplicationDelegate ,
app_state ::{ AppState , Callback } ,
monitor ::{ self , MonitorHandle } ,
2022-09-08 21:03:25 +02:00
observer ::setup_control_flow_observers ,
2019-06-21 11:33:15 -04:00
} ,
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-13 21:36:53 +01:00
pub struct EventLoopWindowTarget {
2023-08-14 21:19:57 +02:00
mtm : MainThreadMarker ,
2017-02-03 23:05:57 +11:00
}
2024-01-13 21:36:53 +01:00
impl EventLoopWindowTarget {
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 ) {
AppState ::set_control_flow ( control_flow )
}
pub ( crate ) fn control_flow ( & self ) -> ControlFlow {
AppState ::control_flow ( )
}
pub ( crate ) fn exit ( & self ) {
AppState ::exit ( )
}
2023-12-22 20:00:20 +04:00
pub ( crate ) fn clear_exit ( & self ) {
AppState ::clear_exit ( )
}
2023-09-07 08:25:04 +02:00
pub ( crate ) fn exiting ( & self ) -> bool {
AppState ::exiting ( )
}
2020-07-04 15:46:41 -04:00
}
2024-01-13 21:36:53 +01:00
impl EventLoopWindowTarget {
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
}
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
///
/// We intentially don't store `WinitApplication` since we want to have
/// the possiblity of swapping that out at some point.
app : Id < NSApplication > ,
2022-02-16 22:09:03 +01:00
/// The delegate is only weakly referenced by NSApplication, so we keep
/// it around here as well.
2023-07-29 00:33:03 +02:00
_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-01-13 21:36:53 +01:00
window_target : Rc < RootWindowTarget > ,
2021-03-08 19:56:39 +01:00
panic_info : Rc < PanicInfo > ,
/// We make sure that the callback closure is dropped during a panic
/// by making the event loop own it.
///
/// Every other reference should be a Weak reference which is only upgraded
/// into a strong reference in order to call the callback but then the
/// strong reference should be dropped as soon as possible.
2022-01-16 11:14:59 +11:00
_callback : Option < Rc < Callback < T > > > ,
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 {
ActivationPolicy ::Regular = > NSApplicationActivationPolicyRegular ,
ActivationPolicy ::Accessory = > NSApplicationActivationPolicyAccessory ,
ActivationPolicy ::Prohibited = > NSApplicationActivationPolicyProhibited ,
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 ,
2022-02-16 22:09:03 +01:00
_delegate : delegate ,
2023-08-14 21:19:57 +02:00
sender ,
2023-08-27 17:04:39 +02:00
receiver : Rc ::new ( receiver ) ,
2019-08-23 12:30:53 +03:00
window_target : Rc ::new ( RootWindowTarget {
2024-01-13 21:36:53 +01:00
p : EventLoopWindowTarget { mtm } ,
2019-05-01 17:03:30 -06:00
_marker : PhantomData ,
2019-08-23 12:30:53 +03:00
} ) ,
2021-03-08 19:56:39 +01:00
panic_info ,
_callback : None ,
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
}
2023-08-13 23:20:09 +04:00
pub fn run < F > ( mut self , callback : 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
{
2023-10-03 23:24:42 +02:00
self . run_on_demand ( callback )
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.
2023-10-03 23:24:42 +02:00
pub fn run_on_demand < F > ( & mut self , callback : 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
{
if AppState ::is_running ( ) {
2023-08-13 23:20:09 +04:00
return Err ( EventLoopError ::AlreadyRunning ) ;
2023-06-18 12:10:09 +01:00
}
// # Safety
// We are erasing the lifetime of the application callback here so that we
// can (temporarily) store it within 'static global `AppState` that's
// accessible to objc delegate callbacks.
//
// The safety of this depends on on making sure to also clear the callback
// from the global `AppState` before we return from here, ensuring that
// we don't retain a reference beyond the real lifetime of the callback.
2021-03-08 19:56:39 +01:00
let callback = unsafe {
mem ::transmute ::<
2024-01-13 21:36:53 +01:00
Rc < RefCell < dyn FnMut ( Event < T > , & RootWindowTarget ) > > ,
Rc < RefCell < dyn FnMut ( Event < T > , & RootWindowTarget ) > > ,
2021-03-08 19:56:39 +01:00
> ( Rc ::new ( RefCell ::new ( callback ) ) )
} ;
self . _callback = Some ( Rc ::clone ( & callback ) ) ;
2023-09-07 08:25:04 +02:00
autoreleasepool ( | _ | {
2021-03-08 19:56:39 +01:00
// A bit of juggling with the callback references to make sure
// that `self.callback` is the only owner of the callback.
let weak_cb : Weak < _ > = Rc ::downgrade ( & callback ) ;
2022-07-20 11:50:49 +03:00
drop ( callback ) ;
2021-03-08 19:56:39 +01:00
2023-06-18 12:10:09 +01:00
// # Safety
// We make sure to call `AppState::clear_callback` before returning
unsafe {
2023-08-27 17:04:39 +02:00
AppState ::set_callback (
weak_cb ,
Rc ::clone ( & self . window_target ) ,
Rc ::clone ( & self . receiver ) ,
) ;
2023-06-18 12:10:09 +01:00
}
2021-03-08 19:56:39 +01:00
2023-06-18 12:10:09 +01:00
// catch panics to make sure we can't unwind without clearing the set callback
// (which would leave the global `AppState` in an undefined, unsafe state)
let catch_result = catch_unwind ( AssertUnwindSafe ( | | {
2023-07-23 23:27:38 +01:00
// clear / normalize pump_events state
AppState ::set_wait_timeout ( None ) ;
AppState ::set_stop_app_before_wait ( false ) ;
AppState ::set_stop_app_after_wait ( false ) ;
AppState ::set_stop_app_on_redraw_requested ( false ) ;
2023-06-18 12:10:09 +01:00
if AppState ::is_launched ( ) {
debug_assert! ( ! AppState ::is_running ( ) ) ;
AppState ::start_running ( ) ; // Set is_running = true + dispatch `NewEvents(Init)` + `Resumed`
}
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 ) ;
}
2023-09-07 08:25:04 +02:00
AppState ::internal_exit ( )
2023-06-18 12:10:09 +01:00
} ) ) ;
// # Safety
// This pairs up with the `unsafe` call to `set_callback` above and ensures that
// we always clear the application callback from the global `AppState` before
// returning
drop ( self . _callback . take ( ) ) ;
AppState ::clear_callback ( ) ;
2023-09-07 08:25:04 +02:00
if let Err ( payload ) = catch_result {
resume_unwind ( payload )
2021-03-08 19:56:39 +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
}
2023-07-24 00:37:51 +01:00
pub fn pump_events < F > ( & mut self , timeout : Option < Duration > , callback : 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
{
// # Safety
// We are erasing the lifetime of the application callback here so that we
// can (temporarily) store it within 'static global `AppState` that's
// accessible to objc delegate callbacks.
//
// The safety of this depends on on making sure to also clear the callback
// from the global `AppState` before we return from here, ensuring that
// we don't retain a reference beyond the real lifetime of the callback.
let callback = unsafe {
mem ::transmute ::<
2024-01-13 21:36:53 +01:00
Rc < RefCell < dyn FnMut ( Event < T > , & RootWindowTarget ) > > ,
Rc < RefCell < dyn FnMut ( Event < T > , & RootWindowTarget ) > > ,
2023-06-18 12:10:09 +01:00
> ( Rc ::new ( RefCell ::new ( callback ) ) )
} ;
self . _callback = Some ( Rc ::clone ( & callback ) ) ;
autoreleasepool ( | _ | {
// A bit of juggling with the callback references to make sure
// that `self.callback` is the only owner of the callback.
let weak_cb : Weak < _ > = Rc ::downgrade ( & callback ) ;
drop ( callback ) ;
// # Safety
// We will make sure to call `AppState::clear_callback` before returning
// to ensure that we don't hold on to the callback beyond its (erased)
// lifetime
unsafe {
2023-08-27 17:04:39 +02:00
AppState ::set_callback (
weak_cb ,
Rc ::clone ( & self . window_target ) ,
Rc ::clone ( & self . receiver ) ,
) ;
2023-06-18 12:10:09 +01:00
}
// catch panics to make sure we can't unwind without clearing the set callback
// (which would leave the global `AppState` in an undefined, unsafe state)
let catch_result = catch_unwind ( AssertUnwindSafe ( | | {
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.
if ! AppState ::is_launched ( ) {
debug_assert! ( ! AppState ::is_running ( ) ) ;
AppState ::request_stop_on_launch ( ) ;
unsafe {
2023-12-23 23:07:55 +01:00
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
2023-06-18 12:10:09 +01:00
} else if ! AppState ::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.
AppState ::start_running ( ) ; // Set is_running = true + dispatch `NewEvents(Init)` + `Resumed`
} 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 ) = > {
AppState ::set_wait_timeout ( None ) ;
AppState ::set_stop_app_before_wait ( true ) ;
}
Some ( duration ) = > {
AppState ::set_stop_app_before_wait ( false ) ;
let timeout = Instant ::now ( ) + duration ;
AppState ::set_wait_timeout ( Some ( timeout ) ) ;
AppState ::set_stop_app_after_wait ( true ) ;
}
None = > {
AppState ::set_wait_timeout ( None ) ;
AppState ::set_stop_app_before_wait ( false ) ;
AppState ::set_stop_app_after_wait ( true ) ;
}
}
2023-06-18 12:10:09 +01:00
AppState ::set_stop_app_on_redraw_requested ( true ) ;
unsafe {
2023-12-23 23:07:55 +01:00
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 ) ;
}
2023-09-07 08:25:04 +02:00
if AppState ::exiting ( ) {
AppState ::internal_exit ( ) ;
PumpStatus ::Exit ( 0 )
2023-06-18 12:10:09 +01:00
} else {
PumpStatus ::Continue
}
} ) ) ;
// # Safety
// This pairs up with the `unsafe` call to `set_callback` above and ensures that
// we always clear the application callback from the global `AppState` before
// returning
AppState ::clear_callback ( ) ;
drop ( self . _callback . take ( ) ) ;
match catch_result {
Ok ( pump_status ) = > pump_status ,
Err ( payload ) = > resume_unwind ( payload ) ,
}
} )
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
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 ) ;
2022-09-08 16:45:29 +02:00
app . stop ( None ) ;
// Posting a dummy event to get `stop` to take effect immediately.
// See: https://stackoverflow.com/questions/48041279/stopping-the-nsapplication-main-event-loop/48064752#48064752
2023-12-23 20:58:38 +01:00
app . postEvent_atStart ( & dummy_event ( ) . unwrap ( ) , true ) ;
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 > { }
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
}