2025-05-23 15:53:12 +02:00
|
|
|
use std::rc::Rc;
|
2024-11-13 15:29:05 +03:00
|
|
|
use std::sync::Arc;
|
2023-07-23 23:27:38 +01:00
|
|
|
use std::time::{Duration, Instant};
|
2019-05-01 17:03:30 -06:00
|
|
|
|
2024-05-27 14:49:22 +02:00
|
|
|
use objc2::rc::{autoreleasepool, Retained};
|
2025-01-28 21:31:14 +01:00
|
|
|
use objc2::runtime::ProtocolObject;
|
2025-02-24 10:38:10 +01:00
|
|
|
use objc2::{available, MainThreadMarker};
|
2024-08-11 23:14:18 +02:00
|
|
|
use objc2_app_kit::{
|
|
|
|
|
NSApplication, NSApplicationActivationPolicy, NSApplicationDidFinishLaunchingNotification,
|
|
|
|
|
NSApplicationWillTerminateNotification, NSWindow,
|
|
|
|
|
};
|
2025-01-28 21:31:14 +01:00
|
|
|
use objc2_foundation::{NSNotificationCenter, NSObjectProtocol};
|
2024-11-13 15:29:05 +03:00
|
|
|
use rwh_06::HasDisplayHandle;
|
2025-05-17 04:26:09 +02:00
|
|
|
use winit_core::application::ApplicationHandler;
|
|
|
|
|
use winit_core::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource};
|
|
|
|
|
use winit_core::error::{EventLoopError, RequestError};
|
2025-05-20 16:56:53 +02:00
|
|
|
use winit_core::event_loop::pump_events::PumpStatus;
|
2025-05-17 04:26:09 +02:00
|
|
|
use winit_core::event_loop::{
|
|
|
|
|
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
|
|
|
|
EventLoopProxy as CoreEventLoopProxy, OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
|
|
|
|
};
|
|
|
|
|
use winit_core::monitor::MonitorHandle as CoreMonitorHandle;
|
|
|
|
|
use winit_core::window::Theme;
|
2023-12-23 23:07:55 +01:00
|
|
|
|
2024-08-11 23:14:18 +02:00
|
|
|
use super::super::notification_center::create_observer;
|
2025-02-24 10:38:10 +01:00
|
|
|
use super::app::override_send_event;
|
2024-08-11 23:14:18 +02:00
|
|
|
use super::app_state::AppState;
|
2024-06-24 13:26:49 +02:00
|
|
|
use super::cursor::CustomCursor;
|
2023-12-23 23:07:55 +01:00
|
|
|
use super::event::dummy_event;
|
2024-08-06 21:02:53 +03:00
|
|
|
use super::monitor;
|
2024-01-14 03:37:53 +01:00
|
|
|
use super::observer::setup_control_flow_observers;
|
2023-06-18 12:10:09 +01:00
|
|
|
use crate::platform::macos::ActivationPolicy;
|
2024-08-06 21:02:53 +03:00
|
|
|
use crate::platform_impl::Window;
|
2019-05-01 17:03:30 -06:00
|
|
|
|
2023-08-27 17:04:39 +02:00
|
|
|
#[derive(Debug)]
|
2024-01-31 17:29:59 +04:00
|
|
|
pub struct ActiveEventLoop {
|
2024-08-11 23:14:18 +02:00
|
|
|
pub(super) app_state: Rc<AppState>,
|
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-08-06 21:02:53 +03:00
|
|
|
pub(crate) fn hide_application(&self) {
|
|
|
|
|
NSApplication::sharedApplication(self.mtm).hide(None)
|
2024-02-28 04:33:47 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
pub(crate) fn hide_other_applications(&self) {
|
|
|
|
|
NSApplication::sharedApplication(self.mtm).hideOtherApplications(None)
|
2024-05-06 16:29:07 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
pub(crate) fn set_allows_automatic_window_tabbing(&self, enabled: bool) {
|
|
|
|
|
NSWindow::setAllowsAutomaticWindowTabbing(enabled, self.mtm)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn allows_automatic_window_tabbing(&self) -> bool {
|
|
|
|
|
NSWindow::allowsAutomaticWindowTabbing(self.mtm)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RootActiveEventLoop for ActiveEventLoop {
|
2024-11-12 10:56:20 +03:00
|
|
|
fn create_proxy(&self) -> CoreEventLoopProxy {
|
|
|
|
|
CoreEventLoopProxy::new(self.app_state.event_loop_proxy().clone())
|
2024-08-06 21:02:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_window(
|
|
|
|
|
&self,
|
2025-05-17 04:26:09 +02:00
|
|
|
window_attributes: winit_core::window::WindowAttributes,
|
|
|
|
|
) -> Result<Box<dyn winit_core::window::Window>, RequestError> {
|
2024-08-23 23:40:27 +03:00
|
|
|
Ok(Box::new(Window::new(self, window_attributes)?))
|
2024-08-06 21:02:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_custom_cursor(
|
2024-08-06 18:57:03 +02:00
|
|
|
&self,
|
|
|
|
|
source: CustomCursorSource,
|
2025-03-13 17:18:37 +03:00
|
|
|
) -> Result<CoreCustomCursor, RequestError> {
|
|
|
|
|
Ok(CoreCustomCursor(Arc::new(CustomCursor::new(source)?)))
|
2024-02-03 07:27:17 +04:00
|
|
|
}
|
|
|
|
|
|
2024-09-21 20:27:12 +03:00
|
|
|
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
|
|
|
|
|
Box::new(
|
|
|
|
|
monitor::available_monitors()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|monitor| CoreMonitorHandle(Arc::new(monitor))),
|
|
|
|
|
)
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-17 04:26:09 +02:00
|
|
|
fn primary_monitor(&self) -> Option<winit_core::monitor::MonitorHandle> {
|
2020-09-07 20:20:47 +03:00
|
|
|
let monitor = monitor::primary_monitor();
|
2024-09-21 20:27:12 +03:00
|
|
|
Some(CoreMonitorHandle(Arc::new(monitor)))
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
2022-07-21 22:22:36 +03:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
2023-09-01 23:14:16 +02:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn system_theme(&self) -> Option<Theme> {
|
2024-08-05 20:51:38 +02:00
|
|
|
let app = NSApplication::sharedApplication(self.mtm);
|
|
|
|
|
|
2025-01-28 21:31:14 +01:00
|
|
|
// Dark appearance was introduced in macOS 10.14
|
|
|
|
|
if available!(macos = 10.14) {
|
2024-08-05 20:51:38 +02:00
|
|
|
Some(super::window_delegate::appearance_to_theme(&app.effectiveAppearance()))
|
|
|
|
|
} else {
|
|
|
|
|
Some(Theme::Light)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn set_control_flow(&self, control_flow: ControlFlow) {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_control_flow(control_flow)
|
2023-09-07 08:25:04 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn control_flow(&self) -> ControlFlow {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.control_flow()
|
2023-09-07 08:25:04 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn exit(&self) {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.exit()
|
2023-09-07 08:25:04 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn exiting(&self) -> bool {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.exiting()
|
2023-09-07 08:25:04 +02:00
|
|
|
}
|
2024-01-15 11:58:11 -08:00
|
|
|
|
2024-11-13 15:29:05 +03:00
|
|
|
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
|
|
|
|
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
2021-12-01 12:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
|
|
|
|
self
|
2023-07-13 15:55:51 +00:00
|
|
|
}
|
2024-08-06 21:02:53 +03:00
|
|
|
}
|
2023-07-13 15:55:51 +00:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
|
|
|
|
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = rwh_06::RawDisplayHandle::AppKit(rwh_06::AppKitDisplayHandle::new());
|
|
|
|
|
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
2023-07-13 15:55:51 +00:00
|
|
|
}
|
2021-12-01 12:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-03 08:40:04 +01:00
|
|
|
#[derive(Debug)]
|
2024-06-24 13:04:55 +03:00
|
|
|
pub struct EventLoop {
|
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.
|
2024-05-27 14:49:22 +02:00
|
|
|
app: Retained<NSApplication>,
|
2024-08-11 23:14:18 +02:00
|
|
|
app_state: Rc<AppState>,
|
2021-04-30 11:31:28 +02:00
|
|
|
|
2024-08-06 21:02:53 +03:00
|
|
|
window_target: ActiveEventLoop,
|
2024-08-11 23:14:18 +02:00
|
|
|
|
|
|
|
|
// Since macOS 10.11, we no longer need to remove the observers before they are deallocated;
|
|
|
|
|
// the system instead cleans it up next time it would have posted a notification to it.
|
|
|
|
|
//
|
|
|
|
|
// Though we do still need to keep the observers around to prevent them from being deallocated.
|
2025-01-28 21:31:14 +01:00
|
|
|
_did_finish_launching_observer: Retained<ProtocolObject<dyn NSObjectProtocol>>,
|
|
|
|
|
_will_terminate_observer: Retained<ProtocolObject<dyn NSObjectProtocol>>,
|
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 {
|
2024-09-16 06:49:18 -07:00
|
|
|
pub(crate) activation_policy: Option<ActivationPolicy>,
|
2022-02-16 22:09:03 +01:00
|
|
|
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 {
|
2024-09-16 06:49:18 -07:00
|
|
|
Self { activation_policy: None, default_menu: true, activate_ignoring_other_apps: true }
|
2022-02-16 22:09:03 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 13:04:55 +03:00
|
|
|
impl EventLoop {
|
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
|
|
|
|
2022-09-08 16:45:29 +02:00
|
|
|
let activation_policy = match attributes.activation_policy {
|
2024-09-16 06:49:18 -07:00
|
|
|
None => None,
|
|
|
|
|
Some(ActivationPolicy::Regular) => Some(NSApplicationActivationPolicy::Regular),
|
|
|
|
|
Some(ActivationPolicy::Accessory) => Some(NSApplicationActivationPolicy::Accessory),
|
|
|
|
|
Some(ActivationPolicy::Prohibited) => Some(NSApplicationActivationPolicy::Prohibited),
|
2019-05-01 17:03:30 -06:00
|
|
|
};
|
2024-06-24 13:04:55 +03:00
|
|
|
|
2024-08-11 23:14:18 +02:00
|
|
|
let app_state = AppState::setup_global(
|
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
|
|
|
|
2025-02-24 10:38:10 +01:00
|
|
|
// Initialize the application (if it has not already been).
|
|
|
|
|
let app = NSApplication::sharedApplication(mtm);
|
|
|
|
|
|
|
|
|
|
// Override `sendEvent:` on the application to forward to our application state.
|
|
|
|
|
override_send_event(&app);
|
|
|
|
|
|
2024-08-11 23:14:18 +02:00
|
|
|
let center = unsafe { NSNotificationCenter::defaultCenter() };
|
|
|
|
|
|
|
|
|
|
let weak_app_state = Rc::downgrade(&app_state);
|
|
|
|
|
let _did_finish_launching_observer = create_observer(
|
|
|
|
|
¢er,
|
|
|
|
|
// `applicationDidFinishLaunching:`
|
|
|
|
|
unsafe { NSApplicationDidFinishLaunchingNotification },
|
|
|
|
|
move |notification| {
|
|
|
|
|
if let Some(app_state) = weak_app_state.upgrade() {
|
|
|
|
|
app_state.did_finish_launching(notification);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let weak_app_state = Rc::downgrade(&app_state);
|
|
|
|
|
let _will_terminate_observer = create_observer(
|
|
|
|
|
¢er,
|
|
|
|
|
// `applicationWillTerminate:`
|
|
|
|
|
unsafe { NSApplicationWillTerminateNotification },
|
|
|
|
|
move |notification| {
|
|
|
|
|
if let Some(app_state) = weak_app_state.upgrade() {
|
|
|
|
|
app_state.will_terminate(notification);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
2022-09-08 16:45:29 +02:00
|
|
|
|
2025-05-23 15:53:12 +02:00
|
|
|
setup_control_flow_observers(mtm);
|
2023-08-14 21:19:57 +02:00
|
|
|
|
2023-08-13 23:20:09 +04:00
|
|
|
Ok(EventLoop {
|
2023-08-27 17:04:39 +02:00
|
|
|
app,
|
2024-08-11 23:14:18 +02:00
|
|
|
app_state: app_state.clone(),
|
|
|
|
|
window_target: ActiveEventLoop { app_state, mtm },
|
|
|
|
|
_did_finish_launching_observer,
|
|
|
|
|
_will_terminate_observer,
|
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-08-06 21:02:53 +03:00
|
|
|
pub fn window_target(&self) -> &dyn RootActiveEventLoop {
|
2019-05-01 17:03:30 -06:00
|
|
|
&self.window_target
|
2017-02-05 12:51:09 +11:00
|
|
|
}
|
|
|
|
|
|
2024-07-11 15:38:09 +02:00
|
|
|
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
2024-05-20 20:27:36 +04:00
|
|
|
self.run_app_on_demand(app)
|
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-06-24 13:04:55 +03:00
|
|
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
2024-05-20 20:27:36 +04:00
|
|
|
&mut self,
|
2025-03-17 10:56:00 +01:00
|
|
|
app: A,
|
2024-05-20 20:27:36 +04:00
|
|
|
) -> Result<(), EventLoopError> {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.clear_exit();
|
2025-03-17 10:56:00 +01:00
|
|
|
self.app_state.set_event_handler(app, || {
|
2024-02-28 04:33:47 +01:00
|
|
|
autoreleasepool(|_| {
|
2023-07-23 23:27:38 +01:00
|
|
|
// clear / normalize pump_events state
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_wait_timeout(None);
|
|
|
|
|
self.app_state.set_stop_before_wait(false);
|
|
|
|
|
self.app_state.set_stop_after_wait(false);
|
|
|
|
|
self.app_state.set_stop_on_redraw(false);
|
|
|
|
|
|
|
|
|
|
if self.app_state.is_launched() {
|
|
|
|
|
debug_assert!(!self.app_state.is_running());
|
|
|
|
|
self.app_state.set_is_running(true);
|
|
|
|
|
self.app_state.dispatch_init_events();
|
2023-06-18 12:10:09 +01:00
|
|
|
}
|
2024-02-28 04:33:47 +01:00
|
|
|
|
2025-01-28 21:31:14 +01:00
|
|
|
// NOTE: Make sure to not run the application re-entrantly, as that'd be confusing.
|
|
|
|
|
self.app.run();
|
2023-06-18 12:10:09 +01:00
|
|
|
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.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-06-24 13:04:55 +03:00
|
|
|
pub fn pump_app_events<A: ApplicationHandler>(
|
2024-05-20 20:27:36 +04:00
|
|
|
&mut self,
|
|
|
|
|
timeout: Option<Duration>,
|
2025-03-17 10:56:00 +01:00
|
|
|
app: A,
|
2024-05-20 20:27:36 +04:00
|
|
|
) -> PumpStatus {
|
2025-03-17 10:56:00 +01:00
|
|
|
self.app_state.set_event_handler(app, || {
|
2024-02-28 04:33:47 +01:00
|
|
|
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
|
2023-06-18 12:10:09 +01:00
|
|
|
// run the loop until it has fully launched.
|
2024-08-11 23:14:18 +02:00
|
|
|
if !self.app_state.is_launched() {
|
|
|
|
|
debug_assert!(!self.app_state.is_running());
|
2023-06-18 12:10:09 +01:00
|
|
|
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_stop_on_launch();
|
2025-01-28 21:31:14 +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
|
2024-08-11 23:14:18 +02:00
|
|
|
} else if !self.app_state.is_running() {
|
2023-12-23 23:07:55 +01:00
|
|
|
// Even though the application may have been launched, it's possible we aren't
|
2023-06-18 12:10:09 +01:00
|
|
|
// running if the `EventLoop` was run before and has since
|
|
|
|
|
// exited. This indicates that we just starting to re-run
|
|
|
|
|
// the same `EventLoop` again.
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_is_running(true);
|
|
|
|
|
self.app_state.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-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_wait_timeout(None);
|
|
|
|
|
self.app_state.set_stop_before_wait(true);
|
2023-07-23 23:27:38 +01:00
|
|
|
},
|
|
|
|
|
Some(duration) => {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_stop_before_wait(false);
|
2023-07-23 23:27:38 +01:00
|
|
|
let timeout = Instant::now() + duration;
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_wait_timeout(Some(timeout));
|
|
|
|
|
self.app_state.set_stop_after_wait(true);
|
2023-07-23 23:27:38 +01:00
|
|
|
},
|
|
|
|
|
None => {
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_wait_timeout(None);
|
|
|
|
|
self.app_state.set_stop_before_wait(false);
|
|
|
|
|
self.app_state.set_stop_after_wait(true);
|
2023-07-23 23:27:38 +01:00
|
|
|
},
|
|
|
|
|
}
|
2024-08-11 23:14:18 +02:00
|
|
|
self.app_state.set_stop_on_redraw(true);
|
2025-01-28 21:31:14 +01:00
|
|
|
self.app.run();
|
2023-06-18 12:10:09 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-11 23:14:18 +02:00
|
|
|
if self.app_state.exiting() {
|
|
|
|
|
self.app_state.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
|
|
|
}
|
2019-05-01 17:03:30 -06:00
|
|
|
}
|
2017-02-04 00:51:38 +11:00
|
|
|
|
2024-01-15 11:58:11 -08:00
|
|
|
pub(crate) struct OwnedDisplayHandle;
|
|
|
|
|
|
2024-11-13 15:29:05 +03:00
|
|
|
impl HasDisplayHandle for OwnedDisplayHandle {
|
|
|
|
|
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = rwh_06::RawDisplayHandle::AppKit(rwh_06::AppKitDisplayHandle::new());
|
|
|
|
|
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
2024-01-15 11:58:11 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-17 11:29:53 +01:00
|
|
|
/// Tell all windows to close.
|
|
|
|
|
///
|
|
|
|
|
/// This will synchronously trigger `WindowEvent::Destroyed` within
|
|
|
|
|
/// `windowWillClose:`, giving the application one last chance to handle
|
|
|
|
|
/// those events. It doesn't matter if the user also ends up closing the
|
|
|
|
|
/// windows in `Window`'s `Drop` impl, once a window has been closed once, it
|
|
|
|
|
/// stays closed.
|
|
|
|
|
///
|
|
|
|
|
/// This ensures that no windows linger on after the event loop has exited,
|
|
|
|
|
/// see <https://github.com/rust-windowing/winit/issues/4135>.
|
|
|
|
|
pub(super) fn notify_windows_of_exit(app: &NSApplication) {
|
|
|
|
|
for window in app.windows() {
|
|
|
|
|
window.close();
|
|
|
|
|
}
|
|
|
|
|
}
|