mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Compare commits
10 Commits
madsmtm/ev
...
madsmtm/la
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9efc50a262 | ||
|
|
117ec364f9 | ||
|
|
9f789e56ee | ||
|
|
91558169d2 | ||
|
|
4998cb990f | ||
|
|
98692641c4 | ||
|
|
a630b5333c | ||
|
|
ca7735f10b | ||
|
|
7adb805011 | ||
|
|
a8c7d809b9 |
@@ -60,7 +60,6 @@ objc2-core-foundation = { version = "0.3.2", default-features = false }
|
||||
objc2-core-graphics = { version = "0.3.2", default-features = false }
|
||||
objc2-core-video = { version = "0.3.2", default-features = false }
|
||||
objc2-foundation = { version = "0.3.2", default-features = false }
|
||||
objc2-quartz-core = { version = "0.3.2", default-features = false }
|
||||
objc2-ui-kit = { version = "0.3.2", default-features = false }
|
||||
|
||||
# Windows dependencies.
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
# Using allow-invalid because this is platform-specific code
|
||||
disallowed-macros = [
|
||||
{ path = "std::print", reason = "works badly on web", replacement = "tracing::info" },
|
||||
{ path = "std::println", reason = "works badly on web", replacement = "tracing::info" },
|
||||
{ path = "std::eprint", reason = "works badly on web", replacement = "tracing::error" },
|
||||
{ path = "std::eprintln", reason = "works badly on web", replacement = "tracing::error" },
|
||||
{ path = "std::dbg", reason = "leftover debugging aid, remove it or use tracing" },
|
||||
]
|
||||
disallowed-methods = [
|
||||
{ allow-invalid = true, path = "objc2_app_kit::NSView::visibleRect", reason = "We expose a render target to the user, and visibility is not really relevant to that (and can break if you don't use the rectangle position as well). Use `frame` instead." },
|
||||
{ allow-invalid = true, path = "objc2_app_kit::NSWindow::setFrameTopLeftPoint", reason = "Not sufficient when working with Winit's coordinate system, use `flip_window_screen_coordinates` instead" },
|
||||
|
||||
@@ -107,7 +107,6 @@ objc2-foundation = { workspace = true, features = [
|
||||
"NSThread",
|
||||
"NSValue",
|
||||
] }
|
||||
objc2-quartz-core = { workspace = true, features = ["std", "CABase"] }
|
||||
winit-common = { workspace = true, features = ["core-foundation", "event-handler"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -9,6 +9,7 @@ use objc2::runtime::{Imp, Sel};
|
||||
use objc2::sel;
|
||||
use objc2_app_kit::{NSApplication, NSEvent, NSEventModifierFlags, NSEventType};
|
||||
use objc2_foundation::MainThreadMarker;
|
||||
use tracing::trace_span;
|
||||
use winit_core::event::{DeviceEvent, ElementState};
|
||||
|
||||
use super::app_state::AppState;
|
||||
@@ -21,6 +22,10 @@ static ORIGINAL: MainThreadBound<Cell<Option<SendEvent>>> = {
|
||||
};
|
||||
|
||||
extern "C-unwind" fn send_event(app: &NSApplication, sel: Sel, event: &NSEvent) {
|
||||
// This can be a bit noisy, since `event` is fairly large. Note that you can use
|
||||
// `RUST_LOG='trace,winit_appkit::app=warn'` if you're debugging and want TRACE-level logs but
|
||||
// not this.
|
||||
let _entered = trace_span!("sendEvent:", ?event).entered();
|
||||
let mtm = MainThreadMarker::from(app);
|
||||
|
||||
// Normally, holding Cmd + any key never sends us a `keyUp` event for that key.
|
||||
@@ -98,7 +103,6 @@ pub(crate) fn override_send_event(global_app: &NSApplication) {
|
||||
}
|
||||
|
||||
fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
||||
let time = app_state.event_time(event);
|
||||
let event_type = event.r#type();
|
||||
#[allow(non_upper_case_globals)]
|
||||
match event_type {
|
||||
@@ -111,7 +115,7 @@ fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
||||
|
||||
if delta_x != 0.0 || delta_y != 0.0 {
|
||||
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.device_event(event_loop, None, time, DeviceEvent::PointerMotion {
|
||||
app.device_event(event_loop, None, DeviceEvent::PointerMotion {
|
||||
delta: (delta_x, delta_y),
|
||||
});
|
||||
});
|
||||
@@ -120,7 +124,7 @@ fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
||||
NSEventType::LeftMouseDown | NSEventType::RightMouseDown | NSEventType::OtherMouseDown => {
|
||||
let button = event.buttonNumber() as u32;
|
||||
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.device_event(event_loop, None, time, DeviceEvent::Button {
|
||||
app.device_event(event_loop, None, DeviceEvent::Button {
|
||||
button,
|
||||
state: ElementState::Pressed,
|
||||
});
|
||||
@@ -129,7 +133,7 @@ fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
||||
NSEventType::LeftMouseUp | NSEventType::RightMouseUp | NSEventType::OtherMouseUp => {
|
||||
let button = event.buttonNumber() as u32;
|
||||
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.device_event(event_loop, None, time, DeviceEvent::Button {
|
||||
app.device_event(event_loop, None, DeviceEvent::Button {
|
||||
button,
|
||||
state: ElementState::Released,
|
||||
});
|
||||
|
||||
@@ -2,14 +2,11 @@ use std::cell::{Cell, OnceCell, RefCell};
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::time::Instant;
|
||||
|
||||
use dispatch2::MainThreadBound;
|
||||
use objc2::MainThreadMarker;
|
||||
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSEvent, NSRunningApplication};
|
||||
use objc2_foundation::{NSNotification, NSTimeInterval};
|
||||
use objc2_quartz_core::CACurrentMediaTime;
|
||||
use tracing::warn;
|
||||
use objc2_app_kit::NSApplication;
|
||||
use winit_common::core_foundation::{EventLoopProxy, MainRunLoop};
|
||||
use winit_common::event_handler::EventHandler;
|
||||
use winit_core::application::ApplicationHandler;
|
||||
@@ -18,24 +15,17 @@ use winit_core::event_loop::ControlFlow;
|
||||
use winit_core::window::WindowId;
|
||||
|
||||
use super::event_loop::{ActiveEventLoop, notify_windows_of_exit, stop_app_immediately};
|
||||
use super::menu;
|
||||
use super::observer::EventLoopWaker;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AppState {
|
||||
mtm: MainThreadMarker,
|
||||
activation_policy: Option<NSApplicationActivationPolicy>,
|
||||
default_menu: bool,
|
||||
activate_ignoring_other_apps: bool,
|
||||
run_loop: MainRunLoop,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
event_handler: EventHandler,
|
||||
stop_on_launch: Cell<bool>,
|
||||
stop_before_wait: Cell<bool>,
|
||||
stop_after_wait: Cell<bool>,
|
||||
stop_on_redraw: Cell<bool>,
|
||||
/// Whether `applicationDidFinishLaunching:` has been run or not.
|
||||
is_launched: Cell<bool>,
|
||||
/// Whether an `EventLoop` is currently running.
|
||||
is_running: Cell<bool>,
|
||||
/// Whether the user has requested the event loop to exit.
|
||||
@@ -45,8 +35,6 @@ pub(super) struct AppState {
|
||||
start_time: Cell<Option<Instant>>,
|
||||
wait_timeout: Cell<Option<Instant>>,
|
||||
pending_redraw: RefCell<Vec<WindowId>>,
|
||||
startup_instant: Instant,
|
||||
startup_timestamp: NSTimeInterval,
|
||||
// NOTE: This is strongly referenced by our `NSWindowDelegate` and our `NSView` subclass, and
|
||||
// as such should be careful to not add fields that, in turn, strongly reference those.
|
||||
}
|
||||
@@ -57,40 +45,19 @@ static GLOBAL: MainThreadBound<OnceCell<Rc<AppState>>> =
|
||||
MainThreadBound::new(OnceCell::new(), unsafe { MainThreadMarker::new_unchecked() });
|
||||
|
||||
impl AppState {
|
||||
pub(super) fn setup_global(
|
||||
mtm: MainThreadMarker,
|
||||
activation_policy: Option<NSApplicationActivationPolicy>,
|
||||
default_menu: bool,
|
||||
activate_ignoring_other_apps: bool,
|
||||
) -> Option<Rc<Self>> {
|
||||
pub(super) fn setup_global(mtm: MainThreadMarker) -> Option<Rc<Self>> {
|
||||
let event_loop_proxy = Arc::new(EventLoopProxy::new(mtm, move || {
|
||||
Self::get(mtm).with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
|
||||
}));
|
||||
|
||||
// Prime dylib caches etc.
|
||||
let _ = CACurrentMediaTime();
|
||||
|
||||
// Find the current Rust timestamp.
|
||||
let startup_instant = Instant::now();
|
||||
// Find the timestamp
|
||||
//
|
||||
// `NSProcessInfo::processInfo().systemUptime()` needs the required reason manifest,
|
||||
// `CACurrentMediaTime` (currently) doesn't, so we use that instead.
|
||||
let startup_timestamp = CACurrentMediaTime();
|
||||
|
||||
let this = Rc::new(Self {
|
||||
mtm,
|
||||
activation_policy,
|
||||
default_menu,
|
||||
activate_ignoring_other_apps,
|
||||
run_loop: MainRunLoop::get(mtm),
|
||||
event_loop_proxy,
|
||||
event_handler: EventHandler::new(),
|
||||
stop_on_launch: Cell::new(false),
|
||||
stop_before_wait: Cell::new(false),
|
||||
stop_after_wait: Cell::new(false),
|
||||
stop_on_redraw: Cell::new(false),
|
||||
is_launched: Cell::new(false),
|
||||
is_running: Cell::new(false),
|
||||
exit: Cell::new(false),
|
||||
control_flow: Cell::new(ControlFlow::default()),
|
||||
@@ -98,8 +65,6 @@ impl AppState {
|
||||
start_time: Cell::new(None),
|
||||
wait_timeout: Cell::new(None),
|
||||
pending_redraw: RefCell::new(vec![]),
|
||||
startup_instant,
|
||||
startup_timestamp,
|
||||
});
|
||||
|
||||
GLOBAL.get(mtm).set(this.clone()).ok().and(Some(this))
|
||||
@@ -113,81 +78,6 @@ impl AppState {
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn event_time(&self, event: &NSEvent) -> Instant {
|
||||
if event.timestamp() == 0.0 {
|
||||
warn!(?event, "got zero timestamp");
|
||||
return Instant::now();
|
||||
}
|
||||
let duration_since_startup = event.timestamp() - self.startup_timestamp;
|
||||
let duration_since_startup = Duration::from_secs_f64(duration_since_startup as f64);
|
||||
self.startup_instant + duration_since_startup
|
||||
}
|
||||
|
||||
// NOTE: This notification will, globally, only be emitted once,
|
||||
// no matter how many `EventLoop`s the user creates.
|
||||
pub fn did_finish_launching(self: &Rc<Self>, _notification: &NSNotification) {
|
||||
trace_scope!("NSApplicationDidFinishLaunchingNotification");
|
||||
self.is_launched.set(true);
|
||||
|
||||
let app = NSApplication::sharedApplication(self.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.
|
||||
if let Some(activation_policy) = self.activation_policy {
|
||||
app.setActivationPolicy(activation_policy);
|
||||
} else {
|
||||
// If no activation policy is explicitly provided, and the application
|
||||
// is bundled, do not set the activation policy at all, to allow the
|
||||
// package manifest to define the behavior via LSUIElement.
|
||||
//
|
||||
// See:
|
||||
// - https://github.com/rust-windowing/winit/issues/261
|
||||
// - https://github.com/rust-windowing/winit/issues/3958
|
||||
let is_bundled =
|
||||
NSRunningApplication::currentApplication().bundleIdentifier().is_some();
|
||||
if !is_bundled {
|
||||
app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
app.activateIgnoringOtherApps(self.activate_ignoring_other_apps);
|
||||
|
||||
if self.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(&app);
|
||||
}
|
||||
|
||||
self.waker.borrow_mut().start();
|
||||
|
||||
self.set_is_running(true);
|
||||
self.dispatch_init_events();
|
||||
|
||||
// If the application is being launched via `EventLoop::pump_app_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 self.stop_on_launch.get() {
|
||||
// NOTE: the original idea had been to only stop the underlying `RunLoop`
|
||||
// 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.
|
||||
let app = NSApplication::sharedApplication(self.mtm);
|
||||
stop_app_immediately(&app);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn will_terminate(self: &Rc<Self>, _notification: &NSNotification) {
|
||||
trace_scope!("NSApplicationWillTerminateNotification");
|
||||
let app = NSApplication::sharedApplication(self.mtm);
|
||||
notify_windows_of_exit(&app);
|
||||
self.event_handler.terminate();
|
||||
self.internal_exit();
|
||||
}
|
||||
|
||||
/// Place the event handler in the application state for the duration
|
||||
/// of the given closure.
|
||||
pub fn set_event_handler<R>(
|
||||
@@ -198,15 +88,12 @@ impl AppState {
|
||||
self.event_handler.set(Box::new(handler), closure)
|
||||
}
|
||||
|
||||
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||
&self.event_loop_proxy
|
||||
pub fn terminate_event_handler(&self) {
|
||||
self.event_handler.terminate();
|
||||
}
|
||||
|
||||
/// If `pump_events` is called to progress the event loop then we
|
||||
/// bootstrap the event loop via `-[NSApplication run]` but will use
|
||||
/// `CFRunLoopRunInMode` for subsequent calls to `pump_events`.
|
||||
pub fn set_stop_on_launch(&self) {
|
||||
self.stop_on_launch.set(true);
|
||||
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||
&self.event_loop_proxy
|
||||
}
|
||||
|
||||
pub fn set_stop_before_wait(&self, value: bool) {
|
||||
@@ -237,10 +124,6 @@ impl AppState {
|
||||
self.set_wait_timeout(None);
|
||||
}
|
||||
|
||||
pub fn is_launched(&self) -> bool {
|
||||
self.is_launched.get()
|
||||
}
|
||||
|
||||
pub fn set_is_running(&self, value: bool) {
|
||||
self.is_running.set(value)
|
||||
}
|
||||
@@ -274,12 +157,7 @@ impl AppState {
|
||||
// -> Don't go back into the event handler when our callstack originates from there
|
||||
if !self.event_handler.in_use() {
|
||||
self.with_handler(|app, event_loop| {
|
||||
app.window_event(
|
||||
event_loop,
|
||||
window_id,
|
||||
Instant::now(),
|
||||
WindowEvent::RedrawRequested,
|
||||
);
|
||||
app.window_event(event_loop, window_id, WindowEvent::RedrawRequested);
|
||||
});
|
||||
|
||||
// `pump_events` will request to stop immediately _after_ dispatching RedrawRequested
|
||||
@@ -379,12 +257,7 @@ impl AppState {
|
||||
let redraw = mem::take(&mut *self.pending_redraw.borrow_mut());
|
||||
for window_id in redraw {
|
||||
self.with_handler(|app, event_loop| {
|
||||
app.window_event(
|
||||
event_loop,
|
||||
window_id,
|
||||
Instant::now(),
|
||||
WindowEvent::RedrawRequested,
|
||||
);
|
||||
app.window_event(event_loop, window_id, WindowEvent::RedrawRequested);
|
||||
});
|
||||
}
|
||||
self.with_handler(|app, event_loop| {
|
||||
|
||||
@@ -5,7 +5,10 @@ use std::sync::OnceLock;
|
||||
use objc2::rc::Retained;
|
||||
use objc2::runtime::Sel;
|
||||
use objc2::{AllocAnyThread, ClassType, available, msg_send, sel};
|
||||
use objc2_app_kit::{NSBitmapImageRep, NSCursor, NSDeviceRGBColorSpace, NSImage};
|
||||
use objc2_app_kit::{
|
||||
NSBitmapImageRep, NSCursor, NSCursorFrameResizeDirections, NSCursorFrameResizePosition,
|
||||
NSDeviceRGBColorSpace, NSImage,
|
||||
};
|
||||
use objc2_foundation::{
|
||||
NSData, NSDictionary, NSNumber, NSObject, NSPoint, NSSize, NSString, ns_string,
|
||||
};
|
||||
@@ -204,23 +207,155 @@ pub(crate) fn cursor_from_icon(icon: CursorIcon) -> Retained<NSCursor> {
|
||||
CursorIcon::NotAllowed | CursorIcon::NoDrop => NSCursor::operationNotAllowedCursor(),
|
||||
CursorIcon::ContextMenu => NSCursor::contextualMenuCursor(),
|
||||
CursorIcon::Crosshair => NSCursor::crosshairCursor(),
|
||||
CursorIcon::EResize => NSCursor::resizeRightCursor(),
|
||||
CursorIcon::NResize => NSCursor::resizeUpCursor(),
|
||||
CursorIcon::WResize => NSCursor::resizeLeftCursor(),
|
||||
CursorIcon::SResize => NSCursor::resizeDownCursor(),
|
||||
CursorIcon::EwResize | CursorIcon::ColResize => NSCursor::resizeLeftRightCursor(),
|
||||
CursorIcon::NsResize | CursorIcon::RowResize => NSCursor::resizeUpDownCursor(),
|
||||
CursorIcon::EResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::Right,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
NSCursor::resizeRightCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::NResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::Top,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
NSCursor::resizeUpCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::WResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::Left,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
NSCursor::resizeLeftCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::SResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::Bottom,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
NSCursor::resizeDownCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::EwResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::Right,
|
||||
NSCursorFrameResizeDirections::All,
|
||||
)
|
||||
} else {
|
||||
NSCursor::resizeLeftRightCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::NsResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::Top,
|
||||
NSCursorFrameResizeDirections::All,
|
||||
)
|
||||
} else {
|
||||
NSCursor::resizeUpDownCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::NeResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::TopRight,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
_windowResizeNorthEastCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::NwResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::TopLeft,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
_windowResizeNorthWestCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::SeResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::BottomRight,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
_windowResizeSouthEastCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::SwResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::BottomLeft,
|
||||
NSCursorFrameResizeDirections::Outward,
|
||||
)
|
||||
} else {
|
||||
_windowResizeSouthWestCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::NeswResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::TopRight,
|
||||
NSCursorFrameResizeDirections::All,
|
||||
)
|
||||
} else {
|
||||
_windowResizeNorthEastSouthWestCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::NwseResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::frameResizeCursorFromPosition_inDirections(
|
||||
NSCursorFrameResizePosition::TopLeft,
|
||||
NSCursorFrameResizeDirections::All,
|
||||
)
|
||||
} else {
|
||||
_windowResizeNorthWestSouthEastCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::ColResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::columnResizeCursor()
|
||||
} else {
|
||||
NSCursor::resizeLeftRightCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::RowResize => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::rowResizeCursor()
|
||||
} else {
|
||||
NSCursor::resizeUpDownCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::ZoomIn => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::zoomInCursor()
|
||||
} else {
|
||||
_zoomInCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::ZoomOut => {
|
||||
if available!(macos = 15.0) {
|
||||
NSCursor::zoomOutCursor()
|
||||
} else {
|
||||
_zoomOutCursor()
|
||||
}
|
||||
},
|
||||
CursorIcon::Help => _helpCursor(),
|
||||
CursorIcon::ZoomIn if available!(macos = 15.0) => NSCursor::zoomInCursor(),
|
||||
CursorIcon::ZoomIn => _zoomInCursor(),
|
||||
CursorIcon::ZoomOut if available!(macos = 15.0) => NSCursor::zoomOutCursor(),
|
||||
CursorIcon::ZoomOut => _zoomOutCursor(),
|
||||
CursorIcon::NeResize => _windowResizeNorthEastCursor(),
|
||||
CursorIcon::NwResize => _windowResizeNorthWestCursor(),
|
||||
CursorIcon::SeResize => _windowResizeSouthEastCursor(),
|
||||
CursorIcon::SwResize => _windowResizeSouthWestCursor(),
|
||||
CursorIcon::NeswResize => _windowResizeNorthEastSouthWestCursor(),
|
||||
CursorIcon::NwseResize => _windowResizeNorthWestSouthEastCursor(),
|
||||
// This is the wrong semantics for `Wait`, but it's the same as
|
||||
// what's used in Safari and Chrome.
|
||||
CursorIcon::Wait | CursorIcon::Progress => busyButClickableCursor(),
|
||||
|
||||
@@ -7,12 +7,13 @@ use objc2::runtime::ProtocolObject;
|
||||
use objc2::{MainThreadMarker, available};
|
||||
use objc2_app_kit::{
|
||||
NSApplication, NSApplicationActivationPolicy, NSApplicationDidFinishLaunchingNotification,
|
||||
NSApplicationWillTerminateNotification, NSWindow,
|
||||
NSApplicationWillTerminateNotification, NSRunningApplication, NSWindow,
|
||||
};
|
||||
use objc2_core_foundation::{CFIndex, CFRunLoopActivity, kCFRunLoopCommonModes};
|
||||
use objc2_foundation::{NSNotificationCenter, NSObjectProtocol};
|
||||
use rwh_06::HasDisplayHandle;
|
||||
use winit_common::core_foundation::{MainRunLoop, MainRunLoopObserver};
|
||||
use tracing::debug_span;
|
||||
use winit_common::core_foundation::{MainRunLoop, MainRunLoopObserver, tracing_observers};
|
||||
use winit_core::application::ApplicationHandler;
|
||||
use winit_core::cursor::{CustomCursor as CoreCustomCursor, CustomCursorSource};
|
||||
use winit_core::error::{EventLoopError, RequestError};
|
||||
@@ -30,8 +31,8 @@ use super::cursor::CustomCursor;
|
||||
use super::event::dummy_event;
|
||||
use super::monitor;
|
||||
use super::notification_center::create_observer;
|
||||
use crate::ActivationPolicy;
|
||||
use crate::window::Window;
|
||||
use crate::{ActivationPolicy, menu};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ActiveEventLoop {
|
||||
@@ -149,9 +150,9 @@ pub struct EventLoop {
|
||||
// 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.
|
||||
_did_finish_launching_observer: Retained<ProtocolObject<dyn NSObjectProtocol>>,
|
||||
_will_terminate_observer: Retained<ProtocolObject<dyn NSObjectProtocol>>,
|
||||
|
||||
_tracing_observers: Option<(MainRunLoopObserver, MainRunLoopObserver)>,
|
||||
_before_waiting_observer: MainRunLoopObserver,
|
||||
_after_waiting_observer: MainRunLoopObserver,
|
||||
}
|
||||
@@ -174,20 +175,8 @@ impl EventLoop {
|
||||
let mtm = MainThreadMarker::new()
|
||||
.expect("on macOS, `EventLoop` must be created on the main thread!");
|
||||
|
||||
let activation_policy = match attributes.activation_policy {
|
||||
None => None,
|
||||
Some(ActivationPolicy::Regular) => Some(NSApplicationActivationPolicy::Regular),
|
||||
Some(ActivationPolicy::Accessory) => Some(NSApplicationActivationPolicy::Accessory),
|
||||
Some(ActivationPolicy::Prohibited) => Some(NSApplicationActivationPolicy::Prohibited),
|
||||
};
|
||||
|
||||
let app_state = AppState::setup_global(
|
||||
mtm,
|
||||
activation_policy,
|
||||
attributes.default_menu,
|
||||
attributes.activate_ignoring_other_apps,
|
||||
)
|
||||
.ok_or_else(|| EventLoopError::RecreationAttempt)?;
|
||||
let app_state =
|
||||
AppState::setup_global(mtm).ok_or_else(|| EventLoopError::RecreationAttempt)?;
|
||||
|
||||
// Initialize the application (if it has not already been).
|
||||
let app = NSApplication::sharedApplication(mtm);
|
||||
@@ -197,41 +186,50 @@ impl EventLoop {
|
||||
|
||||
let center = 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);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Handle `terminate:`. This may happen if:
|
||||
// - The user uses the context menu in the Dock icon.
|
||||
// - Or the `Quit` menu item we install with the default menu (including via. the keyboard
|
||||
// shortcut).
|
||||
// - Maybe other cases?
|
||||
//
|
||||
// In these cases, AppKit is going to call `std::process::exit`, so we won't get the chance
|
||||
// to return to the user from `EventLoop::run_app`. So we have to clean up and drop their
|
||||
// windows and application here too.
|
||||
let weak_app_state = Rc::downgrade(&app_state);
|
||||
let _will_terminate_observer = create_observer(
|
||||
¢er,
|
||||
// `applicationWillTerminate:`
|
||||
unsafe { NSApplicationWillTerminateNotification },
|
||||
move |notification| {
|
||||
let _entered = debug_span!("applicationWillTerminate").entered();
|
||||
|
||||
let app = notification.object().unwrap().downcast::<NSApplication>().unwrap();
|
||||
notify_windows_of_exit(&app);
|
||||
|
||||
if let Some(app_state) = weak_app_state.upgrade() {
|
||||
app_state.will_terminate(notification);
|
||||
app_state.terminate_event_handler();
|
||||
app_state.internal_exit();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Set up run loop observers for calling `new_events` and `about_to_wait`.
|
||||
let main_loop = MainRunLoop::get(mtm);
|
||||
let mode = unsafe { kCFRunLoopCommonModes }.unwrap();
|
||||
|
||||
// Tracing observers have the lowest and highest orderings.
|
||||
let _tracing_observers = tracing_observers(mtm).inspect(|(start, end)| {
|
||||
main_loop.add_observer(start, mode);
|
||||
main_loop.add_observer(end, mode);
|
||||
});
|
||||
|
||||
let app_state_clone = Rc::clone(&app_state);
|
||||
let _before_waiting_observer = MainRunLoopObserver::new(
|
||||
mtm,
|
||||
CFRunLoopActivity::BeforeWaiting,
|
||||
true,
|
||||
// Queued with the lowest priority to ensure it is processed after other observers.
|
||||
// Without that, we'd get a `LoopExiting` after `AboutToWait`.
|
||||
CFIndex::MAX,
|
||||
// Queued with the second-lowest priority (tracing observers use the lowest) to ensure
|
||||
// it is processed after other observers.
|
||||
CFIndex::MAX - 1,
|
||||
move |_| app_state_clone.cleared(),
|
||||
);
|
||||
main_loop.add_observer(&_before_waiting_observer, mode);
|
||||
@@ -241,18 +239,109 @@ impl EventLoop {
|
||||
mtm,
|
||||
CFRunLoopActivity::AfterWaiting,
|
||||
true,
|
||||
// Queued with the highest priority to ensure it is processed before other observers.
|
||||
CFIndex::MIN,
|
||||
// Queued with the second-highest priority (tracing observers use the highest) to
|
||||
// ensure it is processed before other observers.
|
||||
CFIndex::MIN + 1,
|
||||
move |_| app_state_clone.wakeup(),
|
||||
);
|
||||
main_loop.add_observer(&_after_waiting_observer, mode);
|
||||
|
||||
// Run `finishLaunching` just in case it works.
|
||||
app.finishLaunching();
|
||||
// Now _ideally_, calling `finishLaunching` should be enough for the application to, you
|
||||
// know, launch (create the a dock icon etc.), but unfortunately, this doesn't happen for
|
||||
// various godforsaken reasons... The only way to make the application properly launch is by
|
||||
// calling `NSApplication::run`.
|
||||
//
|
||||
// So we check if the application hasn't finished launching, and if it hasn't, we run it
|
||||
// once to finish it.
|
||||
//
|
||||
// This is _very_ important, there's a _lot_ of weird and subtle state that requires that
|
||||
// the application is launched properly, including window creation, the menu bar,
|
||||
// activation, see:
|
||||
// - https://github.com/rust-windowing/winit/pull/1903
|
||||
// - https://github.com/rust-windowing/winit/pull/1922
|
||||
// - https://github.com/rust-windowing/winit/issues/2238
|
||||
// - https://github.com/rust-windowing/winit/issues/2051
|
||||
// - https://github.com/rust-windowing/winit/issues/2087
|
||||
// - https://developer.apple.com/forums/thread/772169
|
||||
//
|
||||
// This approach is similar to what other cross-platform windowing libraries do (except that
|
||||
// we do it without a delegate to allow users to override that):
|
||||
// - GLFW delegate: https://github.com/glfw/glfw/blob/3.4/src/cocoa_init.m#L439-L443
|
||||
// - GLFW launch: https://github.com/glfw/glfw/blob/3.4/src/cocoa_init.m#L634-L635
|
||||
// - FLTK delegate: https://github.com/fltk/fltk/blob/release-1.4.4/src/Fl_cocoa.mm#L1604-L1607
|
||||
// - FLTK launch: https://github.com/fltk/fltk/blob/release-1.4.4/src/Fl_cocoa.mm#L1903-L1919
|
||||
// - Stackoverflow issue: https://stackoverflow.com/questions/48020222/how-to-make-nsapp-run-not-block/67626393#67626393
|
||||
if !NSRunningApplication::currentApplication().isFinishedLaunching() {
|
||||
// Register an observer to stop the application immediately after launching.
|
||||
//
|
||||
// NOTE: This notification will, globally, only be emitted once, no matter how many
|
||||
// `EventLoop`s the user creates. We detect it with `isFinishedLaunching` above.
|
||||
let did_finish_launching_observer = create_observer(
|
||||
¢er,
|
||||
unsafe { NSApplicationDidFinishLaunchingNotification },
|
||||
move |notification| {
|
||||
let _entered = debug_span!("applicationDidFinishLaunching").entered();
|
||||
|
||||
let app = notification.object().unwrap().downcast::<NSApplication>().unwrap();
|
||||
|
||||
// Stop the application, to make the `app.run()` call below return.
|
||||
stop_app_immediately(&app);
|
||||
},
|
||||
);
|
||||
|
||||
// We call `stop_app_immediately` above, so this should return after launching.
|
||||
app.run();
|
||||
|
||||
// The observer should've been called at this point.
|
||||
drop(did_finish_launching_observer);
|
||||
|
||||
// We _could_ keep trying if we failed to initialize, but that would potentially lead
|
||||
// to an infinite loop, it's probably better to just continue.
|
||||
debug_assert!(NSRunningApplication::currentApplication().isFinishedLaunching());
|
||||
}
|
||||
|
||||
// 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.
|
||||
if let Some(activation_policy) = attributes.activation_policy {
|
||||
app.setActivationPolicy(match activation_policy {
|
||||
ActivationPolicy::Regular => NSApplicationActivationPolicy::Regular,
|
||||
ActivationPolicy::Accessory => NSApplicationActivationPolicy::Accessory,
|
||||
ActivationPolicy::Prohibited => NSApplicationActivationPolicy::Prohibited,
|
||||
});
|
||||
} else {
|
||||
// If no activation policy is explicitly provided, and the application
|
||||
// is bundled, do not set the activation policy at all, to allow the
|
||||
// package manifest to define the behavior via LSUIElement.
|
||||
//
|
||||
// See:
|
||||
// - https://github.com/rust-windowing/winit/issues/261
|
||||
// - https://github.com/rust-windowing/winit/issues/3958
|
||||
let is_bundled =
|
||||
NSRunningApplication::currentApplication().bundleIdentifier().is_some();
|
||||
if !is_bundled {
|
||||
app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use `app.activate()` instead on newer OS versions?
|
||||
#[expect(deprecated)]
|
||||
app.activateIgnoringOtherApps(attributes.activate_ignoring_other_apps);
|
||||
|
||||
if attributes.default_menu {
|
||||
// The default menubar initialization should be before everything else, to allow
|
||||
// overriding it even if it's created.
|
||||
menu::initialize(&app);
|
||||
}
|
||||
|
||||
Ok(EventLoop {
|
||||
app,
|
||||
app_state: app_state.clone(),
|
||||
window_target: ActiveEventLoop { app_state, mtm },
|
||||
_did_finish_launching_observer,
|
||||
_will_terminate_observer,
|
||||
_tracing_observers,
|
||||
_before_waiting_observer,
|
||||
_after_waiting_observer,
|
||||
})
|
||||
@@ -270,6 +359,7 @@ impl EventLoop {
|
||||
&mut self,
|
||||
app: A,
|
||||
) -> Result<(), EventLoopError> {
|
||||
let _entered = debug_span!("run_app_on_demand").entered();
|
||||
self.app_state.clear_exit();
|
||||
self.app_state.set_event_handler(app, || {
|
||||
autoreleasepool(|_| {
|
||||
@@ -279,11 +369,9 @@ impl EventLoop {
|
||||
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();
|
||||
}
|
||||
debug_assert!(!self.app_state.is_running());
|
||||
self.app_state.set_is_running(true);
|
||||
self.app_state.dispatch_init_events();
|
||||
|
||||
// NOTE: Make sure to not run the application re-entrantly, as that'd be confusing.
|
||||
self.app.run();
|
||||
@@ -300,19 +388,10 @@ impl EventLoop {
|
||||
timeout: Option<Duration>,
|
||||
app: A,
|
||||
) -> PumpStatus {
|
||||
let _entered = debug_span!("pump_app_events").entered();
|
||||
self.app_state.set_event_handler(app, || {
|
||||
autoreleasepool(|_| {
|
||||
// As a special case, if the application hasn't been launched yet then we at least
|
||||
// run the loop until it has fully launched.
|
||||
if !self.app_state.is_launched() {
|
||||
debug_assert!(!self.app_state.is_running());
|
||||
|
||||
self.app_state.set_stop_on_launch();
|
||||
self.app.run();
|
||||
|
||||
// Note: we dispatch `NewEvents(Init)` + `Resumed` events after the application
|
||||
// has launched
|
||||
} else if !self.app_state.is_running() {
|
||||
if !self.app_state.is_running() {
|
||||
// Even though the application may have been launched, it's possible we aren't
|
||||
// running if the `EventLoop` was run before and has since
|
||||
// exited. This indicates that we just starting to re-run
|
||||
|
||||
@@ -50,15 +50,13 @@
|
||||
//! }
|
||||
//!
|
||||
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! let event_loop = EventLoop::new()?;
|
||||
//!
|
||||
//! // Register the delegate before Winit gets a chance to touch things.
|
||||
//! let mtm = MainThreadMarker::new().unwrap();
|
||||
//! let delegate = AppDelegate::new(mtm);
|
||||
//! // Important: Call `sharedApplication` after `EventLoop::new`,
|
||||
//! // doing it before is not yet supported.
|
||||
//! let app = NSApplication::sharedApplication(mtm);
|
||||
//! app.setDelegate(Some(ProtocolObject::from_ref(&*delegate)));
|
||||
//!
|
||||
//! let event_loop = EventLoop::new()?;
|
||||
//! // event_loop.run_app(&mut my_app);
|
||||
//! Ok(())
|
||||
//! }
|
||||
|
||||
@@ -1,37 +1,10 @@
|
||||
use objc2_core_graphics::CGError;
|
||||
use tracing::trace;
|
||||
use winit_core::error::OsError;
|
||||
|
||||
macro_rules! os_error {
|
||||
($error:expr) => {{ winit_core::error::OsError::new(line!(), file!(), $error) }};
|
||||
}
|
||||
|
||||
macro_rules! trace_scope {
|
||||
($s:literal) => {
|
||||
let _crate = $crate::util::TraceGuard::new(module_path!(), $s);
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct TraceGuard {
|
||||
module_path: &'static str,
|
||||
called_from_fn: &'static str,
|
||||
}
|
||||
|
||||
impl TraceGuard {
|
||||
#[inline]
|
||||
pub(crate) fn new(module_path: &'static str, called_from_fn: &'static str) -> Self {
|
||||
trace!(target = module_path, "Triggered `{}`", called_from_fn);
|
||||
Self { module_path, called_from_fn }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TraceGuard {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
trace!(target = self.module_path, "Completed `{}`", self.called_from_fn);
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn cgerr(err: CGError) -> Result<(), OsError> {
|
||||
if err == CGError::Success { Ok(()) } else { Err(os_error!(format!("CGError {err:?}"))) }
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
|
||||
use dpi::{LogicalPosition, LogicalSize};
|
||||
use objc2::rc::Retained;
|
||||
use objc2::runtime::{AnyObject, Sel};
|
||||
use objc2::{AnyThread, DefinedClass, MainThreadMarker, MainThreadOnly, define_class, msg_send};
|
||||
use objc2::{AnyThread, DefinedClass, MainThreadMarker, define_class, msg_send};
|
||||
use objc2_app_kit::{
|
||||
NSApplication, NSCursor, NSEvent, NSEventPhase, NSResponder, NSTextInputClient, NSTrackingArea,
|
||||
NSTrackingAreaOptions, NSView, NSWindow,
|
||||
@@ -17,7 +16,7 @@ use objc2_foundation::{
|
||||
NSArray, NSAttributedString, NSAttributedStringKey, NSCopying, NSMutableAttributedString,
|
||||
NSNotFound, NSObject, NSPoint, NSRange, NSRect, NSSize, NSString, NSUInteger,
|
||||
};
|
||||
use tracing::warn;
|
||||
use tracing::{debug_span, trace_span};
|
||||
use winit_core::event::{
|
||||
DeviceEvent, ElementState, Ime, KeyEvent, Modifiers, MouseButton, MouseScrollDelta,
|
||||
PointerKind, PointerSource, TouchPhase, WindowEvent,
|
||||
@@ -155,7 +154,7 @@ define_class!(
|
||||
// Not a normal method on `NSView`, it's triggered by `NSViewFrameDidChangeNotification`.
|
||||
#[unsafe(method(viewFrameDidChangeNotification:))]
|
||||
fn frame_did_change(&self, _notification: Option<&AnyObject>) {
|
||||
trace_scope!("NSViewFrameDidChangeNotification");
|
||||
let _entered = debug_span!("NSViewFrameDidChangeNotification").entered();
|
||||
|
||||
// Emit resize event here rather than from windowDidResize because:
|
||||
// 1. When a new window is created as a tab, the frame size may change without a window
|
||||
@@ -170,7 +169,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(drawRect:))]
|
||||
fn draw_rect(&self, _rect: NSRect) {
|
||||
trace_scope!("drawRect:");
|
||||
let _entered = debug_span!("drawRect:").entered();
|
||||
|
||||
self.ivars().app_state.handle_redraw(window_id(&self.window()));
|
||||
|
||||
@@ -179,7 +178,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(acceptsFirstResponder))]
|
||||
fn accepts_first_responder(&self) -> bool {
|
||||
trace_scope!("acceptsFirstResponder");
|
||||
let _entered = trace_span!("acceptsFirstResponder").entered();
|
||||
true
|
||||
}
|
||||
|
||||
@@ -193,13 +192,13 @@ define_class!(
|
||||
// extension for using `NSTouchBar`
|
||||
#[unsafe(method_id(touchBar))]
|
||||
fn touch_bar(&self) -> Option<Retained<NSObject>> {
|
||||
trace_scope!("touchBar");
|
||||
let _entered = debug_span!("touchBar").entered();
|
||||
None
|
||||
}
|
||||
|
||||
#[unsafe(method(resetCursorRects))]
|
||||
fn reset_cursor_rects(&self) {
|
||||
trace_scope!("resetCursorRects");
|
||||
let _entered = debug_span!("resetCursorRects").entered();
|
||||
let bounds = self.bounds();
|
||||
let cursor_state = self.ivars().cursor_state.borrow();
|
||||
// We correctly invoke `addCursorRect` only from inside `resetCursorRects`
|
||||
@@ -214,13 +213,13 @@ define_class!(
|
||||
unsafe impl NSTextInputClient for WinitView {
|
||||
#[unsafe(method(hasMarkedText))]
|
||||
fn has_marked_text(&self) -> bool {
|
||||
trace_scope!("hasMarkedText");
|
||||
let _entered = debug_span!("hasMarkedText").entered();
|
||||
self.ivars().marked_text.borrow().length() > 0
|
||||
}
|
||||
|
||||
#[unsafe(method(markedRange))]
|
||||
fn marked_range(&self) -> NSRange {
|
||||
trace_scope!("markedRange");
|
||||
let _entered = debug_span!("markedRange").entered();
|
||||
let length = self.ivars().marked_text.borrow().length();
|
||||
if length > 0 {
|
||||
NSRange::new(0, length)
|
||||
@@ -232,7 +231,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(selectedRange))]
|
||||
fn selected_range(&self) -> NSRange {
|
||||
trace_scope!("selectedRange");
|
||||
let _entered = debug_span!("selectedRange").entered();
|
||||
// Documented to return `{NSNotFound, 0}` if there is no selection.
|
||||
NSRange::new(NSNotFound as NSUInteger, 0)
|
||||
}
|
||||
@@ -245,7 +244,7 @@ define_class!(
|
||||
_replacement_range: NSRange,
|
||||
) {
|
||||
// TODO: Use _replacement_range, requires changing the event to report surrounding text.
|
||||
trace_scope!("setMarkedText:selectedRange:replacementRange:");
|
||||
let _entered = debug_span!("setMarkedText:selectedRange:replacementRange:").entered();
|
||||
|
||||
let (marked_text, string) = if let Some(string) =
|
||||
string.downcast_ref::<NSAttributedString>()
|
||||
@@ -299,7 +298,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(unmarkText))]
|
||||
fn unmark_text(&self) {
|
||||
trace_scope!("unmarkText");
|
||||
let _entered = debug_span!("unmarkText").entered();
|
||||
*self.ivars().marked_text.borrow_mut() = NSMutableAttributedString::new();
|
||||
|
||||
let input_context = self.inputContext().expect("input context");
|
||||
@@ -316,7 +315,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method_id(validAttributesForMarkedText))]
|
||||
fn valid_attributes_for_marked_text(&self) -> Retained<NSArray<NSAttributedStringKey>> {
|
||||
trace_scope!("validAttributesForMarkedText");
|
||||
let _entered = trace_span!("validAttributesForMarkedText").entered();
|
||||
NSArray::new()
|
||||
}
|
||||
|
||||
@@ -326,13 +325,14 @@ define_class!(
|
||||
_range: NSRange,
|
||||
_actual_range: *mut NSRange,
|
||||
) -> Option<Retained<NSAttributedString>> {
|
||||
trace_scope!("attributedSubstringForProposedRange:actualRange:");
|
||||
let _entered =
|
||||
trace_span!("attributedSubstringForProposedRange:actualRange:").entered();
|
||||
None
|
||||
}
|
||||
|
||||
#[unsafe(method(characterIndexForPoint:))]
|
||||
fn character_index_for_point(&self, _point: NSPoint) -> NSUInteger {
|
||||
trace_scope!("characterIndexForPoint:");
|
||||
let _entered = debug_span!("characterIndexForPoint:").entered();
|
||||
0
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ define_class!(
|
||||
_range: NSRange,
|
||||
_actual_range: *mut NSRange,
|
||||
) -> NSRect {
|
||||
trace_scope!("firstRectForCharacterRange:actualRange:");
|
||||
let _entered = debug_span!("firstRectForCharacterRange:actualRange:").entered();
|
||||
|
||||
// Guard when the view is no longer in a window during teardown.
|
||||
let Some(window) = (**self).window() else {
|
||||
@@ -358,7 +358,7 @@ define_class!(
|
||||
#[unsafe(method(insertText:replacementRange:))]
|
||||
fn insert_text(&self, string: &NSObject, _replacement_range: NSRange) {
|
||||
// TODO: Use _replacement_range, requires changing the event to report surrounding text.
|
||||
trace_scope!("insertText:replacementRange:");
|
||||
let _entered = debug_span!("insertText:replacementRange:").entered();
|
||||
|
||||
let string = if let Some(string) = string.downcast_ref::<NSAttributedString>() {
|
||||
string.string().to_string()
|
||||
@@ -383,7 +383,7 @@ define_class!(
|
||||
// "human readable" character happens, i.e. newlines, tabs, and Ctrl+C.
|
||||
#[unsafe(method(doCommandBySelector:))]
|
||||
fn do_command_by_selector(&self, command: Sel) {
|
||||
trace_scope!("doCommandBySelector:");
|
||||
let _entered = debug_span!("doCommandBySelector:").entered();
|
||||
|
||||
// We shouldn't forward any character from just committed text, since we'll end up
|
||||
// sending it twice with some IMEs like Korean one. We'll also always send
|
||||
@@ -422,7 +422,7 @@ define_class!(
|
||||
impl WinitView {
|
||||
#[unsafe(method(keyDown:))]
|
||||
fn key_down(&self, event: &NSEvent) {
|
||||
trace_scope!("keyDown:");
|
||||
let _entered = debug_span!("keyDown:").entered();
|
||||
{
|
||||
let mut prev_input_source = self.ivars().input_source.borrow_mut();
|
||||
let current_input_source = self.current_input_source();
|
||||
@@ -481,7 +481,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(keyUp:))]
|
||||
fn key_up(&self, event: &NSEvent) {
|
||||
trace_scope!("keyUp:");
|
||||
let _entered = debug_span!("keyUp:").entered();
|
||||
|
||||
let event = replace_event(event, self.option_as_alt());
|
||||
self.update_modifiers(&event, false);
|
||||
@@ -498,14 +498,14 @@ define_class!(
|
||||
|
||||
#[unsafe(method(flagsChanged:))]
|
||||
fn flags_changed(&self, event: &NSEvent) {
|
||||
trace_scope!("flagsChanged:");
|
||||
let _entered = debug_span!("flagsChanged:").entered();
|
||||
|
||||
self.update_modifiers(event, true);
|
||||
}
|
||||
|
||||
#[unsafe(method(insertTab:))]
|
||||
fn insert_tab(&self, _sender: Option<&AnyObject>) {
|
||||
trace_scope!("insertTab:");
|
||||
let _entered = debug_span!("insertTab:").entered();
|
||||
let window = self.window();
|
||||
if let Some(first_responder) = window.firstResponder() {
|
||||
if *first_responder == ***self {
|
||||
@@ -516,7 +516,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(insertBackTab:))]
|
||||
fn insert_back_tab(&self, _sender: Option<&AnyObject>) {
|
||||
trace_scope!("insertBackTab:");
|
||||
let _entered = debug_span!("insertBackTab:").entered();
|
||||
let window = self.window();
|
||||
if let Some(first_responder) = window.firstResponder() {
|
||||
if *first_responder == ***self {
|
||||
@@ -530,7 +530,7 @@ define_class!(
|
||||
#[unsafe(method(cancelOperation:))]
|
||||
fn cancel_operation(&self, _sender: Option<&AnyObject>) {
|
||||
let mtm = MainThreadMarker::from(self);
|
||||
trace_scope!("cancelOperation:");
|
||||
let _entered = debug_span!("cancelOperation:").entered();
|
||||
|
||||
let event = NSApplication::sharedApplication(mtm)
|
||||
.currentEvent()
|
||||
@@ -559,71 +559,73 @@ define_class!(
|
||||
|
||||
#[unsafe(method(mouseDown:))]
|
||||
fn mouse_down(&self, event: &NSEvent) {
|
||||
trace_scope!("mouseDown:");
|
||||
let _entered = debug_span!("mouseDown:").entered();
|
||||
self.mouse_motion(event);
|
||||
self.mouse_click(event, ElementState::Pressed);
|
||||
}
|
||||
|
||||
#[unsafe(method(mouseUp:))]
|
||||
fn mouse_up(&self, event: &NSEvent) {
|
||||
trace_scope!("mouseUp:");
|
||||
let _entered = debug_span!("mouseUp:").entered();
|
||||
self.mouse_motion(event);
|
||||
self.mouse_click(event, ElementState::Released);
|
||||
}
|
||||
|
||||
#[unsafe(method(rightMouseDown:))]
|
||||
fn right_mouse_down(&self, event: &NSEvent) {
|
||||
trace_scope!("rightMouseDown:");
|
||||
let _entered = debug_span!("rightMouseDown:").entered();
|
||||
self.mouse_motion(event);
|
||||
self.mouse_click(event, ElementState::Pressed);
|
||||
}
|
||||
|
||||
#[unsafe(method(rightMouseUp:))]
|
||||
fn right_mouse_up(&self, event: &NSEvent) {
|
||||
trace_scope!("rightMouseUp:");
|
||||
let _entered = debug_span!("rightMouseUp:").entered();
|
||||
self.mouse_motion(event);
|
||||
self.mouse_click(event, ElementState::Released);
|
||||
}
|
||||
|
||||
#[unsafe(method(otherMouseDown:))]
|
||||
fn other_mouse_down(&self, event: &NSEvent) {
|
||||
trace_scope!("otherMouseDown:");
|
||||
let _entered = debug_span!("otherMouseDown:").entered();
|
||||
self.mouse_motion(event);
|
||||
self.mouse_click(event, ElementState::Pressed);
|
||||
}
|
||||
|
||||
#[unsafe(method(otherMouseUp:))]
|
||||
fn other_mouse_up(&self, event: &NSEvent) {
|
||||
trace_scope!("otherMouseUp:");
|
||||
let _entered = debug_span!("otherMouseUp:").entered();
|
||||
self.mouse_motion(event);
|
||||
self.mouse_click(event, ElementState::Released);
|
||||
}
|
||||
|
||||
// No tracing on these because that would be overly verbose
|
||||
|
||||
#[unsafe(method(mouseMoved:))]
|
||||
fn mouse_moved(&self, event: &NSEvent) {
|
||||
let _entered = debug_span!("mouseMoved:").entered();
|
||||
self.mouse_motion(event);
|
||||
}
|
||||
|
||||
#[unsafe(method(mouseDragged:))]
|
||||
fn mouse_dragged(&self, event: &NSEvent) {
|
||||
let _entered = debug_span!("mouseDragged:").entered();
|
||||
self.mouse_motion(event);
|
||||
}
|
||||
|
||||
#[unsafe(method(rightMouseDragged:))]
|
||||
fn right_mouse_dragged(&self, event: &NSEvent) {
|
||||
let _entered = debug_span!("rightMouseDragged:").entered();
|
||||
self.mouse_motion(event);
|
||||
}
|
||||
|
||||
#[unsafe(method(otherMouseDragged:))]
|
||||
fn other_mouse_dragged(&self, event: &NSEvent) {
|
||||
let _entered = debug_span!("otherMouseDragged:").entered();
|
||||
self.mouse_motion(event);
|
||||
}
|
||||
|
||||
#[unsafe(method(mouseEntered:))]
|
||||
fn mouse_entered(&self, event: &NSEvent) {
|
||||
trace_scope!("mouseEntered:");
|
||||
let _entered = debug_span!("mouseEntered:").entered();
|
||||
|
||||
let position = self.mouse_view_point(event).to_physical(self.scale_factor());
|
||||
|
||||
@@ -637,7 +639,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(mouseExited:))]
|
||||
fn mouse_exited(&self, event: &NSEvent) {
|
||||
trace_scope!("mouseExited:");
|
||||
let _entered = debug_span!("mouseExited:").entered();
|
||||
|
||||
let position = self.mouse_view_point(event).to_physical(self.scale_factor());
|
||||
|
||||
@@ -651,7 +653,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(scrollWheel:))]
|
||||
fn scroll_wheel(&self, event: &NSEvent) {
|
||||
trace_scope!("scrollWheel:");
|
||||
let _entered = debug_span!("scrollWheel:").entered();
|
||||
|
||||
self.mouse_motion(event);
|
||||
|
||||
@@ -682,16 +684,15 @@ define_class!(
|
||||
|
||||
self.update_modifiers(event, false);
|
||||
|
||||
let time = self.ivars().app_state.event_time(event);
|
||||
self.ivars().app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.device_event(event_loop, None, time, DeviceEvent::MouseWheel { delta })
|
||||
app.device_event(event_loop, None, DeviceEvent::MouseWheel { delta })
|
||||
});
|
||||
self.queue_event(WindowEvent::MouseWheel { device_id: None, delta, phase });
|
||||
}
|
||||
|
||||
#[unsafe(method(magnifyWithEvent:))]
|
||||
fn magnify_with_event(&self, event: &NSEvent) {
|
||||
trace_scope!("magnifyWithEvent:");
|
||||
let _entered = debug_span!("magnifyWithEvent:").entered();
|
||||
|
||||
self.mouse_motion(event);
|
||||
|
||||
@@ -713,7 +714,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(smartMagnifyWithEvent:))]
|
||||
fn smart_magnify_with_event(&self, event: &NSEvent) {
|
||||
trace_scope!("smartMagnifyWithEvent:");
|
||||
let _entered = debug_span!("smartMagnifyWithEvent:").entered();
|
||||
|
||||
self.mouse_motion(event);
|
||||
|
||||
@@ -722,7 +723,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(rotateWithEvent:))]
|
||||
fn rotate_with_event(&self, event: &NSEvent) {
|
||||
trace_scope!("rotateWithEvent:");
|
||||
let _entered = debug_span!("rotateWithEvent:").entered();
|
||||
|
||||
self.mouse_motion(event);
|
||||
|
||||
@@ -744,7 +745,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(pressureChangeWithEvent:))]
|
||||
fn pressure_change_with_event(&self, event: &NSEvent) {
|
||||
trace_scope!("pressureChangeWithEvent:");
|
||||
let _entered = debug_span!("pressureChangeWithEvent:").entered();
|
||||
|
||||
self.queue_event(WindowEvent::TouchpadPressure {
|
||||
device_id: None,
|
||||
@@ -758,13 +759,13 @@ define_class!(
|
||||
// https://github.com/chromium/chromium/blob/a86a8a6bcfa438fa3ac2eba6f02b3ad1f8e0756f/ui/views/cocoa/bridged_content_view.mm#L816
|
||||
#[unsafe(method(_wantsKeyDownForEvent:))]
|
||||
fn wants_key_down_for_event(&self, _event: &NSEvent) -> bool {
|
||||
trace_scope!("_wantsKeyDownForEvent:");
|
||||
let _entered = debug_span!("_wantsKeyDownForEvent:").entered();
|
||||
true
|
||||
}
|
||||
|
||||
#[unsafe(method(acceptsFirstMouse:))]
|
||||
fn accepts_first_mouse(&self, _event: &NSEvent) -> bool {
|
||||
trace_scope!("acceptsFirstMouse:");
|
||||
let _entered = debug_span!("acceptsFirstMouse:").entered();
|
||||
self.ivars().accepts_first_mouse
|
||||
}
|
||||
}
|
||||
@@ -847,16 +848,9 @@ impl WinitView {
|
||||
}
|
||||
|
||||
fn queue_event(&self, event: WindowEvent) {
|
||||
let app = NSApplication::sharedApplication(self.mtm());
|
||||
let window_id = window_id(&self.window());
|
||||
let time = if let Some(nsevent) = app.currentEvent() {
|
||||
self.ivars().app_state.event_time(&nsevent)
|
||||
} else {
|
||||
warn!("queued event with wrong timestamp, no active NSEvent found");
|
||||
Instant::now()
|
||||
};
|
||||
self.ivars().app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.window_event(event_loop, window_id, time, event);
|
||||
app.window_event(event_loop, window_id, event);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use objc2::rc::{Retained, autoreleasepool};
|
||||
use objc2::{MainThreadMarker, Message, define_class};
|
||||
use objc2_app_kit::{NSPanel, NSResponder, NSWindow};
|
||||
use objc2_foundation::NSObject;
|
||||
use tracing::trace_span;
|
||||
use winit_core::cursor::Cursor;
|
||||
use winit_core::error::RequestError;
|
||||
use winit_core::icon::Icon;
|
||||
@@ -350,13 +351,13 @@ define_class!(
|
||||
impl WinitWindow {
|
||||
#[unsafe(method(canBecomeMainWindow))]
|
||||
fn can_become_main_window(&self) -> bool {
|
||||
trace_scope!("canBecomeMainWindow");
|
||||
let _entered = trace_span!("canBecomeMainWindow").entered();
|
||||
true
|
||||
}
|
||||
|
||||
#[unsafe(method(canBecomeKeyWindow))]
|
||||
fn can_become_key_window(&self) -> bool {
|
||||
trace_scope!("canBecomeKeyWindow");
|
||||
let _entered = trace_span!("canBecomeKeyWindow").entered();
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -374,7 +375,7 @@ define_class!(
|
||||
// it doesn't if window doesn't have NSWindowStyleMask::Titled
|
||||
#[unsafe(method(canBecomeKeyWindow))]
|
||||
fn can_become_key_window(&self) -> bool {
|
||||
trace_scope!("canBecomeKeyWindow");
|
||||
let _entered = trace_span!("canBecomeKeyWindow").entered();
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ use std::ffi::c_void;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
use dpi::{
|
||||
LogicalInsets, LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize,
|
||||
@@ -42,7 +41,7 @@ use objc2_foundation::{
|
||||
NSObjectNSDelayedPerforming, NSObjectNSKeyValueObserverRegistration, NSObjectProtocol, NSPoint,
|
||||
NSRect, NSSize, NSString, ns_string,
|
||||
};
|
||||
use tracing::{trace, warn};
|
||||
use tracing::{debug_span, trace, warn};
|
||||
use winit_common::core_foundation::MainRunLoop;
|
||||
use winit_core::cursor::Cursor;
|
||||
use winit_core::error::{NotSupportedError, RequestError};
|
||||
@@ -122,14 +121,14 @@ define_class!(
|
||||
unsafe impl NSWindowDelegate for WindowDelegate {
|
||||
#[unsafe(method(windowShouldClose:))]
|
||||
fn window_should_close(&self, _: Option<&AnyObject>) -> bool {
|
||||
trace_scope!("windowShouldClose:");
|
||||
let _entered = debug_span!("windowShouldClose:").entered();
|
||||
self.queue_event(WindowEvent::CloseRequested);
|
||||
false
|
||||
}
|
||||
|
||||
#[unsafe(method(windowWillClose:))]
|
||||
fn window_will_close(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowWillClose:");
|
||||
let _entered = debug_span!("windowWillClose:").entered();
|
||||
// `setDelegate:` retains the previous value and then autoreleases it
|
||||
autoreleasepool(|_| {
|
||||
// Since El Capitan, we need to be careful that delegate methods can't
|
||||
@@ -141,14 +140,14 @@ define_class!(
|
||||
|
||||
#[unsafe(method(windowDidResize:))]
|
||||
fn window_did_resize(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidResize:");
|
||||
let _entered = debug_span!("windowDidResize:").entered();
|
||||
// NOTE: WindowEvent::SurfaceResized is reported using NSViewFrameDidChangeNotification.
|
||||
self.emit_move_event();
|
||||
}
|
||||
|
||||
#[unsafe(method(windowWillStartLiveResize:))]
|
||||
fn window_will_start_live_resize(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowWillStartLiveResize:");
|
||||
let _entered = debug_span!("windowWillStartLiveResize:").entered();
|
||||
|
||||
let increments = self.ivars().surface_resize_increments.get();
|
||||
self.set_resize_increments_inner(increments);
|
||||
@@ -156,20 +155,20 @@ define_class!(
|
||||
|
||||
#[unsafe(method(windowDidEndLiveResize:))]
|
||||
fn window_did_end_live_resize(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidEndLiveResize:");
|
||||
let _entered = debug_span!("windowDidEndLiveResize:").entered();
|
||||
self.set_resize_increments_inner(NSSize::new(1., 1.));
|
||||
}
|
||||
|
||||
// This won't be triggered if the move was part of a resize.
|
||||
#[unsafe(method(windowDidMove:))]
|
||||
fn window_did_move(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidMove:");
|
||||
let _entered = debug_span!("windowDidMove:").entered();
|
||||
self.emit_move_event();
|
||||
}
|
||||
|
||||
#[unsafe(method(windowDidChangeBackingProperties:))]
|
||||
fn window_did_change_backing_properties(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidChangeBackingProperties:");
|
||||
let _entered = debug_span!("windowDidChangeBackingProperties:").entered();
|
||||
let scale_factor = self.scale_factor();
|
||||
if scale_factor == self.ivars().previous_scale_factor.get() {
|
||||
return;
|
||||
@@ -185,7 +184,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(windowDidBecomeKey:))]
|
||||
fn window_did_become_key(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidBecomeKey:");
|
||||
let _entered = debug_span!("windowDidBecomeKey:").entered();
|
||||
// TODO: center the cursor if the window had mouse grab when it
|
||||
// lost focus
|
||||
self.queue_event(WindowEvent::Focused(true));
|
||||
@@ -193,7 +192,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(windowDidResignKey:))]
|
||||
fn window_did_resign_key(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidResignKey:");
|
||||
let _entered = debug_span!("windowDidResignKey:").entered();
|
||||
// It happens rather often, e.g. when the user is Cmd+Tabbing, that the
|
||||
// NSWindowDelegate will receive a didResignKey event despite no event
|
||||
// being received when the modifiers are released. This is because
|
||||
@@ -209,7 +208,7 @@ define_class!(
|
||||
/// Invoked when before enter fullscreen
|
||||
#[unsafe(method(windowWillEnterFullScreen:))]
|
||||
fn window_will_enter_fullscreen(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowWillEnterFullScreen:");
|
||||
let _entered = debug_span!("windowWillEnterFullScreen:").entered();
|
||||
|
||||
self.ivars().maximized.set(self.is_zoomed());
|
||||
let mut fullscreen = self.ivars().fullscreen.borrow_mut();
|
||||
@@ -237,7 +236,7 @@ define_class!(
|
||||
/// Invoked when before exit fullscreen
|
||||
#[unsafe(method(windowWillExitFullScreen:))]
|
||||
fn window_will_exit_fullscreen(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowWillExitFullScreen:");
|
||||
let _entered = debug_span!("windowWillExitFullScreen:").entered();
|
||||
|
||||
self.ivars().in_fullscreen_transition.set(true);
|
||||
}
|
||||
@@ -248,7 +247,7 @@ define_class!(
|
||||
_: Option<&AnyObject>,
|
||||
proposed_options: NSApplicationPresentationOptions,
|
||||
) -> NSApplicationPresentationOptions {
|
||||
trace_scope!("window:willUseFullScreenPresentationOptions:");
|
||||
let _entered = debug_span!("window:willUseFullScreenPresentationOptions:").entered();
|
||||
// Generally, games will want to disable the menu bar and the dock. Ideally,
|
||||
// this would be configurable by the user. Unfortunately because of our
|
||||
// `CGShieldingWindowLevel() + 1` hack (see `set_fullscreen`), our window is
|
||||
@@ -271,7 +270,7 @@ define_class!(
|
||||
/// Invoked when entered fullscreen
|
||||
#[unsafe(method(windowDidEnterFullScreen:))]
|
||||
fn window_did_enter_fullscreen(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidEnterFullScreen:");
|
||||
let _entered = debug_span!("windowDidEnterFullScreen:").entered();
|
||||
self.ivars().initial_fullscreen.set(false);
|
||||
self.ivars().in_fullscreen_transition.set(false);
|
||||
if let Some(target_fullscreen) = self.ivars().target_fullscreen.take() {
|
||||
@@ -282,7 +281,7 @@ define_class!(
|
||||
/// Invoked when exited fullscreen
|
||||
#[unsafe(method(windowDidExitFullScreen:))]
|
||||
fn window_did_exit_fullscreen(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidExitFullScreen:");
|
||||
let _entered = debug_span!("windowDidExitFullScreen:").entered();
|
||||
|
||||
self.restore_state_from_fullscreen();
|
||||
self.ivars().in_fullscreen_transition.set(false);
|
||||
@@ -309,7 +308,7 @@ define_class!(
|
||||
/// work you may have done to prepare to enter full-screen mode.
|
||||
#[unsafe(method(windowDidFailToEnterFullScreen:))]
|
||||
fn window_did_fail_to_enter_fullscreen(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidFailToEnterFullScreen:");
|
||||
let _entered = debug_span!("windowDidFailToEnterFullScreen:").entered();
|
||||
self.ivars().in_fullscreen_transition.set(false);
|
||||
self.ivars().target_fullscreen.replace(None);
|
||||
if self.ivars().initial_fullscreen.get() {
|
||||
@@ -328,7 +327,7 @@ define_class!(
|
||||
// Invoked when the occlusion state of the window changes
|
||||
#[unsafe(method(windowDidChangeOcclusionState:))]
|
||||
fn window_did_change_occlusion_state(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidChangeOcclusionState:");
|
||||
let _entered = debug_span!("windowDidChangeOcclusionState:").entered();
|
||||
let visible = self.window().occlusionState().contains(NSWindowOcclusionState::Visible);
|
||||
self.queue_event(WindowEvent::Occluded(!visible));
|
||||
|
||||
@@ -349,7 +348,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(windowDidChangeScreen:))]
|
||||
fn window_did_change_screen(&self, _: Option<&AnyObject>) {
|
||||
trace_scope!("windowDidChangeScreen:");
|
||||
let _entered = debug_span!("windowDidChangeScreen:").entered();
|
||||
let is_simple_fullscreen = self.ivars().is_simple_fullscreen.get();
|
||||
if is_simple_fullscreen {
|
||||
if let Some(screen) = self.window().screen() {
|
||||
@@ -363,7 +362,7 @@ define_class!(
|
||||
/// Invoked when the dragged image enters destination bounds or frame
|
||||
#[unsafe(method(draggingEntered:))]
|
||||
fn dragging_entered(&self, sender: &ProtocolObject<dyn NSDraggingInfo>) -> bool {
|
||||
trace_scope!("draggingEntered:");
|
||||
let _entered = debug_span!("draggingEntered:").entered();
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -394,7 +393,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(wantsPeriodicDraggingUpdates))]
|
||||
fn wants_periodic_dragging_updates(&self) -> bool {
|
||||
trace_scope!("wantsPeriodicDraggingUpdates:");
|
||||
let _entered = debug_span!("wantsPeriodicDraggingUpdates:").entered();
|
||||
true
|
||||
}
|
||||
|
||||
@@ -402,7 +401,7 @@ define_class!(
|
||||
/// modification of the dragging operation or mouse-pointer position.
|
||||
#[unsafe(method(draggingUpdated:))]
|
||||
fn dragging_updated(&self, sender: &ProtocolObject<dyn NSDraggingInfo>) -> bool {
|
||||
trace_scope!("draggingUpdated:");
|
||||
let _entered = debug_span!("draggingUpdated:").entered();
|
||||
|
||||
let dl = sender.draggingLocation();
|
||||
let dl = self.view().convertPoint_fromView(dl, None);
|
||||
@@ -417,14 +416,14 @@ define_class!(
|
||||
/// Invoked when the image is released
|
||||
#[unsafe(method(prepareForDragOperation:))]
|
||||
fn prepare_for_drag_operation(&self, _sender: &NSObject) -> bool {
|
||||
trace_scope!("prepareForDragOperation:");
|
||||
let _entered = debug_span!("prepareForDragOperation:").entered();
|
||||
true
|
||||
}
|
||||
|
||||
/// Invoked after the released image has been removed from the screen
|
||||
#[unsafe(method(performDragOperation:))]
|
||||
fn perform_drag_operation(&self, sender: &ProtocolObject<dyn NSDraggingInfo>) -> bool {
|
||||
trace_scope!("performDragOperation:");
|
||||
let _entered = debug_span!("performDragOperation:").entered();
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -456,13 +455,13 @@ define_class!(
|
||||
/// Invoked when the dragging operation is complete
|
||||
#[unsafe(method(concludeDragOperation:))]
|
||||
fn conclude_drag_operation(&self, _sender: Option<&NSObject>) {
|
||||
trace_scope!("concludeDragOperation:");
|
||||
let _entered = debug_span!("concludeDragOperation:").entered();
|
||||
}
|
||||
|
||||
/// Invoked when the dragging operation is cancelled
|
||||
#[unsafe(method(draggingExited:))]
|
||||
fn dragging_exited(&self, sender: Option<&ProtocolObject<dyn NSDraggingInfo>>) {
|
||||
trace_scope!("draggingExited:");
|
||||
let _entered = debug_span!("draggingExited:").entered();
|
||||
|
||||
let position = sender.map(|sender| {
|
||||
let dl = sender.draggingLocation();
|
||||
@@ -484,7 +483,7 @@ define_class!(
|
||||
change: Option<&NSDictionary<NSKeyValueChangeKey, AnyObject>>,
|
||||
_context: *mut c_void,
|
||||
) {
|
||||
trace_scope!("observeValueForKeyPath:ofObject:change:context:");
|
||||
let _entered = debug_span!("observeValueForKeyPath:ofObject:change:context:").entered();
|
||||
// NOTE: We don't _really_ need to check the key path, as there should only be one, but
|
||||
// in the future we might want to observe other key paths.
|
||||
if key_path == Some(ns_string!("effectiveAppearance")) {
|
||||
@@ -904,16 +903,9 @@ impl WindowDelegate {
|
||||
}
|
||||
|
||||
pub(crate) fn queue_event(&self, event: WindowEvent) {
|
||||
let app = NSApplication::sharedApplication(self.mtm());
|
||||
let window_id = window_id(self.window());
|
||||
let time = if let Some(nsevent) = app.currentEvent() {
|
||||
self.ivars().app_state.event_time(&nsevent)
|
||||
} else {
|
||||
warn!("queued event with wrong timestamp, no active NSEvent found");
|
||||
Instant::now()
|
||||
};
|
||||
self.ivars().app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||
app.window_event(event_loop, window_id, time, event);
|
||||
app.window_event(event_loop, window_id, event);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::cell::Cell;
|
||||
|
||||
use objc2::MainThreadMarker;
|
||||
use objc2_core_foundation::{CFRetained, CFRunLoop, CFRunLoopMode, kCFRunLoopDefaultMode};
|
||||
use tracing::error;
|
||||
use tracing::{Span, error};
|
||||
|
||||
use super::MainRunLoopObserver;
|
||||
|
||||
@@ -49,7 +49,8 @@ impl MainRunLoop {
|
||||
/// This queuing could be implemented in the following several ways with subtle differences in
|
||||
/// timing. This list is sorted in rough order in which they are run:
|
||||
///
|
||||
/// 1. Using `CFRunLoopPerformBlock` or `-[NSRunLoop performBlock:]`.
|
||||
/// 1. Using `CFRunLoopPerformBlock` or `-[NSRunLoop performBlock:]` to queue a closure to run
|
||||
/// the next time runloop sources are processed.
|
||||
///
|
||||
/// 2. Using `-[NSObject performSelectorOnMainThread:withObject:waitUntilDone:]` or wrapping the
|
||||
/// event in `NSEvent` and posting that to `-[NSApplication postEvent:atStart:]` (both
|
||||
@@ -73,9 +74,17 @@ impl MainRunLoop {
|
||||
/// put the event at the very front of the queue, to be handled as soon as possible after
|
||||
/// handling whatever event it's currently handling.
|
||||
pub fn queue_closure(&self, closure: impl FnOnce() + 'static) {
|
||||
// We use this to run a closure asynchronously at a later point, so it also makes sense to
|
||||
// re-enter the current span when running the queued closure.
|
||||
let span = Span::current();
|
||||
|
||||
// Convert `FnOnce()` to `Block<dyn Fn()>`.
|
||||
let closure = Cell::new(Some(closure));
|
||||
let block = block2::RcBlock::new(move || {
|
||||
// Running this block happens inside a `CFRunLoopSource`, but the spans that we emit for
|
||||
// that are (intentionally) overwritten by entering the span from before.
|
||||
let _enter = span.enter();
|
||||
|
||||
debug_assert!(MainThreadMarker::new().is_some());
|
||||
if let Some(closure) = closure.take() {
|
||||
closure()
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
mod event_loop_proxy;
|
||||
mod main_run_loop;
|
||||
mod main_run_loop_observer;
|
||||
mod tracing_observers;
|
||||
|
||||
pub use self::event_loop_proxy::*;
|
||||
pub use self::main_run_loop::*;
|
||||
pub use self::main_run_loop_observer::*;
|
||||
pub use self::tracing_observers::*;
|
||||
|
||||
146
winit-common/src/core_foundation/tracing_observers.rs
Normal file
146
winit-common/src/core_foundation/tracing_observers.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use objc2::MainThreadMarker;
|
||||
use objc2_core_foundation::{CFIndex, CFRunLoop, CFRunLoopActivity, kCFRunLoopDefaultMode};
|
||||
use tracing::span::EnteredSpan;
|
||||
use tracing::{Level, error, field, span_enabled, trace_span};
|
||||
|
||||
use crate::core_foundation::MainRunLoopObserver;
|
||||
|
||||
/// Create two run loop observers that add TRACE-level [spans][tracing::span].
|
||||
///
|
||||
/// This is useful when debugging run loops, it makes it easier to see in which run loop activity an
|
||||
/// event is triggered inside (if any).
|
||||
///
|
||||
/// When debugging these interactions, it can also be useful to configure your tracing subscriber
|
||||
/// with `.with_span_events(tracing_subscriber::fmt::format::FmtSpan::ACTIVE)` to emit events upon
|
||||
/// entering and exiting these stages.
|
||||
pub fn tracing_observers(
|
||||
mtm: MainThreadMarker,
|
||||
) -> Option<(MainRunLoopObserver, MainRunLoopObserver)> {
|
||||
// Observers are a bit costly, so don't create them if the tracing-level for this module is
|
||||
// configured to disable them.
|
||||
if !span_enabled!(Level::TRACE) {
|
||||
return None;
|
||||
}
|
||||
|
||||
/// The state that we think the runloop is currently in.
|
||||
///
|
||||
/// The order of activities we observe if waiting twice looks something like:
|
||||
/// - CFRunLoopActivity::Entry
|
||||
/// - CFRunLoopActivity::BeforeTimers
|
||||
/// - CFRunLoopActivity::BeforeSources
|
||||
/// - CFRunLoopActivity::BeforeWaiting
|
||||
/// - CFRunLoopActivity::AfterWaiting
|
||||
/// - CFRunLoopActivity::BeforeTimers
|
||||
/// - CFRunLoopActivity::BeforeSources
|
||||
/// - CFRunLoopActivity::BeforeWaiting
|
||||
/// - CFRunLoopActivity::AfterWaiting
|
||||
/// - CFRunLoopActivity::Exit
|
||||
///
|
||||
/// And if not waiting, it looks something like:
|
||||
/// - CFRunLoopActivity::Entry
|
||||
/// - CFRunLoopActivity::BeforeTimers
|
||||
/// - CFRunLoopActivity::BeforeSources
|
||||
/// - CFRunLoopActivity::Exit
|
||||
#[derive(Default)]
|
||||
#[allow(unused)] // EnteredSpans are kept around
|
||||
enum RunLoopState {
|
||||
/// Currently processing `Entry`/`Exit` observers.
|
||||
#[default]
|
||||
Entered,
|
||||
/// Currently processing timers or `BeforeTimers` observers.
|
||||
Timers(EnteredSpan),
|
||||
/// Currently processing sources or `BeforeSources` observers.
|
||||
Sources(EnteredSpan),
|
||||
/// Currently waiting or processing `BeforeWaiting`/`AfterWaiting` observers.
|
||||
Waiting(EnteredSpan),
|
||||
}
|
||||
|
||||
// A list of currently entered (outer) spans and their state.
|
||||
//
|
||||
// This is a list because runloops can be run recursively.
|
||||
let spans: Rc<RefCell<Vec<(EnteredSpan, RunLoopState)>>> = Rc::new(RefCell::new(Vec::new()));
|
||||
let spans_clone = Rc::clone(&spans);
|
||||
|
||||
// An observer at the start of run loop activities.
|
||||
let activities = CFRunLoopActivity::Entry
|
||||
| CFRunLoopActivity::BeforeTimers
|
||||
| CFRunLoopActivity::BeforeSources
|
||||
| CFRunLoopActivity::BeforeWaiting;
|
||||
let start = MainRunLoopObserver::new(mtm, activities, true, CFIndex::MIN, move |activity| {
|
||||
match activity {
|
||||
// Add an outer span for each runloop iteration.
|
||||
CFRunLoopActivity::Entry => {
|
||||
let span = trace_span!("inside runloop", mode = field::Empty);
|
||||
|
||||
// Get the mode dynamically, the observer may added to multiple different modes.
|
||||
let mode = CFRunLoop::current().unwrap().current_mode().unwrap();
|
||||
// Mode isn't interesting if it's the default mode.
|
||||
if &*mode != unsafe { kCFRunLoopDefaultMode }.unwrap() {
|
||||
span.record("mode", field::display(mode));
|
||||
}
|
||||
|
||||
let entered = span.entered();
|
||||
spans.borrow_mut().push((entered, RunLoopState::Entered));
|
||||
},
|
||||
|
||||
// Add inner spans that help inspecting the state the runloop is in.
|
||||
CFRunLoopActivity::BeforeTimers => {
|
||||
if let Some((_, state)) = spans.borrow_mut().last_mut() {
|
||||
*state = RunLoopState::Entered; // Drop any previous spans.
|
||||
*state = RunLoopState::Timers(trace_span!("processing timers").entered());
|
||||
} else {
|
||||
error!("unbalanced observer invocations");
|
||||
}
|
||||
},
|
||||
CFRunLoopActivity::BeforeSources => {
|
||||
if let Some((_, state)) = spans.borrow_mut().last_mut() {
|
||||
*state = RunLoopState::Entered; // Drop any previous spans.
|
||||
*state = RunLoopState::Sources(trace_span!("processing sources").entered());
|
||||
} else {
|
||||
error!("unbalanced observer invocations");
|
||||
}
|
||||
},
|
||||
CFRunLoopActivity::BeforeWaiting => {
|
||||
if let Some((_, state)) = spans.borrow_mut().last_mut() {
|
||||
*state = RunLoopState::Entered; // Drop any previous spans.
|
||||
*state = RunLoopState::Waiting(trace_span!("waiting").entered());
|
||||
} else {
|
||||
error!("unbalanced observer invocations");
|
||||
}
|
||||
},
|
||||
|
||||
activity => unreachable!("unexpected activity: {activity:?}"),
|
||||
}
|
||||
});
|
||||
|
||||
// An observer at the end of run loop activities.
|
||||
let activities = CFRunLoopActivity::AfterWaiting | CFRunLoopActivity::Exit;
|
||||
let end = MainRunLoopObserver::new(mtm, activities, true, CFIndex::MAX, move |activity| {
|
||||
match activity {
|
||||
CFRunLoopActivity::AfterWaiting => {
|
||||
if let Some((_, state)) = spans_clone.borrow_mut().last_mut() {
|
||||
// Transition from the waiting state to the initial state.
|
||||
*state = RunLoopState::Entered;
|
||||
} else {
|
||||
error!("unbalanced observer invocations");
|
||||
}
|
||||
},
|
||||
|
||||
CFRunLoopActivity::Exit => {
|
||||
if let Some((span, state)) = spans_clone.borrow_mut().pop() {
|
||||
drop(state); // Explicitly exit and drop inner span.
|
||||
drop(span); // Explicitly exit and drop outer span.
|
||||
} else {
|
||||
error!("unbalanced observer invocations");
|
||||
}
|
||||
},
|
||||
|
||||
activity => unreachable!("unexpected activity: {activity:?}"),
|
||||
}
|
||||
});
|
||||
|
||||
Some((start, end))
|
||||
}
|
||||
@@ -79,6 +79,10 @@ impl EventHandler {
|
||||
// Allowed, happens if the handler was cleared manually
|
||||
// elsewhere (such as in `applicationWillTerminate:`).
|
||||
},
|
||||
// We use `eprintln!` here over `tracing::error!`, since we're going to abort
|
||||
// immediately after this, and it'd be annoying for the user if they didn't get
|
||||
// any feedback on that if they don't have a tracing subscriber.
|
||||
#[allow(clippy::disallowed_macros)]
|
||||
Err(_) => {
|
||||
// Note: This is not expected to ever happen, this
|
||||
// module generally controls the `RefCell`, and
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
//! End user application handling.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use std::time::Instant;
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
use web_time::Instant;
|
||||
|
||||
use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent};
|
||||
use crate::event_loop::ActiveEventLoop;
|
||||
@@ -197,14 +192,10 @@ pub trait ApplicationHandler {
|
||||
}
|
||||
|
||||
/// Emitted when the OS sends an event to a winit window.
|
||||
///
|
||||
/// Contains the ID of the window, the event, and the time the event was received. Note that
|
||||
/// since events are queued, the time will differ from [`Instant::now()`].
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
window_id: WindowId,
|
||||
timestamp: Instant,
|
||||
event: WindowEvent,
|
||||
);
|
||||
|
||||
@@ -215,10 +206,9 @@ pub trait ApplicationHandler {
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
device_id: Option<DeviceId>,
|
||||
timestamp: Instant,
|
||||
event: DeviceEvent,
|
||||
) {
|
||||
let _ = (event_loop, device_id, timestamp, event);
|
||||
let _ = (event_loop, device_id, event);
|
||||
}
|
||||
|
||||
/// Emitted when the event loop is about to block and wait for new events.
|
||||
@@ -382,10 +372,9 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
window_id: WindowId,
|
||||
timestamp: Instant,
|
||||
event: WindowEvent,
|
||||
) {
|
||||
(**self).window_event(event_loop, window_id, timestamp, event);
|
||||
(**self).window_event(event_loop, window_id, event);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -393,10 +382,9 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
device_id: Option<DeviceId>,
|
||||
timestamp: Instant,
|
||||
event: DeviceEvent,
|
||||
) {
|
||||
(**self).device_event(event_loop, device_id, timestamp, event);
|
||||
(**self).device_event(event_loop, device_id, event);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -452,10 +440,9 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
window_id: WindowId,
|
||||
timestamp: Instant,
|
||||
event: WindowEvent,
|
||||
) {
|
||||
(**self).window_event(event_loop, window_id, timestamp, event);
|
||||
(**self).window_event(event_loop, window_id, event);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -463,10 +450,9 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
device_id: Option<DeviceId>,
|
||||
timestamp: Instant,
|
||||
event: DeviceEvent,
|
||||
) {
|
||||
(**self).device_event(event_loop, device_id, timestamp, event);
|
||||
(**self).device_event(event_loop, device_id, event);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -12,7 +12,8 @@ use objc2_ui_kit::{
|
||||
UIApplicationWillResignActiveNotification, UIApplicationWillTerminateNotification, UIScreen,
|
||||
};
|
||||
use rwh_06::HasDisplayHandle;
|
||||
use winit_common::core_foundation::{MainRunLoop, MainRunLoopObserver};
|
||||
use tracing::debug_span;
|
||||
use winit_common::core_foundation::{MainRunLoop, MainRunLoopObserver, tracing_observers};
|
||||
use winit_core::application::ApplicationHandler;
|
||||
use winit_core::cursor::{CustomCursor, CustomCursorSource};
|
||||
use winit_core::error::{EventLoopError, NotSupportedError, RequestError};
|
||||
@@ -134,6 +135,7 @@ pub struct EventLoop {
|
||||
_will_terminate_observer: Retained<ProtocolObject<dyn NSObjectProtocol>>,
|
||||
_did_receive_memory_warning_observer: Retained<ProtocolObject<dyn NSObjectProtocol>>,
|
||||
|
||||
_tracing_observers: Option<(MainRunLoopObserver, MainRunLoopObserver)>,
|
||||
_wakeup_observer: MainRunLoopObserver,
|
||||
_main_events_cleared_observer: MainRunLoopObserver,
|
||||
_events_cleared_observer: MainRunLoopObserver,
|
||||
@@ -159,6 +161,7 @@ impl EventLoop {
|
||||
// `application:didFinishLaunchingWithOptions:`
|
||||
unsafe { UIApplicationDidFinishLaunchingNotification },
|
||||
move |_| {
|
||||
let _entered = debug_span!("UIApplicationDidFinishLaunchingNotification").entered();
|
||||
app_state::did_finish_launching(mtm);
|
||||
},
|
||||
);
|
||||
@@ -166,19 +169,27 @@ impl EventLoop {
|
||||
¢er,
|
||||
// `applicationDidBecomeActive:`
|
||||
unsafe { UIApplicationDidBecomeActiveNotification },
|
||||
move |_| app_state::handle_resumed(mtm),
|
||||
move |_| {
|
||||
let _entered = debug_span!("UIApplicationDidBecomeActiveNotification").entered();
|
||||
app_state::handle_resumed(mtm)
|
||||
},
|
||||
);
|
||||
let _will_resign_active_observer = create_observer(
|
||||
¢er,
|
||||
// `applicationWillResignActive:`
|
||||
unsafe { UIApplicationWillResignActiveNotification },
|
||||
move |_| app_state::handle_suspended(mtm),
|
||||
move |_| {
|
||||
let _entered = debug_span!("UIApplicationWillResignActiveNotification").entered();
|
||||
app_state::handle_suspended(mtm)
|
||||
},
|
||||
);
|
||||
let _will_enter_foreground_observer = create_observer(
|
||||
¢er,
|
||||
// `applicationWillEnterForeground:`
|
||||
unsafe { UIApplicationWillEnterForegroundNotification },
|
||||
move |notification| {
|
||||
let _entered =
|
||||
debug_span!("UIApplicationWillEnterForegroundNotification").entered();
|
||||
let app = notification.object().expect(
|
||||
"UIApplicationWillEnterForegroundNotification to have application object",
|
||||
);
|
||||
@@ -193,6 +204,7 @@ impl EventLoop {
|
||||
// `applicationDidEnterBackground:`
|
||||
unsafe { UIApplicationDidEnterBackgroundNotification },
|
||||
move |notification| {
|
||||
let _entered = debug_span!("UIApplicationDidEnterBackgroundNotification").entered();
|
||||
let app = notification.object().expect(
|
||||
"UIApplicationDidEnterBackgroundNotification to have application object",
|
||||
);
|
||||
@@ -207,6 +219,7 @@ impl EventLoop {
|
||||
// `applicationWillTerminate:`
|
||||
unsafe { UIApplicationWillTerminateNotification },
|
||||
move |notification| {
|
||||
let _entered = debug_span!("UIApplicationWillTerminateNotification").entered();
|
||||
let app = notification
|
||||
.object()
|
||||
.expect("UIApplicationWillTerminateNotification to have application object");
|
||||
@@ -220,18 +233,29 @@ impl EventLoop {
|
||||
¢er,
|
||||
// `applicationDidReceiveMemoryWarning:`
|
||||
unsafe { UIApplicationDidReceiveMemoryWarningNotification },
|
||||
move |_| app_state::handle_memory_warning(mtm),
|
||||
move |_| {
|
||||
let _entered =
|
||||
debug_span!("UIApplicationDidReceiveMemoryWarningNotification").entered();
|
||||
app_state::handle_memory_warning(mtm)
|
||||
},
|
||||
);
|
||||
|
||||
let main_loop = MainRunLoop::get(mtm);
|
||||
let mode = unsafe { kCFRunLoopDefaultMode }.unwrap();
|
||||
|
||||
// Tracing observers have the lowest and highest orderings.
|
||||
let _tracing_observers = tracing_observers(mtm).inspect(|(start, end)| {
|
||||
main_loop.add_observer(start, mode);
|
||||
main_loop.add_observer(end, mode);
|
||||
});
|
||||
|
||||
let _wakeup_observer = MainRunLoopObserver::new(
|
||||
mtm,
|
||||
CFRunLoopActivity::AfterWaiting,
|
||||
true,
|
||||
// Queued with the highest priority to ensure it is processed before other observers.
|
||||
CFIndex::MIN,
|
||||
// Queued with the second-highest priority (tracing observers use the highest) to
|
||||
// ensure it is processed before other observers.
|
||||
CFIndex::MIN + 1,
|
||||
move |_| app_state::handle_wakeup_transition(mtm),
|
||||
);
|
||||
main_loop.add_observer(&_wakeup_observer, mode);
|
||||
@@ -241,17 +265,17 @@ impl EventLoop {
|
||||
CFRunLoopActivity::BeforeWaiting,
|
||||
true,
|
||||
// Core Animation registers its `CFRunLoopObserver` that performs drawing operations in
|
||||
// `CA::Transaction::ensure_implicit` with a priority of `0x1e8480`. We set the
|
||||
// `CA::Transaction::ensure_implicit` with a priority of `2000000`. We set the
|
||||
// main_end priority to be 0, in order to send `AboutToWait` before `RedrawRequested`.
|
||||
// This value was chosen conservatively to guard against apple using different
|
||||
// priorities for their redraw observers in different OS's or on different devices. If
|
||||
// it so happens that it's too conservative, the main symptom would be non-redraw
|
||||
// events coming in after `AboutToWait`.
|
||||
//
|
||||
// The value of `0x1e8480` was determined by inspecting stack traces and the associated
|
||||
// The value of `2000000` was determined by inspecting stack traces and the associated
|
||||
// registers for every `CFRunLoopAddObserver` call on an iPad Air 2 running iOS 11.4.
|
||||
//
|
||||
// Also tested to be `0x1e8480` on iPhone 8, iOS 13 beta 4.
|
||||
// Also tested to be `2000000` on iPhone 8, iOS 13 beta 4.
|
||||
0,
|
||||
move |_| app_state::handle_main_events_cleared(mtm),
|
||||
);
|
||||
@@ -261,8 +285,9 @@ impl EventLoop {
|
||||
mtm,
|
||||
CFRunLoopActivity::BeforeWaiting,
|
||||
true,
|
||||
// Queued with the lowest priority to ensure it is processed after other observers.
|
||||
CFIndex::MAX,
|
||||
// Queued with the second-lowest priority (tracing observers use the lowest) to ensure
|
||||
// it is processed after other observers.
|
||||
CFIndex::MAX - 1,
|
||||
move |_| app_state::handle_events_cleared(mtm),
|
||||
);
|
||||
main_loop.add_observer(&_events_cleared_observer, mode);
|
||||
@@ -277,6 +302,7 @@ impl EventLoop {
|
||||
_did_enter_background_observer,
|
||||
_will_terminate_observer,
|
||||
_did_receive_memory_warning_observer,
|
||||
_tracing_observers,
|
||||
_wakeup_observer,
|
||||
_main_events_cleared_observer,
|
||||
_events_cleared_observer,
|
||||
|
||||
@@ -13,7 +13,7 @@ use objc2_ui_kit::{
|
||||
UIResponder, UIRotationGestureRecognizer, UITapGestureRecognizer, UITextInputTraits, UITouch,
|
||||
UITouchPhase, UITouchType, UITraitEnvironment, UIView,
|
||||
};
|
||||
use tracing::debug;
|
||||
use tracing::{debug, debug_span, trace_span};
|
||||
use winit_core::event::{
|
||||
ButtonSource, ElementState, FingerId, Force, KeyEvent, PointerKind, PointerSource,
|
||||
TabletToolAngle, TabletToolButton, TabletToolData, TabletToolKind, TouchPhase, WindowEvent,
|
||||
@@ -48,6 +48,7 @@ define_class!(
|
||||
impl WinitView {
|
||||
#[unsafe(method(drawRect:))]
|
||||
fn draw_rect(&self, rect: CGRect) {
|
||||
let _entered = debug_span!("drawRect:").entered();
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
let window = self.window().unwrap();
|
||||
app_state::handle_nonuser_event(mtm, EventWrapper::Window {
|
||||
@@ -59,6 +60,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(layoutSubviews))]
|
||||
fn layout_subviews(&self) {
|
||||
let _entered = debug_span!("layoutSubviews").entered();
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
let _: () = unsafe { msg_send![super(self), layoutSubviews] };
|
||||
|
||||
@@ -79,6 +81,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(setContentScaleFactor:))]
|
||||
fn set_content_scale_factor(&self, untrusted_scale_factor: CGFloat) {
|
||||
let _entered = debug_span!("setContentScaleFactor:").entered();
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
let _: () =
|
||||
unsafe { msg_send![super(self), setContentScaleFactor: untrusted_scale_factor] };
|
||||
@@ -124,6 +127,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(safeAreaInsetsDidChange))]
|
||||
fn safe_area_changed(&self) {
|
||||
let _entered = debug_span!("safeAreaInsetsDidChange").entered();
|
||||
debug!("safeAreaInsetsDidChange was called, requesting redraw");
|
||||
// When the safe area changes we want to make sure to emit a redraw event
|
||||
self.setNeedsDisplay();
|
||||
@@ -131,26 +135,31 @@ define_class!(
|
||||
|
||||
#[unsafe(method(touchesBegan:withEvent:))]
|
||||
fn touches_began(&self, touches: &NSSet<UITouch>, _event: Option<&UIEvent>) {
|
||||
let _entered = debug_span!("touchesBegan:withEvent:").entered();
|
||||
self.handle_touches(touches)
|
||||
}
|
||||
|
||||
#[unsafe(method(touchesMoved:withEvent:))]
|
||||
fn touches_moved(&self, touches: &NSSet<UITouch>, _event: Option<&UIEvent>) {
|
||||
let _entered = debug_span!("touchesMoved:withEvent:").entered();
|
||||
self.handle_touches(touches)
|
||||
}
|
||||
|
||||
#[unsafe(method(touchesEnded:withEvent:))]
|
||||
fn touches_ended(&self, touches: &NSSet<UITouch>, _event: Option<&UIEvent>) {
|
||||
let _entered = debug_span!("touchesEnded:withEvent:").entered();
|
||||
self.handle_touches(touches)
|
||||
}
|
||||
|
||||
#[unsafe(method(touchesCancelled:withEvent:))]
|
||||
fn touches_cancelled(&self, touches: &NSSet<UITouch>, _event: Option<&UIEvent>) {
|
||||
let _entered = debug_span!("touchesCancelled:withEvent:").entered();
|
||||
self.handle_touches(touches)
|
||||
}
|
||||
|
||||
#[unsafe(method(pinchGesture:))]
|
||||
fn pinch_gesture(&self, recognizer: &UIPinchGestureRecognizer) {
|
||||
let _entered = debug_span!("pinchGesture:").entered();
|
||||
let window = self.window().unwrap();
|
||||
|
||||
let (phase, delta) = match recognizer.state() {
|
||||
@@ -185,6 +194,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(doubleTapGesture:))]
|
||||
fn double_tap_gesture(&self, recognizer: &UITapGestureRecognizer) {
|
||||
let _entered = debug_span!("doubleTapGesture:").entered();
|
||||
let window = self.window().unwrap();
|
||||
|
||||
if recognizer.state() == UIGestureRecognizerState::Ended {
|
||||
@@ -200,6 +210,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(rotationGesture:))]
|
||||
fn rotation_gesture(&self, recognizer: &UIRotationGestureRecognizer) {
|
||||
let _entered = debug_span!("rotationGesture:").entered();
|
||||
let window = self.window().unwrap();
|
||||
|
||||
let (phase, delta) = match recognizer.state() {
|
||||
@@ -244,6 +255,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(panGesture:))]
|
||||
fn pan_gesture(&self, recognizer: &UIPanGestureRecognizer) {
|
||||
let _entered = debug_span!("panGesture:").entered();
|
||||
let window = self.window().unwrap();
|
||||
|
||||
let translation = recognizer.translationInView(Some(self));
|
||||
@@ -296,6 +308,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(canBecomeFirstResponder))]
|
||||
fn can_become_first_responder(&self) -> bool {
|
||||
let _entered = trace_span!("canBecomeFirstResponder").entered();
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -309,6 +322,10 @@ define_class!(
|
||||
_gesture_recognizer: &UIGestureRecognizer,
|
||||
_other_gesture_recognizer: &UIGestureRecognizer,
|
||||
) -> bool {
|
||||
let _entered = trace_span!(
|
||||
"gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:"
|
||||
)
|
||||
.entered();
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -318,16 +335,19 @@ define_class!(
|
||||
unsafe impl UIKeyInput for WinitView {
|
||||
#[unsafe(method(hasText))]
|
||||
fn has_text(&self) -> bool {
|
||||
let _entered = debug_span!("hasText").entered();
|
||||
true
|
||||
}
|
||||
|
||||
#[unsafe(method(insertText:))]
|
||||
fn insert_text(&self, text: &NSString) {
|
||||
let _entered = debug_span!("insertText:").entered();
|
||||
self.handle_insert_text(text)
|
||||
}
|
||||
|
||||
#[unsafe(method(deleteBackward))]
|
||||
fn delete_backward(&self) {
|
||||
let _entered = debug_span!("deleteBackward").entered();
|
||||
self.handle_delete_backward()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use objc2_ui_kit::{
|
||||
UIDevice, UIInterfaceOrientationMask, UIRectEdge, UIResponder, UIStatusBarStyle,
|
||||
UIUserInterfaceIdiom, UIView, UIViewController,
|
||||
};
|
||||
use tracing::trace_span;
|
||||
|
||||
use crate::{ScreenEdge, StatusBarStyle, ValidOrientations, WindowAttributesIos};
|
||||
|
||||
@@ -28,31 +29,37 @@ define_class!(
|
||||
impl WinitViewController {
|
||||
#[unsafe(method(shouldAutorotate))]
|
||||
fn should_autorotate(&self) -> bool {
|
||||
let _entered = trace_span!("shouldAutorotate").entered();
|
||||
true
|
||||
}
|
||||
|
||||
#[unsafe(method(prefersStatusBarHidden))]
|
||||
fn prefers_status_bar_hidden(&self) -> bool {
|
||||
let _entered = trace_span!("prefersStatusBarHidden").entered();
|
||||
self.ivars().prefers_status_bar_hidden.get()
|
||||
}
|
||||
|
||||
#[unsafe(method(preferredStatusBarStyle))]
|
||||
fn preferred_status_bar_style(&self) -> UIStatusBarStyle {
|
||||
let _entered = trace_span!("preferredStatusBarStyle").entered();
|
||||
self.ivars().preferred_status_bar_style.get()
|
||||
}
|
||||
|
||||
#[unsafe(method(prefersHomeIndicatorAutoHidden))]
|
||||
fn prefers_home_indicator_auto_hidden(&self) -> bool {
|
||||
let _entered = trace_span!("prefersHomeIndicatorAutoHidden").entered();
|
||||
self.ivars().prefers_home_indicator_auto_hidden.get()
|
||||
}
|
||||
|
||||
#[unsafe(method(supportedInterfaceOrientations))]
|
||||
fn supported_orientations(&self) -> UIInterfaceOrientationMask {
|
||||
let _entered = trace_span!("supportedInterfaceOrientations").entered();
|
||||
self.ivars().supported_orientations.get()
|
||||
}
|
||||
|
||||
#[unsafe(method(preferredScreenEdgesDeferringSystemGestures))]
|
||||
fn preferred_screen_edges_deferring_system_gestures(&self) -> UIRectEdge {
|
||||
let _entered = trace_span!("preferredScreenEdgesDeferringSystemGestures").entered();
|
||||
self.ivars().preferred_screen_edges_deferring_system_gestures.get()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use objc2_ui_kit::{
|
||||
UIApplication, UICoordinateSpace, UIEdgeInsets, UIResponder, UIScreen,
|
||||
UIScreenOverscanCompensation, UIViewController, UIWindow,
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
use tracing::{debug, debug_span, warn};
|
||||
use winit_core::cursor::Cursor;
|
||||
use winit_core::error::{NotSupportedError, RequestError};
|
||||
use winit_core::event::WindowEvent;
|
||||
@@ -46,6 +46,7 @@ define_class!(
|
||||
impl WinitUIWindow {
|
||||
#[unsafe(method(becomeKeyWindow))]
|
||||
fn become_key_window(&self) {
|
||||
let _entered = debug_span!("becomeKeyWindow").entered();
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
app_state::handle_nonuser_event(mtm, EventWrapper::Window {
|
||||
window_id: self.id(),
|
||||
@@ -56,6 +57,7 @@ define_class!(
|
||||
|
||||
#[unsafe(method(resignKeyWindow))]
|
||||
fn resign_key_window(&self) {
|
||||
let _entered = debug_span!("resignKeyWindow").entered();
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
app_state::handle_nonuser_event(mtm, EventWrapper::Window {
|
||||
window_id: self.id(),
|
||||
|
||||
@@ -387,11 +387,7 @@ impl LayoutCache {
|
||||
let unicode = Self::to_unicode_string(&key_state, vk, scancode, locale_id);
|
||||
let key = match unicode {
|
||||
ToUnicodeResult::Str(str) => Key::Character(SmolStr::new(str)),
|
||||
ToUnicodeResult::Dead(dead_char) => {
|
||||
// println!("{:?} - {:?} produced dead {:?}", key_code, mod_state,
|
||||
// dead_char);
|
||||
Key::Dead(dead_char)
|
||||
},
|
||||
ToUnicodeResult::Dead(dead_char) => Key::Dead(dead_char),
|
||||
ToUnicodeResult::None => {
|
||||
let has_alt = mod_state.contains(WindowsModifiers::ALT);
|
||||
let has_ctrl = mod_state.contains(WindowsModifiers::CONTROL);
|
||||
|
||||
@@ -66,7 +66,6 @@ impl XConnection {
|
||||
// All util functions that abstract an async function will return a `Flusher`.
|
||||
pub fn flush_requests(&self) -> Result<(), XError> {
|
||||
unsafe { (self.xlib.XFlush)(self.display) };
|
||||
// println!("XFlush");
|
||||
// This isn't necessarily a useful time to check for errors (since our request hasn't
|
||||
// necessarily been processed yet)
|
||||
self.check_errors()
|
||||
@@ -74,7 +73,6 @@ impl XConnection {
|
||||
|
||||
pub fn sync_with_server(&self) -> Result<(), XError> {
|
||||
unsafe { (self.xlib.XSync)(self.display, ffi::False) };
|
||||
// println!("XSync");
|
||||
self.check_errors()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use cfg_aliases::cfg_aliases;
|
||||
|
||||
// Only relevant for examples and Winit, our usage of println! is fine here.
|
||||
#[allow(clippy::disallowed_macros)]
|
||||
fn main() {
|
||||
// The script doesn't depend on our code.
|
||||
// Dummy invocation to enable change-tracking in build scripts.
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
// Setup cfg aliases.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
fn main() -> Result<(), impl std::error::Error> {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::{LogicalPosition, LogicalSize, Position};
|
||||
use winit::event::{ElementState, KeyEvent, WindowEvent};
|
||||
@@ -38,7 +39,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
|
||||
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
|
||||
let window = event_loop.create_window(attributes).unwrap();
|
||||
println!("Parent window id: {:?})", window.id());
|
||||
info!("Parent window id: {:?})", window.id());
|
||||
self.parent_window_id = Some(window.id());
|
||||
|
||||
self.windows.insert(window.id(), WindowData::new(window, 0xffbbbbbb));
|
||||
@@ -56,12 +57,12 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
event_loop.exit();
|
||||
},
|
||||
WindowEvent::PointerEntered { device_id: _, .. } => {
|
||||
// On x11, println when the cursor entered in a window even if the child window
|
||||
// On x11, log when the cursor entered in a window even if the child window
|
||||
// is created by some key inputs.
|
||||
// the child windows are always placed at (0, 0) with size (200, 200) in the
|
||||
// parent window, so we also can see this log when we move
|
||||
// the cursor around (200, 200) in parent window.
|
||||
println!("cursor entered in the window {window_id:?}");
|
||||
info!("cursor entered in the window {window_id:?}");
|
||||
},
|
||||
WindowEvent::KeyboardInput {
|
||||
event: KeyEvent { state: ElementState::Pressed, .. },
|
||||
@@ -75,7 +76,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
let child_window =
|
||||
spawn_child_window(parent_window.window.as_ref(), event_loop, child_index);
|
||||
let child_id = child_window.id();
|
||||
println!("Child window created with id: {child_id:?}");
|
||||
info!("Child window created with id: {child_id:?}");
|
||||
self.windows.insert(child_id, WindowData::new(child_window, child_color));
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::thread;
|
||||
#[cfg(not(web_platform))]
|
||||
use std::time;
|
||||
|
||||
use ::tracing::{info, warn};
|
||||
use tracing::{info, warn};
|
||||
#[cfg(web_platform)]
|
||||
use web_time as time;
|
||||
use winit::application::ApplicationHandler;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::error::Error;
|
||||
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
@@ -49,7 +50,7 @@ impl ApplicationHandler for Application {
|
||||
| WindowEvent::DragEntered { .. }
|
||||
| WindowEvent::DragMoved { .. }
|
||||
| WindowEvent::DragDropped { .. } => {
|
||||
println!("{event:?}");
|
||||
info!("{event:?}");
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
let window = self.window.as_ref().unwrap();
|
||||
|
||||
@@ -76,7 +76,7 @@ impl ApplicationHandler for App {
|
||||
self.window = match event_loop.create_window(window_attributes) {
|
||||
Ok(window) => Some(window),
|
||||
Err(err) => {
|
||||
eprintln!("error creating window: {err}");
|
||||
error!("error creating window: {err}");
|
||||
event_loop.exit();
|
||||
return;
|
||||
},
|
||||
@@ -346,7 +346,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
|
||||
println!(
|
||||
info!(
|
||||
r#"This showcases the use of an input method engine (IME) by emulating a text edit field.
|
||||
Use CTRL+i to toggle IME support.
|
||||
Use CTRL+p to cycle content purpose values.
|
||||
|
||||
@@ -7,6 +7,7 @@ fn main() -> std::process::ExitCode {
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||
@@ -15,6 +16,8 @@ fn main() -> std::process::ExitCode {
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
mod fill;
|
||||
#[path = "util/tracing.rs"]
|
||||
mod tracing;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct PumpDemo {
|
||||
@@ -33,7 +36,7 @@ fn main() -> std::process::ExitCode {
|
||||
_window_id: WindowId,
|
||||
event: WindowEvent,
|
||||
) {
|
||||
println!("{event:?}");
|
||||
info!("{event:?}");
|
||||
|
||||
let window = match self.window.as_ref() {
|
||||
Some(window) => window,
|
||||
@@ -51,9 +54,9 @@ fn main() -> std::process::ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
let mut event_loop = EventLoop::new().unwrap();
|
||||
tracing::init();
|
||||
|
||||
tracing_subscriber::fmt::init();
|
||||
let mut event_loop = EventLoop::new().unwrap();
|
||||
|
||||
let mut app = PumpDemo::default();
|
||||
|
||||
@@ -69,12 +72,12 @@ fn main() -> std::process::ExitCode {
|
||||
//
|
||||
// Since `pump_events` doesn't block it will be important to
|
||||
// throttle the loop in the app somehow.
|
||||
println!("Update()");
|
||||
info!("Update()");
|
||||
sleep(Duration::from_millis(16));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(ios_platform, web_platform, orbital_platform))]
|
||||
fn main() {
|
||||
println!("This platform doesn't support pump_events.");
|
||||
panic!("This platform doesn't support pump_events.")
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::time::Duration;
|
||||
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::run_on_demand::EventLoopExtRunOnDemand;
|
||||
@@ -13,6 +14,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
mod fill;
|
||||
#[path = "util/tracing.rs"]
|
||||
mod tracing;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct App {
|
||||
@@ -44,10 +47,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
event: WindowEvent,
|
||||
) {
|
||||
if event == WindowEvent::Destroyed && self.window_id == Some(window_id) {
|
||||
println!(
|
||||
"--------------------------------------------------------- Window {} Destroyed",
|
||||
self.idx
|
||||
);
|
||||
info!("Window {} Destroyed", self.idx);
|
||||
self.window_id = None;
|
||||
event_loop.exit();
|
||||
return;
|
||||
@@ -60,11 +60,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
println!(
|
||||
"--------------------------------------------------------- Window {} \
|
||||
CloseRequested",
|
||||
self.idx
|
||||
);
|
||||
info!("Window {} CloseRequested", self.idx);
|
||||
fill::cleanup_window(window.as_ref());
|
||||
self.window = None;
|
||||
},
|
||||
@@ -76,20 +72,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
tracing_subscriber::fmt::init();
|
||||
tracing::init();
|
||||
|
||||
let mut event_loop = EventLoop::new().unwrap();
|
||||
|
||||
let mut app = App { idx: 1, ..Default::default() };
|
||||
event_loop.run_app_on_demand(&mut app)?;
|
||||
|
||||
println!("--------------------------------------------------------- Finished first loop");
|
||||
println!("--------------------------------------------------------- Waiting 5 seconds");
|
||||
info!("Finished first loop");
|
||||
info!("Waiting 5 seconds");
|
||||
std::thread::sleep(Duration::from_secs(5));
|
||||
|
||||
app.idx += 1;
|
||||
event_loop.run_app_on_demand(&mut app)?;
|
||||
println!("--------------------------------------------------------- Finished second loop");
|
||||
info!("Finished second loop");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -101,5 +97,5 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
orbital_platform
|
||||
)))]
|
||||
fn main() {
|
||||
println!("This example is not supported on this platform");
|
||||
panic!("This example is not supported on this platform")
|
||||
}
|
||||
|
||||
@@ -23,3 +23,6 @@ pub fn init() {
|
||||
)
|
||||
.init();
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub use ::tracing::*;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Simple winit window example.
|
||||
|
||||
use std::error::Error;
|
||||
use std::time::Instant;
|
||||
|
||||
use tracing::{error, info};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
@@ -30,24 +30,18 @@ impl ApplicationHandler for App {
|
||||
self.window = match event_loop.create_window(window_attributes) {
|
||||
Ok(window) => Some(window),
|
||||
Err(err) => {
|
||||
eprintln!("error creating window: {err}");
|
||||
error!("error creating window: {err}");
|
||||
event_loop.exit();
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event_loop: &dyn ActiveEventLoop,
|
||||
_: WindowId,
|
||||
timestamp: Instant,
|
||||
event: WindowEvent,
|
||||
) {
|
||||
::tracing::info!("{:?}: {event:?}", timestamp.elapsed());
|
||||
fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _: WindowId, event: WindowEvent) {
|
||||
info!("{event:?}");
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
println!("Close was requested; stopping");
|
||||
info!("Close was requested; stopping");
|
||||
event_loop.exit();
|
||||
},
|
||||
WindowEvent::SurfaceResized(_) => {
|
||||
@@ -69,21 +63,11 @@ impl ApplicationHandler for App {
|
||||
fill::fill_window(window.as_ref());
|
||||
|
||||
// For contiguous redraw loop you can request a redraw from here.
|
||||
window.request_redraw();
|
||||
// window.request_redraw();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn device_event(
|
||||
&mut self,
|
||||
_event_loop: &dyn ActiveEventLoop,
|
||||
_device_id: Option<winit::event::DeviceId>,
|
||||
timestamp: Instant,
|
||||
event: winit::event::DeviceEvent,
|
||||
) {
|
||||
::tracing::info!("{:?}: {event:?}", timestamp.elapsed());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
@@ -11,6 +11,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
mod fill;
|
||||
#[path = "util/tracing.rs"]
|
||||
mod tracing;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XEmbedDemo {
|
||||
@@ -58,7 +60,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
.ok_or("Expected a 32-bit X11 window ID as the first argument.")?
|
||||
.parse::<u32>()?;
|
||||
|
||||
tracing_subscriber::fmt::init();
|
||||
tracing::init();
|
||||
let event_loop = EventLoop::new()?;
|
||||
|
||||
Ok(event_loop.run_app(XEmbedDemo { parent_window_id, window: None })?)
|
||||
@@ -66,6 +68,5 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
#[cfg(not(x11_platform))]
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
println!("This example is only supported on X11 platforms.");
|
||||
Ok(())
|
||||
panic!("This example is only supported on X11 platforms.")
|
||||
}
|
||||
|
||||
@@ -46,11 +46,13 @@ changelog entry.
|
||||
- On iOS, add Apple Pencil support with force, altitude, and azimuth data.
|
||||
- On Redox, add support for missing keyboard scancodes.
|
||||
- Implement `Send` and `Sync` for `OwnedDisplayHandle`.
|
||||
- Use new macOS 15 cursors for resize icons.
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `windows-sys` to `v0.61`.
|
||||
- On older macOS versions (tested up to 12.7.6), applications now receive mouse movement events for unfocused windows, matching the behavior on other platforms.
|
||||
- On macOS, the application is now launched in `EventLoop::new` instead of `EventLoop::run_app`. If you're registering a custom delegate, you should now register it before `EventLoop::new`.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ impl EventLoopBuilder {
|
||||
/// `DISPLAY` respectively when building the event loop.
|
||||
/// - **Android:** must be configured with an `AndroidApp` from `android_main()` by calling
|
||||
/// [`.with_android_app(app)`] before calling `.build()`, otherwise it'll panic.
|
||||
/// - **macOS:** this will launch the application, so if you want to register a custom delegate,
|
||||
/// or otherwise do stuff before `applicationDidFinishLaunching:`, you should do it before
|
||||
/// this function is called.
|
||||
///
|
||||
/// [`platform`]: crate::platform
|
||||
#[cfg_attr(
|
||||
@@ -88,7 +91,7 @@ impl EventLoopBuilder {
|
||||
)]
|
||||
#[inline]
|
||||
pub fn build(&mut self) -> Result<EventLoop, EventLoopError> {
|
||||
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
|
||||
let _entered = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
|
||||
|
||||
// Certain platforms accept a mutable reference in their API.
|
||||
#[allow(clippy::unnecessary_mut_passed)]
|
||||
@@ -262,7 +265,7 @@ impl EventLoop {
|
||||
///
|
||||
/// [`DeviceEvent`]: crate::event::DeviceEvent
|
||||
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
||||
let _span = tracing::debug_span!(
|
||||
let _entered = tracing::debug_span!(
|
||||
"winit::EventLoop::listen_device_events",
|
||||
allowed = ?allowed
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user