Swizzle sendEvent: instead of subclassing NSApplication (#4036)
This is done to avoid order-dependent behavior that you'd otherwise encounter where `EventLoop::new` had to be called at the beginning of `fn main` to ensure that Winit's application was the one being registered as the main application by calling `sharedApplication`. Fixes https://github.com/rust-windowing/winit/issues/3772. This should also make it (more) possible to use multiple versions of Winit in the same application (though that's still untested). Finally, it should allow the user to override `NSApplication` themselves if they need to do that for some reason.
This commit is contained in:
parent
4d6fe7e35c
commit
675582bd46
3 changed files with 145 additions and 42 deletions
|
|
@ -10,7 +10,7 @@ use std::time::{Duration, Instant};
|
|||
|
||||
use objc2::rc::{autoreleasepool, Retained};
|
||||
use objc2::runtime::ProtocolObject;
|
||||
use objc2::{available, msg_send, ClassType, MainThreadMarker};
|
||||
use objc2::{available, MainThreadMarker};
|
||||
use objc2_app_kit::{
|
||||
NSApplication, NSApplicationActivationPolicy, NSApplicationDidFinishLaunchingNotification,
|
||||
NSApplicationWillTerminateNotification, NSWindow,
|
||||
|
|
@ -24,7 +24,7 @@ use objc2_foundation::{NSNotificationCenter, NSObjectProtocol};
|
|||
use rwh_06::HasDisplayHandle;
|
||||
|
||||
use super::super::notification_center::create_observer;
|
||||
use super::app::WinitApplication;
|
||||
use super::app::override_send_event;
|
||||
use super::app_state::AppState;
|
||||
use super::cursor::CustomCursor;
|
||||
use super::event::dummy_event;
|
||||
|
|
@ -209,16 +209,6 @@ impl EventLoop {
|
|||
let mtm = MainThreadMarker::new()
|
||||
.expect("on macOS, `EventLoop` must be created on the main thread!");
|
||||
|
||||
let app: Retained<NSApplication> =
|
||||
unsafe { msg_send![WinitApplication::class(), sharedApplication] };
|
||||
|
||||
if !app.isKindOfClass(WinitApplication::class()) {
|
||||
panic!(
|
||||
"`winit` requires control over the principal class. You must create the event \
|
||||
loop before other parts of your application initialize NSApplication"
|
||||
);
|
||||
}
|
||||
|
||||
let activation_policy = match attributes.activation_policy {
|
||||
None => None,
|
||||
Some(ActivationPolicy::Regular) => Some(NSApplicationActivationPolicy::Regular),
|
||||
|
|
@ -233,6 +223,12 @@ impl EventLoop {
|
|||
attributes.activate_ignoring_other_apps,
|
||||
);
|
||||
|
||||
// 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);
|
||||
|
||||
let center = unsafe { NSNotificationCenter::defaultCenter() };
|
||||
|
||||
let weak_app_state = Rc::downgrade(&app_state);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue