macOS: Run tasks synchronously on main thread instead of asynchronously (#2574)
* Close windows synchronously on main thread * Set style mask synchronously on main thread * Set title synchronously on main thread * Set visibility and focus synchronously on main thread * Set window level synchronously on main thread * Set position and size synchronously on main thread * Set cursor hittest synchronously on main thread * Add changelog entry
This commit is contained in:
parent
2a58b785fe
commit
bf92f3e97b
4 changed files with 54 additions and 63 deletions
|
|
@ -1,4 +1,3 @@
|
|||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
use dispatch::Queue;
|
||||
|
|
@ -29,6 +28,14 @@ impl<T> Deref for MainThreadSafe<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_on_main<R: Send>(f: impl FnOnce() -> R + Send) -> R {
|
||||
if is_main_thread() {
|
||||
f()
|
||||
} else {
|
||||
Queue::main().exec_sync(f)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_style_mask(window: &NSWindow, mask: NSWindowStyleMask) {
|
||||
window.setStyleMask(mask);
|
||||
// If we don't do this, key handling will break
|
||||
|
|
@ -40,54 +47,43 @@ fn set_style_mask(window: &NSWindow, mask: NSWindowStyleMask) {
|
|||
// `setStyleMask:` isn't thread-safe, so we have to use Grand Central Dispatch.
|
||||
// Otherwise, this would vomit out errors about not being on the main thread
|
||||
// and fail to do anything.
|
||||
pub(crate) fn set_style_mask_async(window: &NSWindow, mask: NSWindowStyleMask) {
|
||||
// TODO(madsmtm): Remove this 'static hack!
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
set_style_mask(&window, mask);
|
||||
});
|
||||
}
|
||||
pub(crate) fn set_style_mask_sync(window: &NSWindow, mask: NSWindowStyleMask) {
|
||||
if is_main_thread() {
|
||||
set_style_mask(window, mask);
|
||||
} else {
|
||||
let window = MainThreadSafe(window);
|
||||
Queue::main().exec_sync(move || {
|
||||
set_style_mask(&window, mask);
|
||||
})
|
||||
}
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
set_style_mask(&window, mask);
|
||||
})
|
||||
}
|
||||
|
||||
// `setContentSize:` isn't thread-safe either, though it doesn't log any errors
|
||||
// and just fails silently. Anyway, GCD to the rescue!
|
||||
pub(crate) fn set_content_size_async(window: &NSWindow, size: LogicalSize<f64>) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
pub(crate) fn set_content_size_sync(window: &NSWindow, size: LogicalSize<f64>) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.setContentSize(NSSize::new(size.width as CGFloat, size.height as CGFloat));
|
||||
});
|
||||
}
|
||||
|
||||
// `setFrameTopLeftPoint:` isn't thread-safe, but fortunately has the courtesy
|
||||
// to log errors.
|
||||
pub(crate) fn set_frame_top_left_point_async(window: &NSWindow, point: NSPoint) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
pub(crate) fn set_frame_top_left_point_sync(window: &NSWindow, point: NSPoint) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.setFrameTopLeftPoint(point);
|
||||
});
|
||||
}
|
||||
|
||||
// `setFrameTopLeftPoint:` isn't thread-safe, and fails silently.
|
||||
pub(crate) fn set_level_async(window: &NSWindow, level: NSWindowLevel) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
pub(crate) fn set_level_sync(window: &NSWindow, level: NSWindowLevel) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.setLevel(level);
|
||||
});
|
||||
}
|
||||
|
||||
// `setIgnoresMouseEvents_:` isn't thread-safe, and fails silently.
|
||||
pub(crate) fn set_ignore_mouse_events(window: &NSWindow, ignore: bool) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
pub(crate) fn set_ignore_mouse_events_sync(window: &NSWindow, ignore: bool) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.setIgnoresMouseEvents(ignore);
|
||||
});
|
||||
}
|
||||
|
|
@ -171,18 +167,18 @@ pub(crate) fn set_maximized_async(
|
|||
|
||||
// `orderOut:` isn't thread-safe. Calling it from another thread actually works,
|
||||
// but with an odd delay.
|
||||
pub(crate) fn order_out_async(window: &NSWindow) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
pub(crate) fn order_out_sync(window: &NSWindow) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.orderOut(None);
|
||||
});
|
||||
}
|
||||
|
||||
// `makeKeyAndOrderFront:` isn't thread-safe. Calling it from another thread
|
||||
// actually works, but with an odd delay.
|
||||
pub(crate) fn make_key_and_order_front_async(window: &NSWindow) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
pub(crate) fn make_key_and_order_front_sync(window: &NSWindow) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.makeKeyAndOrderFront(None);
|
||||
});
|
||||
}
|
||||
|
|
@ -190,21 +186,18 @@ pub(crate) fn make_key_and_order_front_async(window: &NSWindow) {
|
|||
// `setTitle:` isn't thread-safe. Calling it from another thread invalidates the
|
||||
// window drag regions, which throws an exception when not done in the main
|
||||
// thread
|
||||
pub(crate) fn set_title_async(window: &NSWindow, title: String) {
|
||||
let window = unsafe { MainThreadSafe(mem::transmute::<&NSWindow, &'static NSWindow>(window)) };
|
||||
Queue::main().exec_async(move || {
|
||||
window.setTitle(&NSString::from_str(&title));
|
||||
pub(crate) fn set_title_sync(window: &NSWindow, title: &str) {
|
||||
let window = MainThreadSafe(window);
|
||||
run_on_main(move || {
|
||||
window.setTitle(&NSString::from_str(title));
|
||||
});
|
||||
}
|
||||
|
||||
// `close:` is thread-safe, but we want the event to be triggered from the main
|
||||
// thread. Though, it's a good idea to look into that more...
|
||||
//
|
||||
// ArturKovacs: It's important that this operation keeps the underlying window alive
|
||||
// through the `Id` because otherwise it would dereference free'd memory
|
||||
pub(crate) fn close_async(window: Id<NSWindow, Shared>) {
|
||||
pub(crate) fn close_sync(window: &NSWindow) {
|
||||
let window = MainThreadSafe(window);
|
||||
Queue::main().exec_async(move || {
|
||||
run_on_main(move || {
|
||||
autoreleasepool(move |_| {
|
||||
window.close();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue