Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/platform/pump_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,19 +155,19 @@ pub trait EventLoopExtPumpEvents {
/// - **Windows**: The implementation will use `PeekMessage` when checking for
/// window messages to avoid blocking your external event loop.
///
/// - **MacOS**: The implementation works in terms of stopping the global `NSApp`
/// - **MacOS**: The implementation works in terms of stopping the global application
/// whenever the application `RunLoop` indicates that it is preparing to block
/// and wait for new events.
///
/// This is very different to the polling APIs that are available on other
/// platforms (the lower level polling primitives on MacOS are private
/// implementation details for `NSApp` which aren't accessible to application
/// developers)
/// implementation details for `NSApplication` which aren't accessible to
/// application developers)
///
/// It's likely this will be less efficient than polling on other OSs and
/// it also means the `NSApp` is stopped while outside of the Winit
/// it also means the `NSApplication` is stopped while outside of the Winit
/// event loop - and that's observable (for example to crates like `rfd`)
/// because the `NSApp` is global state.
/// because the `NSApplication` is global state.
///
/// If you render outside of Winit you are likely to see window resizing artifacts
/// since MacOS expects applications to render synchronously during any `drawRect`
Expand Down
5 changes: 2 additions & 3 deletions src/platform_impl/macos/app.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
#![allow(clippy::unnecessary_cast)]

use icrate::AppKit::{
NSEvent, NSEventModifierFlagCommand, NSEventTypeKeyUp, NSEventTypeLeftMouseDown,
NSApplication, NSEvent, NSEventModifierFlagCommand, NSEventTypeKeyUp, NSEventTypeLeftMouseDown,
NSEventTypeLeftMouseDragged, NSEventTypeLeftMouseUp, NSEventTypeMouseMoved,
NSEventTypeOtherMouseDown, NSEventTypeOtherMouseDragged, NSEventTypeOtherMouseUp,
NSEventTypeRightMouseDown, NSEventTypeRightMouseDragged, NSEventTypeRightMouseUp, NSResponder,
};
use icrate::Foundation::NSObject;
use objc2::{declare_class, msg_send, mutability, ClassType, DeclaredClass};

use super::appkit::NSApplication;
use super::event::flags_contains;
use super::{app_state::AppState, DEVICE_ID};
use crate::event::{DeviceEvent, ElementState, Event};
Expand Down Expand Up @@ -41,7 +40,7 @@ declare_class!(
&& flags_contains(modifier_flags, NSEventModifierFlagCommand)
{
if let Some(key_window) = self.keyWindow() {
unsafe { key_window.sendEvent(event) };
key_window.sendEvent(event);
}
} else {
maybe_dispatch_device_event(event);
Expand Down
13 changes: 8 additions & 5 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use icrate::Foundation::NSObject;
use icrate::AppKit::{NSApplicationActivationPolicy, NSApplicationDelegate};
use icrate::Foundation::{MainThreadMarker, NSObject, NSObjectProtocol};
use objc2::rc::Id;
use objc2::runtime::AnyObject;
use objc2::{declare_class, msg_send_id, mutability, ClassType, DeclaredClass};

use super::app_state::AppState;
use super::appkit::NSApplicationActivationPolicy;

#[derive(Debug)]
pub(super) struct State {
Expand All @@ -18,15 +18,17 @@ declare_class!(

unsafe impl ClassType for ApplicationDelegate {
type Super = NSObject;
type Mutability = mutability::InteriorMutable;
type Mutability = mutability::MainThreadOnly;
const NAME: &'static str = "WinitApplicationDelegate";
}

impl DeclaredClass for ApplicationDelegate {
type Ivars = State;
}

unsafe impl ApplicationDelegate {
unsafe impl NSObjectProtocol for ApplicationDelegate {}

unsafe impl NSApplicationDelegate for ApplicationDelegate {
#[method(applicationDidFinishLaunching:)]
fn did_finish_launching(&self, _sender: Option<&AnyObject>) {
trace_scope!("applicationDidFinishLaunching:");
Expand All @@ -48,11 +50,12 @@ declare_class!(

impl ApplicationDelegate {
pub(super) fn new(
mtm: MainThreadMarker,
activation_policy: NSApplicationActivationPolicy,
default_menu: bool,
activate_ignoring_other_apps: bool,
) -> Id<Self> {
let this = Self::alloc().set_ivars(State {
let this = mtm.alloc().set_ivars(State {
activation_policy,
default_menu,
activate_ignoring_other_apps,
Expand Down
43 changes: 23 additions & 20 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use std::{
};

use core_foundation::runloop::{CFRunLoopGetMain, CFRunLoopWakeUp};
use icrate::AppKit::{NSApplication, NSApplicationActivationPolicy};
use icrate::Foundation::{is_main_thread, MainThreadMarker, NSSize};
use objc2::rc::{autoreleasepool, Id};
use once_cell::sync::Lazy;

use super::appkit::{NSApp, NSApplication, NSApplicationActivationPolicy};
use super::{
event::dummy_event, event_loop::PanicInfo, menu, observer::EventLoopWaker, util::Never,
window::WinitWindow,
Expand Down Expand Up @@ -58,14 +58,14 @@ impl<T> EventLoopHandler<T> {
where
F: FnOnce(&mut EventLoopHandler<T>, RefMut<'_, dyn FnMut(Event<T>, &RootWindowTarget<T>)>),
{
// The `NSApp` and our `HANDLER` are global state and so it's possible that
// we could get a delegate callback after the application has exit an
// `NSApplication` and our `HANDLER` are global state and so it's possible
// that we could get a delegate callback after the application has exit an
// `EventLoop`. If the loop has been exit then our weak `self.callback`
// will fail to upgrade.
//
// We don't want to panic or output any verbose logging if we fail to
// upgrade the weak reference since it might be valid that the application
// re-starts the `NSApp` after exiting a Winit `EventLoop`
// re-starts the `NSApplication` after exiting a Winit `EventLoop`
if let Some(callback) = self.callback.upgrade() {
let callback = callback.borrow_mut();
(f)(self, callback);
Expand Down Expand Up @@ -145,9 +145,9 @@ impl Handler {

/// `true` after `ApplicationDelegate::applicationDidFinishLaunching` called
///
/// NB: This is global / `NSApp` state and since the app will only be launched
/// once but an `EventLoop` may be run more than once then only the first
/// `EventLoop` will observe the `NSApp` before it is launched.
/// NB: This is global / `NSApplication` state and since the app will only
/// be launched once but an `EventLoop` may be run more than once then only
/// the first `EventLoop` will observe the application before it is launched.
fn is_launched(&self) -> bool {
self.launched.load(Ordering::Acquire)
}
Expand All @@ -159,16 +159,16 @@ impl Handler {

/// `true` if an `EventLoop` is currently running
///
/// NB: This is global / `NSApp` state and may persist beyond the lifetime of
/// a running `EventLoop`.
/// NB: This is global / `NSApplication` state and may persist beyond the
/// lifetime of a running `EventLoop`.
///
/// # Caveat
/// This is only intended to be called from the main thread
fn is_running(&self) -> bool {
self.running.load(Ordering::Relaxed)
}

/// Set when an `EventLoop` starts running, after the `NSApp` is launched
/// Set when an `EventLoop` starts running, after the `NSApplication` is launched
///
/// # Caveat
/// This is only intended to be called from the main thread
Expand All @@ -181,8 +181,8 @@ impl Handler {
/// Since an `EventLoop` may be run more than once we need make sure to reset the
/// `control_flow` state back to `Poll` each time the loop exits.
///
/// Note: that if the `NSApp` has been launched then that state is preserved, and we won't
/// need to re-launch the app if subsequent EventLoops are run.
/// Note: that if the `NSApplication` has been launched then that state is preserved,
/// and we won't need to re-launch the app if subsequent EventLoops are run.
///
/// # Caveat
/// This is only intended to be called from the main thread
Expand Down Expand Up @@ -393,7 +393,7 @@ impl AppState {
}

// If `pump_events` is called to progress the event loop then we bootstrap the event
// loop via `[NSApp run]` but will use `CFRunLoopRunInMode` for subsequent calls to
// loop via `-[NSAppplication run]` but will use `CFRunLoopRunInMode` for subsequent calls to
// `pump_events`
pub fn request_stop_on_launch() {
HANDLER.request_stop_app_on_launch();
Expand Down Expand Up @@ -461,35 +461,37 @@ impl AppState {
activate_ignoring_other_apps: bool,
) {
let mtm = MainThreadMarker::new().unwrap();
let app = NSApp();
let app = NSApplication::sharedApplication(mtm);
// We need to delay setting the activation policy and activating the app
// until `applicationDidFinishLaunching` has been called. Otherwise the
// menu bar is initially unresponsive on macOS 10.15.
app.setActivationPolicy(activation_policy);

window_activation_hack(&app);
#[allow(deprecated)]
app.activateIgnoringOtherApps(activate_ignoring_other_apps);

HANDLER.set_launched();
HANDLER.waker().start();
if create_default_menu {
// The menubar initialization should be before the `NewEvents` event, to allow
// overriding of the default menu even if it's created
menu::initialize(mtm);
menu::initialize(&app);
}

Self::start_running();

// If the `NSApp` is being launched via `EventLoop::pump_events()` then we'll
// If the application is being launched via `EventLoop::pump_events()` then we'll
// want to stop the app once it is launched (and return to the external loop)
//
// In this case we still want to consider Winit's `EventLoop` to be "running",
// so we call `start_running()` above.
if HANDLER.should_stop_app_on_launch() {
// Note: the original idea had been to only stop the underlying `RunLoop`
// for the app but that didn't work as expected (`[NSApp run]` effectively
// ignored the attempt to stop the RunLoop and re-started it.). So we
// return from `pump_events` by stopping the `NSApp`
// for the app but that didn't work as expected (`-[NSApplication run]`
// effectively ignored the attempt to stop the RunLoop and re-started it).
//
// So we return from `pump_events` by stopping the application.
Self::stop();
}
}
Expand Down Expand Up @@ -591,7 +593,8 @@ impl AppState {
}

pub fn stop() {
let app = NSApp();
let mtm = MainThreadMarker::new().unwrap();
let app = NSApplication::sharedApplication(mtm);
autoreleasepool(|_| {
app.stop(None);
// To stop event loop immediately, we need to post some event here.
Expand Down
144 changes: 0 additions & 144 deletions src/platform_impl/macos/appkit/application.rs

This file was deleted.

Loading