mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 22:31:30 +11:00
Simplify code by switching to higher-level dispatch APIs (#1409)
* Switch to higher-level dispatch APIs * Inline all the functions * Switch to autoreleasepool from objc
This commit is contained in:
parent
d934f94704
commit
e48262a797
|
@ -41,7 +41,7 @@ objc = "0.2.3"
|
||||||
cocoa = "0.19.1"
|
cocoa = "0.19.1"
|
||||||
core-foundation = "0.6"
|
core-foundation = "0.6"
|
||||||
core-graphics = "0.17.3"
|
core-graphics = "0.17.3"
|
||||||
dispatch = "0.1.4"
|
dispatch = "0.2.0"
|
||||||
objc = "0.2.6"
|
objc = "0.2.6"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies.core-video-sys]
|
[target.'cfg(target_os = "macos")'.dependencies.core-video-sys]
|
||||||
|
|
|
@ -1,20 +1,36 @@
|
||||||
use std::{
|
use std::{
|
||||||
os::raw::c_void,
|
ops::Deref,
|
||||||
sync::{Mutex, Weak},
|
sync::{Mutex, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
appkit::{CGFloat, NSScreen, NSWindow, NSWindowStyleMask},
|
appkit::{CGFloat, NSScreen, NSWindow, NSWindowStyleMask},
|
||||||
base::{id, nil},
|
base::{id, nil},
|
||||||
foundation::{NSAutoreleasePool, NSPoint, NSSize, NSString},
|
foundation::{NSPoint, NSSize, NSString},
|
||||||
};
|
};
|
||||||
use dispatch::ffi::{dispatch_async_f, dispatch_get_main_queue, dispatch_sync_f};
|
use dispatch::Queue;
|
||||||
|
use objc::rc::autoreleasepool;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::LogicalSize,
|
dpi::LogicalSize,
|
||||||
platform_impl::platform::{ffi, util::IdRef, window::SharedState},
|
platform_impl::platform::{ffi, util::IdRef, window::SharedState},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Unsafe wrapper type that allows us to dispatch things that aren't Send.
|
||||||
|
// This should *only* be used to dispatch to the main queue.
|
||||||
|
// While it is indeed not guaranteed that these types can safely be sent to
|
||||||
|
// other threads, we know that they're safe to use on the main thread.
|
||||||
|
struct MainThreadSafe<T>(T);
|
||||||
|
|
||||||
|
unsafe impl<T> Send for MainThreadSafe<T> {}
|
||||||
|
|
||||||
|
impl<T> Deref for MainThreadSafe<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn set_style_mask(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
unsafe fn set_style_mask(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
||||||
ns_window.setStyleMask_(mask);
|
ns_window.setStyleMask_(mask);
|
||||||
// If we don't do this, key handling will break
|
// If we don't do this, key handling will break
|
||||||
|
@ -22,203 +38,55 @@ unsafe fn set_style_mask(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
||||||
ns_window.makeFirstResponder_(ns_view);
|
ns_window.makeFirstResponder_(ns_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SetStyleMaskData {
|
|
||||||
ns_window: id,
|
|
||||||
ns_view: id,
|
|
||||||
mask: NSWindowStyleMask,
|
|
||||||
}
|
|
||||||
impl SetStyleMaskData {
|
|
||||||
fn new_ptr(ns_window: id, ns_view: id, mask: NSWindowStyleMask) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetStyleMaskData {
|
|
||||||
ns_window,
|
|
||||||
ns_view,
|
|
||||||
mask,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn set_style_mask_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut SetStyleMaskData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
set_style_mask(context.ns_window, context.ns_view, context.mask);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Always use this function instead of trying to modify `styleMask` directly!
|
// Always use this function instead of trying to modify `styleMask` directly!
|
||||||
// `setStyleMask:` isn't thread-safe, so we have to use Grand Central Dispatch.
|
// `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
|
// Otherwise, this would vomit out errors about not being on the main thread
|
||||||
// and fail to do anything.
|
// and fail to do anything.
|
||||||
pub unsafe fn set_style_mask_async(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
pub unsafe fn set_style_mask_async(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
||||||
let context = SetStyleMaskData::new_ptr(ns_window, ns_view, mask);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
let ns_view = MainThreadSafe(ns_view);
|
||||||
dispatch_get_main_queue(),
|
Queue::main().exec_async(move || {
|
||||||
context as *mut _,
|
set_style_mask(*ns_window, *ns_view, mask);
|
||||||
set_style_mask_callback,
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
pub unsafe fn set_style_mask_sync(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
pub unsafe fn set_style_mask_sync(ns_window: id, ns_view: id, mask: NSWindowStyleMask) {
|
||||||
let context = SetStyleMaskData::new_ptr(ns_window, ns_view, mask);
|
|
||||||
if msg_send![class!(NSThread), isMainThread] {
|
if msg_send![class!(NSThread), isMainThread] {
|
||||||
set_style_mask_callback(context as *mut _);
|
set_style_mask(ns_window, ns_view, mask);
|
||||||
} else {
|
} else {
|
||||||
dispatch_sync_f(
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_get_main_queue(),
|
let ns_view = MainThreadSafe(ns_view);
|
||||||
context as *mut _,
|
Queue::main().exec_sync(move || {
|
||||||
set_style_mask_callback,
|
set_style_mask(*ns_window, *ns_view, mask);
|
||||||
);
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SetContentSizeData {
|
|
||||||
ns_window: id,
|
|
||||||
size: LogicalSize<f64>,
|
|
||||||
}
|
|
||||||
impl SetContentSizeData {
|
|
||||||
fn new_ptr(ns_window: id, size: LogicalSize<f64>) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetContentSizeData { ns_window, size }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn set_content_size_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut SetContentSizeData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
NSWindow::setContentSize_(
|
|
||||||
context.ns_window,
|
|
||||||
NSSize::new(
|
|
||||||
context.size.width as CGFloat,
|
|
||||||
context.size.height as CGFloat,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `setContentSize:` isn't thread-safe either, though it doesn't log any errors
|
// `setContentSize:` isn't thread-safe either, though it doesn't log any errors
|
||||||
// and just fails silently. Anyway, GCD to the rescue!
|
// and just fails silently. Anyway, GCD to the rescue!
|
||||||
pub unsafe fn set_content_size_async(ns_window: id, size: LogicalSize<f64>) {
|
pub unsafe fn set_content_size_async(ns_window: id, size: LogicalSize<f64>) {
|
||||||
let context = SetContentSizeData::new_ptr(ns_window, size);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
Queue::main().exec_async(move || {
|
||||||
dispatch_get_main_queue(),
|
ns_window.setContentSize_(NSSize::new(size.width as CGFloat, size.height as CGFloat));
|
||||||
context as *mut _,
|
});
|
||||||
set_content_size_callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SetFrameTopLeftPointData {
|
|
||||||
ns_window: id,
|
|
||||||
point: NSPoint,
|
|
||||||
}
|
|
||||||
impl SetFrameTopLeftPointData {
|
|
||||||
fn new_ptr(ns_window: id, point: NSPoint) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetFrameTopLeftPointData { ns_window, point }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn set_frame_top_left_point_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut SetFrameTopLeftPointData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
NSWindow::setFrameTopLeftPoint_(context.ns_window, context.point);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `setFrameTopLeftPoint:` isn't thread-safe, but fortunately has the courtesy
|
// `setFrameTopLeftPoint:` isn't thread-safe, but fortunately has the courtesy
|
||||||
// to log errors.
|
// to log errors.
|
||||||
pub unsafe fn set_frame_top_left_point_async(ns_window: id, point: NSPoint) {
|
pub unsafe fn set_frame_top_left_point_async(ns_window: id, point: NSPoint) {
|
||||||
let context = SetFrameTopLeftPointData::new_ptr(ns_window, point);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
Queue::main().exec_async(move || {
|
||||||
dispatch_get_main_queue(),
|
ns_window.setFrameTopLeftPoint_(point);
|
||||||
context as *mut _,
|
});
|
||||||
set_frame_top_left_point_callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SetLevelData {
|
|
||||||
ns_window: id,
|
|
||||||
level: ffi::NSWindowLevel,
|
|
||||||
}
|
|
||||||
impl SetLevelData {
|
|
||||||
fn new_ptr(ns_window: id, level: ffi::NSWindowLevel) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetLevelData { ns_window, level }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn set_level_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut SetLevelData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
context.ns_window.setLevel_(context.level as _);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `setFrameTopLeftPoint:` isn't thread-safe, and fails silently.
|
// `setFrameTopLeftPoint:` isn't thread-safe, and fails silently.
|
||||||
pub unsafe fn set_level_async(ns_window: id, level: ffi::NSWindowLevel) {
|
pub unsafe fn set_level_async(ns_window: id, level: ffi::NSWindowLevel) {
|
||||||
let context = SetLevelData::new_ptr(ns_window, level);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
Queue::main().exec_async(move || {
|
||||||
dispatch_get_main_queue(),
|
ns_window.setLevel_(level as _);
|
||||||
context as *mut _,
|
});
|
||||||
set_level_callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ToggleFullScreenData {
|
|
||||||
ns_window: id,
|
|
||||||
ns_view: id,
|
|
||||||
not_fullscreen: bool,
|
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
|
||||||
}
|
|
||||||
impl ToggleFullScreenData {
|
|
||||||
fn new_ptr(
|
|
||||||
ns_window: id,
|
|
||||||
ns_view: id,
|
|
||||||
not_fullscreen: bool,
|
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
|
||||||
) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(ToggleFullScreenData {
|
|
||||||
ns_window,
|
|
||||||
ns_view,
|
|
||||||
not_fullscreen,
|
|
||||||
shared_state,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn toggle_full_screen_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut ToggleFullScreenData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
|
|
||||||
// `toggleFullScreen` doesn't work if the `StyleMask` is none, so we
|
|
||||||
// set a normal style temporarily. The previous state will be
|
|
||||||
// restored in `WindowDelegate::window_did_exit_fullscreen`.
|
|
||||||
if context.not_fullscreen {
|
|
||||||
let curr_mask = context.ns_window.styleMask();
|
|
||||||
let required = NSWindowStyleMask::NSTitledWindowMask
|
|
||||||
| NSWindowStyleMask::NSResizableWindowMask;
|
|
||||||
if !curr_mask.contains(required) {
|
|
||||||
set_style_mask(context.ns_window, context.ns_view, required);
|
|
||||||
if let Some(shared_state) = context.shared_state.upgrade() {
|
|
||||||
trace!("Locked shared state in `toggle_full_screen_callback`");
|
|
||||||
let mut shared_state_lock = shared_state.lock().unwrap();
|
|
||||||
(*shared_state_lock).saved_style = Some(curr_mask);
|
|
||||||
trace!("Unlocked shared state in `toggle_full_screen_callback`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Window level must be restored from `CGShieldingWindowLevel()
|
|
||||||
// + 1` back to normal in order for `toggleFullScreen` to do
|
|
||||||
// anything
|
|
||||||
context.ns_window.setLevel_(0);
|
|
||||||
context.ns_window.toggleFullScreen_(nil);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `toggleFullScreen` is thread-safe, but our additional logic to account for
|
// `toggleFullScreen` is thread-safe, but our additional logic to account for
|
||||||
// window styles isn't.
|
// window styles isn't.
|
||||||
pub unsafe fn toggle_full_screen_async(
|
pub unsafe fn toggle_full_screen_async(
|
||||||
|
@ -227,91 +95,42 @@ pub unsafe fn toggle_full_screen_async(
|
||||||
not_fullscreen: bool,
|
not_fullscreen: bool,
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
shared_state: Weak<Mutex<SharedState>>,
|
||||||
) {
|
) {
|
||||||
let context = ToggleFullScreenData::new_ptr(ns_window, ns_view, not_fullscreen, shared_state);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
let ns_view = MainThreadSafe(ns_view);
|
||||||
dispatch_get_main_queue(),
|
let shared_state = MainThreadSafe(shared_state);
|
||||||
context as *mut _,
|
Queue::main().exec_async(move || {
|
||||||
toggle_full_screen_callback,
|
// `toggleFullScreen` doesn't work if the `StyleMask` is none, so we
|
||||||
);
|
// set a normal style temporarily. The previous state will be
|
||||||
}
|
// restored in `WindowDelegate::window_did_exit_fullscreen`.
|
||||||
|
if not_fullscreen {
|
||||||
extern "C" fn restore_display_mode_callback(screen: *mut c_void) {
|
let curr_mask = ns_window.styleMask();
|
||||||
unsafe {
|
let required =
|
||||||
let screen = Box::from_raw(screen as *mut u32);
|
NSWindowStyleMask::NSTitledWindowMask | NSWindowStyleMask::NSResizableWindowMask;
|
||||||
ffi::CGRestorePermanentDisplayConfiguration();
|
if !curr_mask.contains(required) {
|
||||||
assert_eq!(ffi::CGDisplayRelease(*screen), ffi::kCGErrorSuccess);
|
set_style_mask(*ns_window, *ns_view, required);
|
||||||
}
|
if let Some(shared_state) = shared_state.upgrade() {
|
||||||
}
|
trace!("Locked shared state in `toggle_full_screen_callback`");
|
||||||
pub unsafe fn restore_display_mode_async(ns_screen: u32) {
|
let mut shared_state_lock = shared_state.lock().unwrap();
|
||||||
dispatch_async_f(
|
(*shared_state_lock).saved_style = Some(curr_mask);
|
||||||
dispatch_get_main_queue(),
|
trace!("Unlocked shared state in `toggle_full_screen_callback`");
|
||||||
Box::into_raw(Box::new(ns_screen)) as *mut _,
|
|
||||||
restore_display_mode_callback,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SetMaximizedData {
|
|
||||||
ns_window: id,
|
|
||||||
is_zoomed: bool,
|
|
||||||
maximized: bool,
|
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
|
||||||
}
|
|
||||||
impl SetMaximizedData {
|
|
||||||
fn new_ptr(
|
|
||||||
ns_window: id,
|
|
||||||
is_zoomed: bool,
|
|
||||||
maximized: bool,
|
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
|
||||||
) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetMaximizedData {
|
|
||||||
ns_window,
|
|
||||||
is_zoomed,
|
|
||||||
maximized,
|
|
||||||
shared_state,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn set_maximized_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut SetMaximizedData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
|
|
||||||
if let Some(shared_state) = context.shared_state.upgrade() {
|
|
||||||
trace!("Locked shared state in `set_maximized`");
|
|
||||||
let mut shared_state_lock = shared_state.lock().unwrap();
|
|
||||||
|
|
||||||
// Save the standard frame sized if it is not zoomed
|
|
||||||
if !context.is_zoomed {
|
|
||||||
shared_state_lock.standard_frame = Some(NSWindow::frame(context.ns_window));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_state_lock.maximized = context.maximized;
|
|
||||||
|
|
||||||
let curr_mask = context.ns_window.styleMask();
|
|
||||||
if shared_state_lock.fullscreen.is_some() {
|
|
||||||
// Handle it in window_did_exit_fullscreen
|
|
||||||
return;
|
|
||||||
} else if curr_mask.contains(NSWindowStyleMask::NSResizableWindowMask) {
|
|
||||||
// Just use the native zoom if resizable
|
|
||||||
context.ns_window.zoom_(nil);
|
|
||||||
} else {
|
|
||||||
// if it's not resizable, we set the frame directly
|
|
||||||
let new_rect = if context.maximized {
|
|
||||||
let screen = NSScreen::mainScreen(nil);
|
|
||||||
NSScreen::visibleFrame(screen)
|
|
||||||
} else {
|
|
||||||
shared_state_lock.saved_standard_frame()
|
|
||||||
};
|
|
||||||
context.ns_window.setFrame_display_(new_rect, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("Unlocked shared state in `set_maximized`");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box::from_raw(context_ptr);
|
// Window level must be restored from `CGShieldingWindowLevel()
|
||||||
}
|
// + 1` back to normal in order for `toggleFullScreen` to do
|
||||||
|
// anything
|
||||||
|
ns_window.setLevel_(0);
|
||||||
|
ns_window.toggleFullScreen_(nil);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn restore_display_mode_async(ns_screen: u32) {
|
||||||
|
Queue::main().exec_async(move || {
|
||||||
|
ffi::CGRestorePermanentDisplayConfiguration();
|
||||||
|
assert_eq!(ffi::CGDisplayRelease(ns_screen), ffi::kCGErrorSuccess);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// `setMaximized` is not thread-safe
|
// `setMaximized` is not thread-safe
|
||||||
pub unsafe fn set_maximized_async(
|
pub unsafe fn set_maximized_async(
|
||||||
ns_window: id,
|
ns_window: id,
|
||||||
|
@ -319,127 +138,79 @@ pub unsafe fn set_maximized_async(
|
||||||
maximized: bool,
|
maximized: bool,
|
||||||
shared_state: Weak<Mutex<SharedState>>,
|
shared_state: Weak<Mutex<SharedState>>,
|
||||||
) {
|
) {
|
||||||
let context = SetMaximizedData::new_ptr(ns_window, is_zoomed, maximized, shared_state);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
let shared_state = MainThreadSafe(shared_state);
|
||||||
dispatch_get_main_queue(),
|
Queue::main().exec_async(move || {
|
||||||
context as *mut _,
|
if let Some(shared_state) = shared_state.upgrade() {
|
||||||
set_maximized_callback,
|
trace!("Locked shared state in `set_maximized`");
|
||||||
);
|
let mut shared_state_lock = shared_state.lock().unwrap();
|
||||||
|
|
||||||
|
// Save the standard frame sized if it is not zoomed
|
||||||
|
if !is_zoomed {
|
||||||
|
shared_state_lock.standard_frame = Some(NSWindow::frame(*ns_window));
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_state_lock.maximized = maximized;
|
||||||
|
|
||||||
|
let curr_mask = ns_window.styleMask();
|
||||||
|
if shared_state_lock.fullscreen.is_some() {
|
||||||
|
// Handle it in window_did_exit_fullscreen
|
||||||
|
return;
|
||||||
|
} else if curr_mask.contains(NSWindowStyleMask::NSResizableWindowMask) {
|
||||||
|
// Just use the native zoom if resizable
|
||||||
|
ns_window.zoom_(nil);
|
||||||
|
} else {
|
||||||
|
// if it's not resizable, we set the frame directly
|
||||||
|
let new_rect = if maximized {
|
||||||
|
let screen = NSScreen::mainScreen(nil);
|
||||||
|
NSScreen::visibleFrame(screen)
|
||||||
|
} else {
|
||||||
|
shared_state_lock.saved_standard_frame()
|
||||||
|
};
|
||||||
|
ns_window.setFrame_display_(new_rect, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!("Unlocked shared state in `set_maximized`");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrderOutData {
|
|
||||||
ns_window: id,
|
|
||||||
}
|
|
||||||
impl OrderOutData {
|
|
||||||
fn new_ptr(ns_window: id) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(OrderOutData { ns_window }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn order_out_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut OrderOutData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
context.ns_window.orderOut_(nil);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `orderOut:` isn't thread-safe. Calling it from another thread actually works,
|
// `orderOut:` isn't thread-safe. Calling it from another thread actually works,
|
||||||
// but with an odd delay.
|
// but with an odd delay.
|
||||||
pub unsafe fn order_out_async(ns_window: id) {
|
pub unsafe fn order_out_async(ns_window: id) {
|
||||||
let context = OrderOutData::new_ptr(ns_window);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
Queue::main().exec_async(move || {
|
||||||
dispatch_get_main_queue(),
|
ns_window.orderOut_(nil);
|
||||||
context as *mut _,
|
});
|
||||||
order_out_callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MakeKeyAndOrderFrontData {
|
|
||||||
ns_window: id,
|
|
||||||
}
|
|
||||||
impl MakeKeyAndOrderFrontData {
|
|
||||||
fn new_ptr(ns_window: id) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(MakeKeyAndOrderFrontData { ns_window }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn make_key_and_order_front_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut MakeKeyAndOrderFrontData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
context.ns_window.makeKeyAndOrderFront_(nil);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `makeKeyAndOrderFront:` isn't thread-safe. Calling it from another thread
|
// `makeKeyAndOrderFront:` isn't thread-safe. Calling it from another thread
|
||||||
// actually works, but with an odd delay.
|
// actually works, but with an odd delay.
|
||||||
pub unsafe fn make_key_and_order_front_async(ns_window: id) {
|
pub unsafe fn make_key_and_order_front_async(ns_window: id) {
|
||||||
let context = MakeKeyAndOrderFrontData::new_ptr(ns_window);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
Queue::main().exec_async(move || {
|
||||||
dispatch_get_main_queue(),
|
ns_window.makeKeyAndOrderFront_(nil);
|
||||||
context as *mut _,
|
});
|
||||||
make_key_and_order_front_callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SetTitleData {
|
|
||||||
ns_window: id,
|
|
||||||
title: String,
|
|
||||||
}
|
|
||||||
impl SetTitleData {
|
|
||||||
fn new_ptr(ns_window: id, title: String) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(SetTitleData { ns_window, title }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn set_title_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut SetTitleData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
let title = IdRef::new(NSString::alloc(nil).init_str(&context.title));
|
|
||||||
context.ns_window.setTitle_(*title);
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `setTitle:` isn't thread-safe. Calling it from another thread invalidates the
|
// `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
|
// window drag regions, which throws an exception when not done in the main
|
||||||
// thread
|
// thread
|
||||||
pub unsafe fn set_title_async(ns_window: id, title: String) {
|
pub unsafe fn set_title_async(ns_window: id, title: String) {
|
||||||
let context = SetTitleData::new_ptr(ns_window, title);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(
|
Queue::main().exec_async(move || {
|
||||||
dispatch_get_main_queue(),
|
let title = IdRef::new(NSString::alloc(nil).init_str(&title));
|
||||||
context as *mut _,
|
ns_window.setTitle_(*title);
|
||||||
set_title_callback,
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CloseData {
|
|
||||||
ns_window: id,
|
|
||||||
}
|
|
||||||
impl CloseData {
|
|
||||||
fn new_ptr(ns_window: id) -> *mut Self {
|
|
||||||
Box::into_raw(Box::new(CloseData { ns_window }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extern "C" fn close_callback(context: *mut c_void) {
|
|
||||||
unsafe {
|
|
||||||
let context_ptr = context as *mut CloseData;
|
|
||||||
{
|
|
||||||
let context = &*context_ptr;
|
|
||||||
let pool = NSAutoreleasePool::new(nil);
|
|
||||||
context.ns_window.close();
|
|
||||||
pool.drain();
|
|
||||||
}
|
|
||||||
Box::from_raw(context_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `close:` is thread-safe, but we want the event to be triggered from the main
|
// `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...
|
// thread. Though, it's a good idea to look into that more...
|
||||||
pub unsafe fn close_async(ns_window: id) {
|
pub unsafe fn close_async(ns_window: id) {
|
||||||
let context = CloseData::new_ptr(ns_window);
|
let ns_window = MainThreadSafe(ns_window);
|
||||||
dispatch_async_f(dispatch_get_main_queue(), context as *mut _, close_callback);
|
Queue::main().exec_async(move || {
|
||||||
|
autoreleasepool(move || {
|
||||||
|
ns_window.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue