mirror of
https://github.com/rust-windowing/winit.git
synced 2026-08-29 04:40:04 -04:00
chore: update to objc2 frameworks v0.3.2
This commit is contained in:
committed by
Kirill Chibisov
parent
d815bc089c
commit
b811e9d878
12
Cargo.toml
12
Cargo.toml
@@ -55,12 +55,12 @@ ndk = { version = "0.9.0", features = ["rwh_06"], default-features = false }
|
|||||||
block2 = "0.6.1"
|
block2 = "0.6.1"
|
||||||
dispatch2 = { version = "0.3.0", default-features = false, features = ["std", "objc2"] }
|
dispatch2 = { version = "0.3.0", default-features = false, features = ["std", "objc2"] }
|
||||||
objc2 = { version = "0.6.1", features = ["relax-sign-encoding"] }
|
objc2 = { version = "0.6.1", features = ["relax-sign-encoding"] }
|
||||||
objc2-app-kit = { version = "0.3.1", default-features = false }
|
objc2-app-kit = { version = "0.3.2", default-features = false }
|
||||||
objc2-core-foundation = { version = "0.3.1", default-features = false }
|
objc2-core-foundation = { version = "0.3.2", default-features = false }
|
||||||
objc2-core-graphics = { version = "0.3.1", default-features = false }
|
objc2-core-graphics = { version = "0.3.2", default-features = false }
|
||||||
objc2-core-video = { version = "0.3.1", default-features = false }
|
objc2-core-video = { version = "0.3.2", default-features = false }
|
||||||
objc2-foundation = { version = "0.3.1", default-features = false }
|
objc2-foundation = { version = "0.3.2", default-features = false }
|
||||||
objc2-ui-kit = { version = "0.3.1", default-features = false }
|
objc2-ui-kit = { version = "0.3.2", default-features = false }
|
||||||
|
|
||||||
# Windows dependencies.
|
# Windows dependencies.
|
||||||
unicode-segmentation = "1.7.1"
|
unicode-segmentation = "1.7.1"
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ extern "C-unwind" fn send_event(app: &NSApplication, sel: Sel, event: &NSEvent)
|
|||||||
// For posterity, there are some undocumented event types
|
// For posterity, there are some undocumented event types
|
||||||
// (https://github.com/servo/cocoa-rs/issues/155)
|
// (https://github.com/servo/cocoa-rs/issues/155)
|
||||||
// but that doesn't really matter here.
|
// but that doesn't really matter here.
|
||||||
let event_type = unsafe { event.r#type() };
|
let event_type = event.r#type();
|
||||||
let modifier_flags = unsafe { event.modifierFlags() };
|
let modifier_flags = event.modifierFlags();
|
||||||
if event_type == NSEventType::KeyUp && modifier_flags.contains(NSEventModifierFlags::Command) {
|
if event_type == NSEventType::KeyUp && modifier_flags.contains(NSEventModifierFlags::Command) {
|
||||||
if let Some(key_window) = app.keyWindow() {
|
if let Some(key_window) = app.keyWindow() {
|
||||||
key_window.sendEvent(event);
|
key_window.sendEvent(event);
|
||||||
@@ -98,15 +98,15 @@ pub(crate) fn override_send_event(global_app: &NSApplication) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
||||||
let event_type = unsafe { event.r#type() };
|
let event_type = event.r#type();
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
match event_type {
|
match event_type {
|
||||||
NSEventType::MouseMoved
|
NSEventType::MouseMoved
|
||||||
| NSEventType::LeftMouseDragged
|
| NSEventType::LeftMouseDragged
|
||||||
| NSEventType::OtherMouseDragged
|
| NSEventType::OtherMouseDragged
|
||||||
| NSEventType::RightMouseDragged => {
|
| NSEventType::RightMouseDragged => {
|
||||||
let delta_x = unsafe { event.deltaX() } as f64;
|
let delta_x = event.deltaX() as f64;
|
||||||
let delta_y = unsafe { event.deltaY() } as f64;
|
let delta_y = event.deltaY() as f64;
|
||||||
|
|
||||||
if delta_x != 0.0 || delta_y != 0.0 {
|
if delta_x != 0.0 || delta_y != 0.0 {
|
||||||
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||||
@@ -117,7 +117,7 @@ fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
NSEventType::LeftMouseDown | NSEventType::RightMouseDown | NSEventType::OtherMouseDown => {
|
NSEventType::LeftMouseDown | NSEventType::RightMouseDown | NSEventType::OtherMouseDown => {
|
||||||
let button = unsafe { event.buttonNumber() } as u32;
|
let button = event.buttonNumber() as u32;
|
||||||
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||||
app.device_event(event_loop, None, DeviceEvent::Button {
|
app.device_event(event_loop, None, DeviceEvent::Button {
|
||||||
button,
|
button,
|
||||||
@@ -126,7 +126,7 @@ fn maybe_dispatch_device_event(app_state: &Rc<AppState>, event: &NSEvent) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
NSEventType::LeftMouseUp | NSEventType::RightMouseUp | NSEventType::OtherMouseUp => {
|
NSEventType::LeftMouseUp | NSEventType::RightMouseUp | NSEventType::OtherMouseUp => {
|
||||||
let button = unsafe { event.buttonNumber() } as u32;
|
let button = event.buttonNumber() as u32;
|
||||||
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
app_state.maybe_queue_with_handler(move |app, event_loop| {
|
||||||
app.device_event(event_loop, None, DeviceEvent::Button {
|
app.device_event(event_loop, None, DeviceEvent::Button {
|
||||||
button,
|
button,
|
||||||
@@ -153,16 +153,14 @@ mod tests {
|
|||||||
let Some(mtm) = MainThreadMarker::new() else { return };
|
let Some(mtm) = MainThreadMarker::new() else { return };
|
||||||
|
|
||||||
// Create a new application, without making it the shared application.
|
// Create a new application, without making it the shared application.
|
||||||
let app = unsafe { NSApplication::new(mtm) };
|
let app = NSApplication::new(mtm);
|
||||||
override_send_event(&app);
|
override_send_event(&app);
|
||||||
// Test calling twice works.
|
// Test calling twice works.
|
||||||
override_send_event(&app);
|
override_send_event(&app);
|
||||||
|
|
||||||
// FIXME(madsmtm): Can't test this yet, need some way to mock AppState.
|
// FIXME(madsmtm): Can't test this yet, need some way to mock AppState.
|
||||||
// unsafe {
|
// let event = super::super::event::dummy_event().unwrap();
|
||||||
// let event = super::super::event::dummy_event().unwrap();
|
// app.sendEvent(&event)
|
||||||
// app.sendEvent(&event)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ impl AppState {
|
|||||||
// - https://github.com/rust-windowing/winit/issues/261
|
// - https://github.com/rust-windowing/winit/issues/261
|
||||||
// - https://github.com/rust-windowing/winit/issues/3958
|
// - https://github.com/rust-windowing/winit/issues/3958
|
||||||
let is_bundled =
|
let is_bundled =
|
||||||
unsafe { NSRunningApplication::currentApplication().bundleIdentifier().is_some() };
|
NSRunningApplication::currentApplication().bundleIdentifier().is_some();
|
||||||
if !is_bundled {
|
if !is_bundled {
|
||||||
app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
|
app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,10 +62,8 @@ pub(crate) fn cursor_from_image(cursor: &CursorImage) -> Result<Retained<NSCurso
|
|||||||
unsafe { slice::from_raw_parts_mut(bitmap.bitmapData(), cursor.buffer().len()) };
|
unsafe { slice::from_raw_parts_mut(bitmap.bitmapData(), cursor.buffer().len()) };
|
||||||
bitmap_data.copy_from_slice(cursor.buffer());
|
bitmap_data.copy_from_slice(cursor.buffer());
|
||||||
|
|
||||||
let image = unsafe {
|
let image = NSImage::initWithSize(NSImage::alloc(), NSSize::new(width.into(), height.into()));
|
||||||
NSImage::initWithSize(NSImage::alloc(), NSSize::new(width.into(), height.into()))
|
image.addRepresentation(&bitmap);
|
||||||
};
|
|
||||||
unsafe { image.addRepresentation(&bitmap) };
|
|
||||||
|
|
||||||
let hotspot = NSPoint::new(cursor.hotspot_x() as f64, cursor.hotspot_y() as f64);
|
let hotspot = NSPoint::new(cursor.hotspot_x() as f64, cursor.hotspot_y() as f64);
|
||||||
|
|
||||||
@@ -140,12 +138,9 @@ unsafe fn load_webkit_cursor(name: &NSString) -> Retained<NSCursor> {
|
|||||||
|
|
||||||
// TODO: Handle PLists better
|
// TODO: Handle PLists better
|
||||||
let info_path = cursor_path.stringByAppendingPathComponent(ns_string!("info.plist"));
|
let info_path = cursor_path.stringByAppendingPathComponent(ns_string!("info.plist"));
|
||||||
let info: Retained<NSDictionary<NSObject, NSObject>> = unsafe {
|
#[allow(deprecated)]
|
||||||
msg_send![
|
let info: Retained<NSDictionary<NSObject, NSObject>> =
|
||||||
<NSDictionary<NSObject, NSObject>>::class(),
|
unsafe { NSDictionary::dictionaryWithContentsOfFile(&info_path) }.unwrap();
|
||||||
dictionaryWithContentsOfFile: &*info_path,
|
|
||||||
]
|
|
||||||
};
|
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
if let Some(n) = info.objectForKey(ns_string!("hotx")) {
|
if let Some(n) = info.objectForKey(ns_string!("hotx")) {
|
||||||
if let Ok(n) = n.downcast::<NSNumber>() {
|
if let Ok(n) = n.downcast::<NSNumber>() {
|
||||||
@@ -216,9 +211,9 @@ pub(crate) fn cursor_from_icon(icon: CursorIcon) -> Retained<NSCursor> {
|
|||||||
CursorIcon::EwResize | CursorIcon::ColResize => NSCursor::resizeLeftRightCursor(),
|
CursorIcon::EwResize | CursorIcon::ColResize => NSCursor::resizeLeftRightCursor(),
|
||||||
CursorIcon::NsResize | CursorIcon::RowResize => NSCursor::resizeUpDownCursor(),
|
CursorIcon::NsResize | CursorIcon::RowResize => NSCursor::resizeUpDownCursor(),
|
||||||
CursorIcon::Help => _helpCursor(),
|
CursorIcon::Help => _helpCursor(),
|
||||||
CursorIcon::ZoomIn if available!(macos = 15.0) => unsafe { NSCursor::zoomInCursor() },
|
CursorIcon::ZoomIn if available!(macos = 15.0) => NSCursor::zoomInCursor(),
|
||||||
CursorIcon::ZoomIn => _zoomInCursor(),
|
CursorIcon::ZoomIn => _zoomInCursor(),
|
||||||
CursorIcon::ZoomOut if available!(macos = 15.0) => unsafe { NSCursor::zoomOutCursor() },
|
CursorIcon::ZoomOut if available!(macos = 15.0) => NSCursor::zoomOutCursor(),
|
||||||
CursorIcon::ZoomOut => _zoomOutCursor(),
|
CursorIcon::ZoomOut => _zoomOutCursor(),
|
||||||
CursorIcon::NeResize => _windowResizeNorthEastCursor(),
|
CursorIcon::NeResize => _windowResizeNorthEastCursor(),
|
||||||
CursorIcon::NwResize => _windowResizeNorthWestCursor(),
|
CursorIcon::NwResize => _windowResizeNorthWestCursor(),
|
||||||
|
|||||||
@@ -67,9 +67,7 @@ pub fn get_modifierless_char(scancode: u16) -> Key {
|
|||||||
|
|
||||||
// Ignores all modifiers except for SHIFT (yes, even ALT is ignored).
|
// Ignores all modifiers except for SHIFT (yes, even ALT is ignored).
|
||||||
fn get_logical_key_char(ns_event: &NSEvent, modifierless_chars: &str) -> Key {
|
fn get_logical_key_char(ns_event: &NSEvent, modifierless_chars: &str) -> Key {
|
||||||
let string = unsafe { ns_event.charactersIgnoringModifiers() }
|
let string = ns_event.charactersIgnoringModifiers().map(|s| s.to_string()).unwrap_or_default();
|
||||||
.map(|s| s.to_string())
|
|
||||||
.unwrap_or_default();
|
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
// Probably a dead key
|
// Probably a dead key
|
||||||
let first_char = modifierless_chars.chars().next();
|
let first_char = modifierless_chars.chars().next();
|
||||||
@@ -85,7 +83,7 @@ pub(crate) fn create_key_event(ns_event: &NSEvent, is_press: bool, is_repeat: bo
|
|||||||
use ElementState::{Pressed, Released};
|
use ElementState::{Pressed, Released};
|
||||||
let state = if is_press { Pressed } else { Released };
|
let state = if is_press { Pressed } else { Released };
|
||||||
|
|
||||||
let scancode = unsafe { ns_event.keyCode() };
|
let scancode = ns_event.keyCode();
|
||||||
let mut physical_key = scancode_to_physicalkey(scancode as u32);
|
let mut physical_key = scancode_to_physicalkey(scancode as u32);
|
||||||
|
|
||||||
// NOTE: The logical key should heed both SHIFT and ALT if possible.
|
// NOTE: The logical key should heed both SHIFT and ALT if possible.
|
||||||
@@ -95,7 +93,7 @@ pub(crate) fn create_key_event(ns_event: &NSEvent, is_press: bool, is_repeat: bo
|
|||||||
// * Pressing CTRL SHIFT A: logical key should also be "A"
|
// * Pressing CTRL SHIFT A: logical key should also be "A"
|
||||||
// This is not easy to tease out of `NSEvent`, but we do our best.
|
// This is not easy to tease out of `NSEvent`, but we do our best.
|
||||||
|
|
||||||
let characters = unsafe { ns_event.characters() }.map(|s| s.to_string()).unwrap_or_default();
|
let characters = ns_event.characters().map(|s| s.to_string()).unwrap_or_default();
|
||||||
let text_with_all_modifiers = if characters.is_empty() {
|
let text_with_all_modifiers = if characters.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -111,7 +109,7 @@ pub(crate) fn create_key_event(ns_event: &NSEvent, is_press: bool, is_repeat: bo
|
|||||||
// `get_modifierless_char/key_without_modifiers` ignores ALL modifiers.
|
// `get_modifierless_char/key_without_modifiers` ignores ALL modifiers.
|
||||||
let key_without_modifiers = get_modifierless_char(scancode);
|
let key_without_modifiers = get_modifierless_char(scancode);
|
||||||
|
|
||||||
let modifiers = unsafe { ns_event.modifierFlags() };
|
let modifiers = ns_event.modifierFlags();
|
||||||
let has_ctrl = modifiers.contains(NSEventModifierFlags::Control);
|
let has_ctrl = modifiers.contains(NSEventModifierFlags::Control);
|
||||||
let has_cmd = modifiers.contains(NSEventModifierFlags::Command);
|
let has_cmd = modifiers.contains(NSEventModifierFlags::Command);
|
||||||
|
|
||||||
@@ -302,15 +300,15 @@ const NX_DEVICERALTKEYMASK: NSEventModifierFlags = NSEventModifierFlags(0x000000
|
|||||||
const NX_DEVICERCTLKEYMASK: NSEventModifierFlags = NSEventModifierFlags(0x00002000);
|
const NX_DEVICERCTLKEYMASK: NSEventModifierFlags = NSEventModifierFlags(0x00002000);
|
||||||
|
|
||||||
pub(super) fn lalt_pressed(event: &NSEvent) -> bool {
|
pub(super) fn lalt_pressed(event: &NSEvent) -> bool {
|
||||||
unsafe { event.modifierFlags() }.contains(NX_DEVICELALTKEYMASK)
|
event.modifierFlags().contains(NX_DEVICELALTKEYMASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ralt_pressed(event: &NSEvent) -> bool {
|
pub(super) fn ralt_pressed(event: &NSEvent) -> bool {
|
||||||
unsafe { event.modifierFlags() }.contains(NX_DEVICERALTKEYMASK)
|
event.modifierFlags().contains(NX_DEVICERALTKEYMASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn event_mods(event: &NSEvent) -> Modifiers {
|
pub(super) fn event_mods(event: &NSEvent) -> Modifiers {
|
||||||
let flags = unsafe { event.modifierFlags() };
|
let flags = event.modifierFlags();
|
||||||
let mut state = ModifiersState::empty();
|
let mut state = ModifiersState::empty();
|
||||||
let mut pressed_mods = ModifiersKeys::empty();
|
let mut pressed_mods = ModifiersKeys::empty();
|
||||||
|
|
||||||
@@ -334,8 +332,7 @@ pub(super) fn event_mods(event: &NSEvent) -> Modifiers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn dummy_event() -> Option<Retained<NSEvent>> {
|
pub(super) fn dummy_event() -> Option<Retained<NSEvent>> {
|
||||||
unsafe {
|
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2(
|
||||||
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2(
|
|
||||||
NSEventType::ApplicationDefined,
|
NSEventType::ApplicationDefined,
|
||||||
NSPoint::new(0.0, 0.0),
|
NSPoint::new(0.0, 0.0),
|
||||||
NSEventModifierFlags(0),
|
NSEventModifierFlags(0),
|
||||||
@@ -346,7 +343,6 @@ pub(super) fn dummy_event() -> Option<Retained<NSEvent>> {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
|
pub fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ impl EventLoop {
|
|||||||
// Override `sendEvent:` on the application to forward to our application state.
|
// Override `sendEvent:` on the application to forward to our application state.
|
||||||
override_send_event(&app);
|
override_send_event(&app);
|
||||||
|
|
||||||
let center = unsafe { NSNotificationCenter::defaultCenter() };
|
let center = NSNotificationCenter::defaultCenter();
|
||||||
|
|
||||||
let weak_app_state = Rc::downgrade(&app_state);
|
let weak_app_state = Rc::downgrade(&app_state);
|
||||||
let _did_finish_launching_observer = create_observer(
|
let _did_finish_launching_observer = create_observer(
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ pub fn initialize(app: &NSApplication) {
|
|||||||
app_menu.addItem(&quit_item);
|
app_menu.addItem(&quit_item);
|
||||||
app_menu_item.setSubmenu(Some(&app_menu));
|
app_menu_item.setSubmenu(Some(&app_menu));
|
||||||
|
|
||||||
unsafe { app.setServicesMenu(Some(&services_menu)) };
|
app.setServicesMenu(Some(&services_menu));
|
||||||
app.setMainMenu(Some(&menubar));
|
app.setMainMenu(Some(&menubar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,35 +65,33 @@ impl VideoModeHandle {
|
|||||||
native_mode: NativeDisplayMode,
|
native_mode: NativeDisplayMode,
|
||||||
refresh_rate_millihertz: Option<NonZeroU32>,
|
refresh_rate_millihertz: Option<NonZeroU32>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
unsafe {
|
// The bit-depth is basically always 32 since macOS 10.12.
|
||||||
// The bit-depth is basically always 32 since macOS 10.12.
|
#[allow(deprecated)]
|
||||||
#[allow(deprecated)]
|
let pixel_encoding =
|
||||||
let pixel_encoding =
|
CGDisplayMode::pixel_encoding(Some(&native_mode.0)).unwrap().to_string();
|
||||||
CGDisplayMode::pixel_encoding(Some(&native_mode.0)).unwrap().to_string();
|
let bit_depth = if pixel_encoding.eq_ignore_ascii_case(ffi::IO32BitDirectPixels) {
|
||||||
let bit_depth = if pixel_encoding.eq_ignore_ascii_case(ffi::IO32BitDirectPixels) {
|
NonZeroU16::new(32)
|
||||||
NonZeroU16::new(32)
|
} else if pixel_encoding.eq_ignore_ascii_case(ffi::IO16BitDirectPixels) {
|
||||||
} else if pixel_encoding.eq_ignore_ascii_case(ffi::IO16BitDirectPixels) {
|
NonZeroU16::new(16)
|
||||||
NonZeroU16::new(16)
|
} else if pixel_encoding.eq_ignore_ascii_case(ffi::kIO30BitDirectPixels) {
|
||||||
} else if pixel_encoding.eq_ignore_ascii_case(ffi::kIO30BitDirectPixels) {
|
NonZeroU16::new(30)
|
||||||
NonZeroU16::new(30)
|
} else if pixel_encoding.eq_ignore_ascii_case(ffi::kIO64BitDirectPixels) {
|
||||||
} else if pixel_encoding.eq_ignore_ascii_case(ffi::kIO64BitDirectPixels) {
|
NonZeroU16::new(64)
|
||||||
NonZeroU16::new(64)
|
} else {
|
||||||
} else {
|
warn!(?pixel_encoding, "unknown bit depth");
|
||||||
warn!(?pixel_encoding, "unknown bit depth");
|
None
|
||||||
None
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let mode = VideoMode::new(
|
let mode = VideoMode::new(
|
||||||
PhysicalSize::new(
|
PhysicalSize::new(
|
||||||
CGDisplayMode::pixel_width(Some(&native_mode.0)) as u32,
|
CGDisplayMode::pixel_width(Some(&native_mode.0)) as u32,
|
||||||
CGDisplayMode::pixel_height(Some(&native_mode.0)) as u32,
|
CGDisplayMode::pixel_height(Some(&native_mode.0)) as u32,
|
||||||
),
|
),
|
||||||
bit_depth,
|
bit_depth,
|
||||||
refresh_rate_millihertz,
|
refresh_rate_millihertz,
|
||||||
);
|
);
|
||||||
|
|
||||||
VideoModeHandle { mode, monitor: monitor.clone(), native_mode }
|
Self { mode, monitor: monitor.clone(), native_mode }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +135,7 @@ impl MonitorHandle {
|
|||||||
|
|
||||||
fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||||
let current_display_mode =
|
let current_display_mode =
|
||||||
NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.display_id()) }.unwrap());
|
NativeDisplayMode(CGDisplayCopyDisplayMode(self.display_id()).unwrap());
|
||||||
refresh_rate_millihertz(self.display_id(), ¤t_display_mode)
|
refresh_rate_millihertz(self.display_id(), ¤t_display_mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +157,7 @@ impl MonitorHandle {
|
|||||||
};
|
};
|
||||||
|
|
||||||
modes.into_iter().map(move |mode| {
|
modes.into_iter().map(move |mode| {
|
||||||
let cg_refresh_rate_hertz = unsafe { CGDisplayMode::refresh_rate(Some(&mode)) };
|
let cg_refresh_rate_hertz = CGDisplayMode::refresh_rate(Some(&mode));
|
||||||
|
|
||||||
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
|
// CGDisplayModeGetRefreshRate returns 0.0 for any display that
|
||||||
// isn't a CRT
|
// isn't a CRT
|
||||||
@@ -202,7 +200,7 @@ impl MonitorHandleProvider for MonitorHandle {
|
|||||||
//
|
//
|
||||||
// <https://github.com/glfw/glfw/blob/57cbded0760a50b9039ee0cb3f3c14f60145567c/src/cocoa_monitor.m#L44-L126>
|
// <https://github.com/glfw/glfw/blob/57cbded0760a50b9039ee0cb3f3c14f60145567c/src/cocoa_monitor.m#L44-L126>
|
||||||
fn name(&self) -> Option<std::borrow::Cow<'_, str>> {
|
fn name(&self) -> Option<std::borrow::Cow<'_, str>> {
|
||||||
let screen_num = unsafe { CGDisplayModelNumber(self.display_id()) };
|
let screen_num = CGDisplayModelNumber(self.display_id());
|
||||||
Some(format!("Monitor #{screen_num}").into())
|
Some(format!("Monitor #{screen_num}").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +208,7 @@ impl MonitorHandleProvider for MonitorHandle {
|
|||||||
// This is already in screen coordinates. If we were using `NSScreen`,
|
// This is already in screen coordinates. If we were using `NSScreen`,
|
||||||
// then a conversion would've been needed:
|
// then a conversion would've been needed:
|
||||||
// flip_window_screen_coordinates(self.ns_screen(mtm)?.frame())
|
// flip_window_screen_coordinates(self.ns_screen(mtm)?.frame())
|
||||||
let bounds = unsafe { CGDisplayBounds(self.display_id()) };
|
let bounds = CGDisplayBounds(self.display_id());
|
||||||
let position = LogicalPosition::new(bounds.origin.x, bounds.origin.y);
|
let position = LogicalPosition::new(bounds.origin.x, bounds.origin.y);
|
||||||
Some(position.to_physical(self.scale_factor()))
|
Some(position.to_physical(self.scale_factor()))
|
||||||
}
|
}
|
||||||
@@ -225,8 +223,7 @@ impl MonitorHandleProvider for MonitorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn current_video_mode(&self) -> Option<VideoMode> {
|
fn current_video_mode(&self) -> Option<VideoMode> {
|
||||||
let mode =
|
let mode = NativeDisplayMode(CGDisplayCopyDisplayMode(self.display_id()).unwrap());
|
||||||
NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.display_id()) }.unwrap());
|
|
||||||
let refresh_rate_millihertz = refresh_rate_millihertz(self.display_id(), &mode);
|
let refresh_rate_millihertz = refresh_rate_millihertz(self.display_id(), &mode);
|
||||||
Some(VideoModeHandle::new(self.clone(), mode, refresh_rate_millihertz).mode)
|
Some(VideoModeHandle::new(self.clone(), mode, refresh_rate_millihertz).mode)
|
||||||
}
|
}
|
||||||
@@ -264,7 +261,7 @@ pub fn available_monitors() -> VecDeque<MonitorHandle> {
|
|||||||
|
|
||||||
pub fn primary_monitor() -> MonitorHandle {
|
pub fn primary_monitor() -> MonitorHandle {
|
||||||
// Display ID just fetched from `CGMainDisplayID`, should be fine to unwrap.
|
// Display ID just fetched from `CGMainDisplayID`, should be fine to unwrap.
|
||||||
MonitorHandle::new(unsafe { CGMainDisplayID() }).expect("invalid display ID")
|
MonitorHandle::new(CGMainDisplayID()).expect("invalid display ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for MonitorHandle {
|
impl fmt::Debug for MonitorHandle {
|
||||||
@@ -315,40 +312,38 @@ pub(crate) fn flip_window_screen_coordinates(frame: NSRect) -> NSPoint {
|
|||||||
// It is intentional that we use `CGMainDisplayID` (as opposed to
|
// It is intentional that we use `CGMainDisplayID` (as opposed to
|
||||||
// `NSScreen::mainScreen`), because that's what the screen coordinates
|
// `NSScreen::mainScreen`), because that's what the screen coordinates
|
||||||
// are relative to, no matter which display the window is currently on.
|
// are relative to, no matter which display the window is currently on.
|
||||||
let main_screen_height = unsafe { CGDisplayBounds(CGMainDisplayID()) }.size.height;
|
let main_screen_height = CGDisplayBounds(CGMainDisplayID()).size.height;
|
||||||
|
|
||||||
let y = main_screen_height - frame.size.height - frame.origin.y;
|
let y = main_screen_height - frame.size.height - frame.origin.y;
|
||||||
NSPoint::new(frame.origin.x, y)
|
NSPoint::new(frame.origin.x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> Option<NonZeroU32> {
|
fn refresh_rate_millihertz(id: CGDirectDisplayID, mode: &NativeDisplayMode) -> Option<NonZeroU32> {
|
||||||
unsafe {
|
let refresh_rate = CGDisplayMode::refresh_rate(Some(&mode.0));
|
||||||
let refresh_rate = CGDisplayMode::refresh_rate(Some(&mode.0));
|
if refresh_rate > 0.0 {
|
||||||
if refresh_rate > 0.0 {
|
return NonZeroU32::new((refresh_rate * 1000.0).round() as u32);
|
||||||
return NonZeroU32::new((refresh_rate * 1000.0).round() as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut display_link = std::ptr::null_mut();
|
|
||||||
#[allow(deprecated)]
|
|
||||||
if CVDisplayLink::create_with_cg_display(id, NonNull::from(&mut display_link))
|
|
||||||
!= kCVReturnSuccess
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let display_link = CFRetained::from_raw(NonNull::new(display_link).unwrap());
|
|
||||||
#[allow(deprecated)]
|
|
||||||
let time = display_link.nominal_output_video_refresh_period();
|
|
||||||
|
|
||||||
// This value is indefinite if an invalid display link was specified
|
|
||||||
if time.flags & CVTimeFlags::IsIndefinite.0 != 0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
(time.timeScale as i64)
|
|
||||||
.checked_div(time.timeValue)
|
|
||||||
.map(|v| (v * 1000) as u32)
|
|
||||||
.and_then(NonZeroU32::new)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut display_link = std::ptr::null_mut();
|
||||||
|
#[allow(deprecated)]
|
||||||
|
if unsafe { CVDisplayLink::create_with_cg_display(id, NonNull::from(&mut display_link)) }
|
||||||
|
!= kCVReturnSuccess
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let display_link = unsafe { CFRetained::from_raw(NonNull::new(display_link).unwrap()) };
|
||||||
|
#[allow(deprecated)]
|
||||||
|
let time = display_link.nominal_output_video_refresh_period();
|
||||||
|
|
||||||
|
// This value is indefinite if an invalid display link was specified
|
||||||
|
if time.flags & CVTimeFlags::IsIndefinite.0 != 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
(time.timeScale as i64)
|
||||||
|
.checked_div(time.timeValue)
|
||||||
|
.map(|v| (v * 1000) as u32)
|
||||||
|
.and_then(NonZeroU32::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -395,7 +390,7 @@ mod tests {
|
|||||||
// Assertion failed: (did_initialize), function CGS_REQUIRE_INIT, file CGInitialization.c, line 44.
|
// Assertion failed: (did_initialize), function CGS_REQUIRE_INIT, file CGInitialization.c, line 44.
|
||||||
// ```
|
// ```
|
||||||
// See https://github.com/JXA-Cookbook/JXA-Cookbook/issues/27#issuecomment-277517668
|
// See https://github.com/JXA-Cookbook/JXA-Cookbook/issues/27#issuecomment-277517668
|
||||||
let _ = unsafe { CGMainDisplayID() };
|
let _ = CGMainDisplayID();
|
||||||
|
|
||||||
let handle = MonitorHandle(CFUUID::new(None).unwrap());
|
let handle = MonitorHandle(CFUUID::new(None).unwrap());
|
||||||
assert_eq!(handle.display_id(), 0);
|
assert_eq!(handle.display_id(), 0);
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ define_class!(
|
|||||||
self.queue_event(WindowEvent::Ime(Ime::Enabled));
|
self.queue_event(WindowEvent::Ime(Ime::Enabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
if unsafe { self.hasMarkedText() } {
|
if self.hasMarkedText() {
|
||||||
self.ivars().ime_state.set(ImeState::Preedit);
|
self.ivars().ime_state.set(ImeState::Preedit);
|
||||||
} else {
|
} else {
|
||||||
// In case the preedit was cleared, set IME into the Ground state.
|
// In case the preedit was cleared, set IME into the Ground state.
|
||||||
@@ -305,8 +305,8 @@ define_class!(
|
|||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// Convert the selected range from UTF-16 indices to UTF-8 indices.
|
// Convert the selected range from UTF-16 indices to UTF-8 indices.
|
||||||
let sub_string_a = unsafe { string.substringToIndex(selected_range.location) };
|
let sub_string_a = string.substringToIndex(selected_range.location);
|
||||||
let sub_string_b = unsafe { string.substringToIndex(selected_range.end()) };
|
let sub_string_b = string.substringToIndex(selected_range.end());
|
||||||
let lowerbound_utf8 = sub_string_a.len();
|
let lowerbound_utf8 = sub_string_a.len();
|
||||||
let upperbound_utf8 = sub_string_b.len();
|
let upperbound_utf8 = sub_string_b.len();
|
||||||
Some((lowerbound_utf8, upperbound_utf8))
|
Some((lowerbound_utf8, upperbound_utf8))
|
||||||
@@ -391,7 +391,7 @@ define_class!(
|
|||||||
let is_control = string.chars().next().is_some_and(|c| c.is_control());
|
let is_control = string.chars().next().is_some_and(|c| c.is_control());
|
||||||
|
|
||||||
// Commit only if we have marked text.
|
// Commit only if we have marked text.
|
||||||
if unsafe { self.hasMarkedText() } && self.is_ime_enabled() && !is_control {
|
if self.hasMarkedText() && self.is_ime_enabled() && !is_control {
|
||||||
self.queue_event(WindowEvent::Ime(Ime::Preedit(String::new(), None)));
|
self.queue_event(WindowEvent::Ime(Ime::Preedit(String::new(), None)));
|
||||||
self.queue_event(WindowEvent::Ime(Ime::Commit(string)));
|
self.queue_event(WindowEvent::Ime(Ime::Commit(string)));
|
||||||
self.ivars().ime_state.set(ImeState::Committed);
|
self.ivars().ime_state.set(ImeState::Committed);
|
||||||
@@ -414,8 +414,7 @@ define_class!(
|
|||||||
|
|
||||||
self.ivars().forward_key_to_app.set(true);
|
self.ivars().forward_key_to_app.set(true);
|
||||||
|
|
||||||
if unsafe { self.hasMarkedText() } && self.ivars().ime_state.get() == ImeState::Preedit
|
if self.hasMarkedText() && self.ivars().ime_state.get() == ImeState::Preedit {
|
||||||
{
|
|
||||||
// Leave preedit so that we also report the key-up for this key.
|
// Leave preedit so that we also report the key-up for this key.
|
||||||
self.ivars().ime_state.set(ImeState::Ground);
|
self.ivars().ime_state.set(ImeState::Ground);
|
||||||
}
|
}
|
||||||
@@ -467,7 +466,7 @@ define_class!(
|
|||||||
// is not handled by IME and should be handled by the application)
|
// is not handled by IME and should be handled by the application)
|
||||||
if self.ivars().ime_capabilities.get().is_some() {
|
if self.ivars().ime_capabilities.get().is_some() {
|
||||||
let events_for_nsview = NSArray::from_slice(&[&*event]);
|
let events_for_nsview = NSArray::from_slice(&[&*event]);
|
||||||
unsafe { self.interpretKeyEvents(&events_for_nsview) };
|
self.interpretKeyEvents(&events_for_nsview);
|
||||||
|
|
||||||
// If the text was committed we must treat the next keyboard event as IME related.
|
// If the text was committed we must treat the next keyboard event as IME related.
|
||||||
if self.ivars().ime_state.get() == ImeState::Committed {
|
if self.ivars().ime_state.get() == ImeState::Committed {
|
||||||
@@ -490,7 +489,7 @@ define_class!(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !had_ime_input || self.ivars().forward_key_to_app.get() {
|
if !had_ime_input || self.ivars().forward_key_to_app.get() {
|
||||||
let key_event = create_key_event(&event, true, unsafe { event.isARepeat() });
|
let key_event = create_key_event(&event, true, event.isARepeat());
|
||||||
self.queue_event(WindowEvent::KeyboardInput {
|
self.queue_event(WindowEvent::KeyboardInput {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
event: key_event,
|
event: key_event,
|
||||||
@@ -557,7 +556,7 @@ define_class!(
|
|||||||
.expect("could not find current event");
|
.expect("could not find current event");
|
||||||
|
|
||||||
self.update_modifiers(&event, false);
|
self.update_modifiers(&event, false);
|
||||||
let event = create_key_event(&event, true, unsafe { event.isARepeat() });
|
let event = create_key_event(&event, true, event.isARepeat());
|
||||||
|
|
||||||
self.queue_event(WindowEvent::KeyboardInput {
|
self.queue_event(WindowEvent::KeyboardInput {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
@@ -676,8 +675,8 @@ define_class!(
|
|||||||
self.mouse_motion(event);
|
self.mouse_motion(event);
|
||||||
|
|
||||||
let delta = {
|
let delta = {
|
||||||
let (x, y) = unsafe { (event.scrollingDeltaX(), event.scrollingDeltaY()) };
|
let (x, y) = (event.scrollingDeltaX(), event.scrollingDeltaY());
|
||||||
if unsafe { event.hasPreciseScrollingDeltas() } {
|
if event.hasPreciseScrollingDeltas() {
|
||||||
let delta = LogicalPosition::new(x, y).to_physical(self.scale_factor());
|
let delta = LogicalPosition::new(x, y).to_physical(self.scale_factor());
|
||||||
MouseScrollDelta::PixelDelta(delta)
|
MouseScrollDelta::PixelDelta(delta)
|
||||||
} else {
|
} else {
|
||||||
@@ -690,10 +689,10 @@ define_class!(
|
|||||||
// momentum phase is recorded (or rather, the started/ended cases of the
|
// momentum phase is recorded (or rather, the started/ended cases of the
|
||||||
// momentum phase) then we report the touch phase.
|
// momentum phase) then we report the touch phase.
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
let phase = match unsafe { event.momentumPhase() } {
|
let phase = match event.momentumPhase() {
|
||||||
NSEventPhase::MayBegin | NSEventPhase::Began => TouchPhase::Started,
|
NSEventPhase::MayBegin | NSEventPhase::Began => TouchPhase::Started,
|
||||||
NSEventPhase::Ended | NSEventPhase::Cancelled => TouchPhase::Ended,
|
NSEventPhase::Ended | NSEventPhase::Cancelled => TouchPhase::Ended,
|
||||||
_ => match unsafe { event.phase() } {
|
_ => match event.phase() {
|
||||||
NSEventPhase::MayBegin | NSEventPhase::Began => TouchPhase::Started,
|
NSEventPhase::MayBegin | NSEventPhase::Began => TouchPhase::Started,
|
||||||
NSEventPhase::Ended | NSEventPhase::Cancelled => TouchPhase::Ended,
|
NSEventPhase::Ended | NSEventPhase::Cancelled => TouchPhase::Ended,
|
||||||
_ => TouchPhase::Moved,
|
_ => TouchPhase::Moved,
|
||||||
@@ -715,7 +714,7 @@ define_class!(
|
|||||||
self.mouse_motion(event);
|
self.mouse_motion(event);
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
let phase = match unsafe { event.phase() } {
|
let phase = match event.phase() {
|
||||||
NSEventPhase::Began => TouchPhase::Started,
|
NSEventPhase::Began => TouchPhase::Started,
|
||||||
NSEventPhase::Changed => TouchPhase::Moved,
|
NSEventPhase::Changed => TouchPhase::Moved,
|
||||||
NSEventPhase::Cancelled => TouchPhase::Cancelled,
|
NSEventPhase::Cancelled => TouchPhase::Cancelled,
|
||||||
@@ -725,7 +724,7 @@ define_class!(
|
|||||||
|
|
||||||
self.queue_event(WindowEvent::PinchGesture {
|
self.queue_event(WindowEvent::PinchGesture {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
delta: unsafe { event.magnification() },
|
delta: event.magnification(),
|
||||||
phase,
|
phase,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -746,7 +745,7 @@ define_class!(
|
|||||||
self.mouse_motion(event);
|
self.mouse_motion(event);
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
let phase = match unsafe { event.phase() } {
|
let phase = match event.phase() {
|
||||||
NSEventPhase::Began => TouchPhase::Started,
|
NSEventPhase::Began => TouchPhase::Started,
|
||||||
NSEventPhase::Changed => TouchPhase::Moved,
|
NSEventPhase::Changed => TouchPhase::Moved,
|
||||||
NSEventPhase::Cancelled => TouchPhase::Cancelled,
|
NSEventPhase::Cancelled => TouchPhase::Cancelled,
|
||||||
@@ -756,7 +755,7 @@ define_class!(
|
|||||||
|
|
||||||
self.queue_event(WindowEvent::RotationGesture {
|
self.queue_event(WindowEvent::RotationGesture {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
delta: unsafe { event.rotation() },
|
delta: event.rotation(),
|
||||||
phase,
|
phase,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -767,8 +766,8 @@ define_class!(
|
|||||||
|
|
||||||
self.queue_event(WindowEvent::TouchpadPressure {
|
self.queue_event(WindowEvent::TouchpadPressure {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
pressure: unsafe { event.pressure() },
|
pressure: event.pressure(),
|
||||||
stage: unsafe { event.stage() } as i64,
|
stage: event.stage() as i64,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,8 +930,8 @@ impl WinitView {
|
|||||||
// later will work though, since the flags are attached to the event and contain valid
|
// later will work though, since the flags are attached to the event and contain valid
|
||||||
// information.
|
// information.
|
||||||
'send_event: {
|
'send_event: {
|
||||||
if is_flags_changed_event && unsafe { ns_event.keyCode() } != 0 {
|
if is_flags_changed_event && ns_event.keyCode() != 0 {
|
||||||
let scancode = unsafe { ns_event.keyCode() };
|
let scancode = ns_event.keyCode();
|
||||||
let physical_key = scancode_to_physicalkey(scancode as u32);
|
let physical_key = scancode_to_physicalkey(scancode as u32);
|
||||||
|
|
||||||
let logical_key = code_to_key(physical_key, scancode);
|
let logical_key = code_to_key(physical_key, scancode);
|
||||||
@@ -1064,7 +1063,7 @@ impl WinitView {
|
|||||||
|| view_point.x > frame.size.width
|
|| view_point.x > frame.size.width
|
||||||
|| view_point.y > frame.size.height
|
|| view_point.y > frame.size.height
|
||||||
{
|
{
|
||||||
let mouse_buttons_down = unsafe { NSEvent::pressedMouseButtons() };
|
let mouse_buttons_down = NSEvent::pressedMouseButtons();
|
||||||
if mouse_buttons_down == 0 {
|
if mouse_buttons_down == 0 {
|
||||||
// Point is outside of the client area (view) and no buttons are pressed
|
// Point is outside of the client area (view) and no buttons are pressed
|
||||||
return;
|
return;
|
||||||
@@ -1082,7 +1081,7 @@ impl WinitView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_view_point(&self, event: &NSEvent) -> LogicalPosition<f64> {
|
fn mouse_view_point(&self, event: &NSEvent) -> LogicalPosition<f64> {
|
||||||
let window_point = unsafe { event.locationInWindow() };
|
let window_point = event.locationInWindow();
|
||||||
let view_point = self.convertPoint_fromView(window_point, None);
|
let view_point = self.convertPoint_fromView(window_point, None);
|
||||||
|
|
||||||
LogicalPosition::new(view_point.x, view_point.y)
|
LogicalPosition::new(view_point.x, view_point.y)
|
||||||
@@ -1096,7 +1095,7 @@ fn mouse_button(event: &NSEvent) -> MouseButton {
|
|||||||
// For the other events, it's always set to 0.
|
// For the other events, it's always set to 0.
|
||||||
// MacOS only defines the left, right and middle buttons, 3..=31 are left as generic buttons,
|
// MacOS only defines the left, right and middle buttons, 3..=31 are left as generic buttons,
|
||||||
// but 3 and 4 are very commonly used as Back and Forward by hardware vendors and applications.
|
// but 3 and 4 are very commonly used as Back and Forward by hardware vendors and applications.
|
||||||
match unsafe { event.buttonNumber() } {
|
match event.buttonNumber() {
|
||||||
0 => MouseButton::Left,
|
0 => MouseButton::Left,
|
||||||
1 => MouseButton::Right,
|
1 => MouseButton::Right,
|
||||||
2 => MouseButton::Middle,
|
2 => MouseButton::Middle,
|
||||||
@@ -1120,12 +1119,10 @@ fn replace_event(event: &NSEvent, option_as_alt: OptionAsAlt) -> Retained<NSEven
|
|||||||
&& !ev_mods.meta_key();
|
&& !ev_mods.meta_key();
|
||||||
|
|
||||||
if ignore_alt_characters {
|
if ignore_alt_characters {
|
||||||
let ns_chars = unsafe {
|
let ns_chars =
|
||||||
event.charactersIgnoringModifiers().expect("expected characters to be non-null")
|
event.charactersIgnoringModifiers().expect("expected characters to be non-null");
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
NSEvent::keyEventWithType_location_modifierFlags_timestamp_windowNumber_context_characters_charactersIgnoringModifiers_isARepeat_keyCode(
|
||||||
NSEvent::keyEventWithType_location_modifierFlags_timestamp_windowNumber_context_characters_charactersIgnoringModifiers_isARepeat_keyCode(
|
|
||||||
event.r#type(),
|
event.r#type(),
|
||||||
event.locationInWindow(),
|
event.locationInWindow(),
|
||||||
event.modifierFlags(),
|
event.modifierFlags(),
|
||||||
@@ -1138,7 +1135,6 @@ fn replace_event(event: &NSEvent, option_as_alt: OptionAsAlt) -> Retained<NSEven
|
|||||||
event.keyCode(),
|
event.keyCode(),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
event.copy()
|
event.copy()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ use objc2::{
|
|||||||
use objc2_app_kit::{
|
use objc2_app_kit::{
|
||||||
NSAppKitVersionNumber, NSAppKitVersionNumber10_12, NSAppearance, NSAppearanceCustomization,
|
NSAppKitVersionNumber, NSAppKitVersionNumber10_12, NSAppearance, NSAppearanceCustomization,
|
||||||
NSAppearanceNameAqua, NSApplication, NSApplicationPresentationOptions, NSBackingStoreType,
|
NSAppearanceNameAqua, NSApplication, NSApplicationPresentationOptions, NSBackingStoreType,
|
||||||
NSColor, NSDraggingDestination, NSDraggingInfo, NSFilenamesPboardType,
|
NSColor, NSDraggingDestination, NSDraggingInfo, NSRequestUserAttentionType, NSScreen,
|
||||||
NSRequestUserAttentionType, NSScreen, NSToolbar, NSView, NSViewFrameDidChangeNotification,
|
NSToolbar, NSView, NSViewFrameDidChangeNotification, NSWindow, NSWindowButton,
|
||||||
NSWindow, NSWindowButton, NSWindowDelegate, NSWindowFullScreenButton, NSWindowLevel,
|
NSWindowDelegate, NSWindowLevel, NSWindowOcclusionState, NSWindowOrderingMode,
|
||||||
NSWindowOcclusionState, NSWindowOrderingMode, NSWindowSharingType, NSWindowStyleMask,
|
NSWindowSharingType, NSWindowStyleMask, NSWindowTabbingMode, NSWindowTitleVisibility,
|
||||||
NSWindowTabbingMode, NSWindowTitleVisibility, NSWindowToolbarStyle,
|
NSWindowToolbarStyle,
|
||||||
};
|
};
|
||||||
|
#[allow(deprecated)]
|
||||||
|
use objc2_app_kit::{NSFilenamesPboardType, NSWindowFullScreenButton};
|
||||||
use objc2_core_foundation::{CGFloat, CGPoint};
|
use objc2_core_foundation::{CGFloat, CGPoint};
|
||||||
use objc2_core_graphics::{
|
use objc2_core_graphics::{
|
||||||
kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, kCGDisplayFadeReservationInvalidToken,
|
kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, kCGDisplayFadeReservationInvalidToken,
|
||||||
@@ -350,7 +352,8 @@ define_class!(
|
|||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let pb = unsafe { sender.draggingPasteboard() };
|
let pb = sender.draggingPasteboard();
|
||||||
|
#[allow(deprecated)]
|
||||||
let filenames = pb
|
let filenames = pb
|
||||||
.propertyListForType(unsafe { NSFilenamesPboardType })
|
.propertyListForType(unsafe { NSFilenamesPboardType })
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -361,7 +364,7 @@ define_class!(
|
|||||||
.map(|file| PathBuf::from(file.downcast::<NSString>().unwrap().to_string()))
|
.map(|file| PathBuf::from(file.downcast::<NSString>().unwrap().to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let dl = unsafe { sender.draggingLocation() };
|
let dl = sender.draggingLocation();
|
||||||
let dl = self.view().convertPoint_fromView(dl, None);
|
let dl = self.view().convertPoint_fromView(dl, None);
|
||||||
let position =
|
let position =
|
||||||
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor());
|
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor());
|
||||||
@@ -383,7 +386,7 @@ define_class!(
|
|||||||
fn dragging_updated(&self, sender: &ProtocolObject<dyn NSDraggingInfo>) -> bool {
|
fn dragging_updated(&self, sender: &ProtocolObject<dyn NSDraggingInfo>) -> bool {
|
||||||
trace_scope!("draggingUpdated:");
|
trace_scope!("draggingUpdated:");
|
||||||
|
|
||||||
let dl = unsafe { sender.draggingLocation() };
|
let dl = sender.draggingLocation();
|
||||||
let dl = self.view().convertPoint_fromView(dl, None);
|
let dl = self.view().convertPoint_fromView(dl, None);
|
||||||
let position =
|
let position =
|
||||||
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor());
|
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor());
|
||||||
@@ -407,7 +410,8 @@ define_class!(
|
|||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let pb = unsafe { sender.draggingPasteboard() };
|
let pb = sender.draggingPasteboard();
|
||||||
|
#[allow(deprecated)]
|
||||||
let filenames = pb
|
let filenames = pb
|
||||||
.propertyListForType(unsafe { NSFilenamesPboardType })
|
.propertyListForType(unsafe { NSFilenamesPboardType })
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -418,7 +422,7 @@ define_class!(
|
|||||||
.map(|file| PathBuf::from(file.downcast::<NSString>().unwrap().to_string()))
|
.map(|file| PathBuf::from(file.downcast::<NSString>().unwrap().to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let dl = unsafe { sender.draggingLocation() };
|
let dl = sender.draggingLocation();
|
||||||
let dl = self.view().convertPoint_fromView(dl, None);
|
let dl = self.view().convertPoint_fromView(dl, None);
|
||||||
let position =
|
let position =
|
||||||
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor());
|
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor());
|
||||||
@@ -440,7 +444,7 @@ define_class!(
|
|||||||
trace_scope!("draggingExited:");
|
trace_scope!("draggingExited:");
|
||||||
|
|
||||||
let position = sender.map(|sender| {
|
let position = sender.map(|sender| {
|
||||||
let dl = unsafe { sender.draggingLocation() };
|
let dl = sender.draggingLocation();
|
||||||
let dl = self.view().convertPoint_fromView(dl, None);
|
let dl = self.view().convertPoint_fromView(dl, None);
|
||||||
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor())
|
LogicalPosition::<f64>::from((dl.x, dl.y)).to_physical(self.scale_factor())
|
||||||
});
|
});
|
||||||
@@ -477,12 +481,12 @@ define_class!(
|
|||||||
let old = old.downcast::<NSAppearance>().unwrap();
|
let old = old.downcast::<NSAppearance>().unwrap();
|
||||||
let new = new.downcast::<NSAppearance>().unwrap();
|
let new = new.downcast::<NSAppearance>().unwrap();
|
||||||
|
|
||||||
trace!(old = %unsafe { old.name() }, new = %unsafe { new.name() }, "effectiveAppearance changed");
|
trace!(old = %old.name(), new = %new.name(), "effectiveAppearance changed");
|
||||||
|
|
||||||
// Ignore the change if the window's theme is customized by the user (since in that
|
// Ignore the change if the window's theme is customized by the user (since in that
|
||||||
// case the `effectiveAppearance` is only emitted upon said customization, and then
|
// case the `effectiveAppearance` is only emitted upon said customization, and then
|
||||||
// it's triggered directly by a user action, and we don't want to emit the event).
|
// it's triggered directly by a user action, and we don't want to emit the event).
|
||||||
if unsafe { self.window().appearance() }.is_some() {
|
if self.window().appearance().is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,9 +509,7 @@ define_class!(
|
|||||||
|
|
||||||
impl Drop for WindowDelegate {
|
impl Drop for WindowDelegate {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe { self.window().removeObserver_forKeyPath(self, ns_string!("effectiveAppearance")) };
|
||||||
self.window().removeObserver_forKeyPath(self, ns_string!("effectiveAppearance"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,12 +668,10 @@ fn new_window(
|
|||||||
window.setMovableByWindowBackground(true);
|
window.setMovableByWindowBackground(true);
|
||||||
}
|
}
|
||||||
if macos_attrs.unified_titlebar {
|
if macos_attrs.unified_titlebar {
|
||||||
unsafe {
|
// The toolbar style is ignored if there is no toolbar, so it is
|
||||||
// The toolbar style is ignored if there is no toolbar, so it is
|
// necessary to add one.
|
||||||
// necessary to add one.
|
window.setToolbar(Some(&NSToolbar::new(mtm)));
|
||||||
window.setToolbar(Some(&NSToolbar::new(mtm)));
|
window.setToolbarStyle(NSWindowToolbarStyle::Unified);
|
||||||
window.setToolbarStyle(NSWindowToolbarStyle::Unified);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !attrs.enabled_buttons.contains(WindowButtons::MAXIMIZE) {
|
if !attrs.enabled_buttons.contains(WindowButtons::MAXIMIZE) {
|
||||||
@@ -720,7 +720,7 @@ fn new_window(
|
|||||||
view.setPostsFrameChangedNotifications(true);
|
view.setPostsFrameChangedNotifications(true);
|
||||||
// `setPostsFrameChangedNotifications` posts the notification immediately, so register the
|
// `setPostsFrameChangedNotifications` posts the notification immediately, so register the
|
||||||
// observer _after_, again so that the event isn't triggered initially.
|
// observer _after_, again so that the event isn't triggered initially.
|
||||||
let notification_center = unsafe { NSNotificationCenter::defaultCenter() };
|
let notification_center = NSNotificationCenter::defaultCenter();
|
||||||
unsafe {
|
unsafe {
|
||||||
notification_center.addObserver_selector_name_object(
|
notification_center.addObserver_selector_name_object(
|
||||||
&view,
|
&view,
|
||||||
@@ -733,10 +733,11 @@ fn new_window(
|
|||||||
if attrs.transparent {
|
if attrs.transparent {
|
||||||
window.setOpaque(false);
|
window.setOpaque(false);
|
||||||
// See `set_transparent` for details on why we do this.
|
// See `set_transparent` for details on why we do this.
|
||||||
window.setBackgroundColor(unsafe { Some(&NSColor::clearColor()) });
|
window.setBackgroundColor(Some(&NSColor::clearColor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// register for drag and drop operations.
|
// register for drag and drop operations.
|
||||||
|
#[allow(deprecated)]
|
||||||
window.registerForDraggedTypes(&NSArray::from_slice(&[unsafe { NSFilenamesPboardType }]));
|
window.registerForDraggedTypes(&NSArray::from_slice(&[unsafe { NSFilenamesPboardType }]));
|
||||||
|
|
||||||
Some(window)
|
Some(window)
|
||||||
@@ -790,7 +791,7 @@ impl WindowDelegate {
|
|||||||
let scale_factor = window.backingScaleFactor() as _;
|
let scale_factor = window.backingScaleFactor() as _;
|
||||||
|
|
||||||
if let Some(appearance) = theme_to_appearance(attrs.preferred_theme) {
|
if let Some(appearance) = theme_to_appearance(attrs.preferred_theme) {
|
||||||
unsafe { window.setAppearance(Some(&appearance)) };
|
window.setAppearance(Some(&appearance));
|
||||||
}
|
}
|
||||||
|
|
||||||
let delegate = mtm.alloc().set_ivars(State {
|
let delegate = mtm.alloc().set_ivars(State {
|
||||||
@@ -945,11 +946,8 @@ impl WindowDelegate {
|
|||||||
// transparent, as in that case, the transparent contents will just be drawn on top of
|
// transparent, as in that case, the transparent contents will just be drawn on top of
|
||||||
// the background color. As such, to allow the window to be transparent, we must also set
|
// the background color. As such, to allow the window to be transparent, we must also set
|
||||||
// the background color to one with an empty alpha channel.
|
// the background color to one with an empty alpha channel.
|
||||||
let color = if transparent {
|
let color =
|
||||||
unsafe { NSColor::clearColor() }
|
if transparent { NSColor::clearColor() } else { NSColor::windowBackgroundColor() };
|
||||||
} else {
|
|
||||||
unsafe { NSColor::windowBackgroundColor() }
|
|
||||||
};
|
|
||||||
|
|
||||||
self.window().setBackgroundColor(Some(&color));
|
self.window().setBackgroundColor(Some(&color));
|
||||||
}
|
}
|
||||||
@@ -958,7 +956,7 @@ impl WindowDelegate {
|
|||||||
// NOTE: in general we want to specify the blur radius, but the choice of 80
|
// NOTE: in general we want to specify the blur radius, but the choice of 80
|
||||||
// should be a reasonable default.
|
// should be a reasonable default.
|
||||||
let radius = if blur { 80 } else { 0 };
|
let radius = if blur { 80 } else { 0 };
|
||||||
let window_number = unsafe { self.window().windowNumber() };
|
let window_number = self.window().windowNumber();
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::CGSSetWindowBackgroundBlurRadius(
|
ffi::CGSSetWindowBackgroundBlurRadius(
|
||||||
ffi::CGSMainConnectionID(),
|
ffi::CGSMainConnectionID(),
|
||||||
@@ -1017,7 +1015,7 @@ impl WindowDelegate {
|
|||||||
NSPoint::new(position.x, position.y),
|
NSPoint::new(position.x, position.y),
|
||||||
self.window().frame().size,
|
self.window().frame().size,
|
||||||
));
|
));
|
||||||
unsafe { self.window().setFrameOrigin(point) };
|
self.window().setFrameOrigin(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1039,17 +1037,15 @@ impl WindowDelegate {
|
|||||||
let insets = if self.view().respondsToSelector(sel!(safeAreaInsets)) {
|
let insets = if self.view().respondsToSelector(sel!(safeAreaInsets)) {
|
||||||
// Includes NSWindowStyleMask::FullSizeContentView by default, and the notch because
|
// Includes NSWindowStyleMask::FullSizeContentView by default, and the notch because
|
||||||
// we've set it up with `additionalSafeAreaInsets`.
|
// we've set it up with `additionalSafeAreaInsets`.
|
||||||
unsafe { self.view().safeAreaInsets() }
|
self.view().safeAreaInsets()
|
||||||
} else {
|
} else {
|
||||||
// If `safeAreaInsets` is not available, we'll have to do the calculation ourselves.
|
// If `safeAreaInsets` is not available, we'll have to do the calculation ourselves.
|
||||||
|
|
||||||
let window_rect = unsafe {
|
let window_rect = self.window().convertRectFromScreen(
|
||||||
self.window().convertRectFromScreen(
|
self.window().contentRectForFrameRect(self.window().frame()),
|
||||||
self.window().contentRectForFrameRect(self.window().frame()),
|
);
|
||||||
)
|
|
||||||
};
|
|
||||||
// This includes NSWindowStyleMask::FullSizeContentView.
|
// This includes NSWindowStyleMask::FullSizeContentView.
|
||||||
let layout_rect = unsafe { self.window().contentLayoutRect() };
|
let layout_rect = self.window().contentLayoutRect();
|
||||||
|
|
||||||
// Calculate the insets from window coordinates in AppKit's coordinate system.
|
// Calculate the insets from window coordinates in AppKit's coordinate system.
|
||||||
NSEdgeInsets {
|
NSEdgeInsets {
|
||||||
@@ -1079,7 +1075,7 @@ impl WindowDelegate {
|
|||||||
let min_size = dimensions.to_logical::<CGFloat>(self.scale_factor());
|
let min_size = dimensions.to_logical::<CGFloat>(self.scale_factor());
|
||||||
|
|
||||||
let min_size = NSSize::new(min_size.width, min_size.height);
|
let min_size = NSSize::new(min_size.width, min_size.height);
|
||||||
unsafe { self.window().setContentMinSize(min_size) };
|
self.window().setContentMinSize(min_size);
|
||||||
|
|
||||||
// If necessary, resize the window to match constraint
|
// If necessary, resize the window to match constraint
|
||||||
let mut current_size = self.window().contentRectForFrameRect(self.window().frame()).size;
|
let mut current_size = self.window().contentRectForFrameRect(self.window().frame()).size;
|
||||||
@@ -1101,7 +1097,7 @@ impl WindowDelegate {
|
|||||||
let max_size = dimensions.to_logical::<CGFloat>(scale_factor);
|
let max_size = dimensions.to_logical::<CGFloat>(scale_factor);
|
||||||
|
|
||||||
let max_size = NSSize::new(max_size.width, max_size.height);
|
let max_size = NSSize::new(max_size.width, max_size.height);
|
||||||
unsafe { self.window().setContentMaxSize(max_size) };
|
self.window().setContentMaxSize(max_size);
|
||||||
|
|
||||||
// If necessary, resize the window to match constraint
|
// If necessary, resize the window to match constraint
|
||||||
let mut current_size = self.window().contentRectForFrameRect(self.window().frame()).size;
|
let mut current_size = self.window().contentRectForFrameRect(self.window().frame()).size;
|
||||||
@@ -1246,7 +1242,7 @@ impl WindowDelegate {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Do this for real https://stackoverflow.com/a/40922095/5435443
|
// TODO: Do this for real https://stackoverflow.com/a/40922095/5435443
|
||||||
cgerr(unsafe { CGAssociateMouseAndMouseCursorPosition(associate_mouse_cursor) })?;
|
cgerr(CGAssociateMouseAndMouseCursorPosition(associate_mouse_cursor))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1274,8 +1270,8 @@ impl WindowDelegate {
|
|||||||
x: window_position.x + cursor_position.x,
|
x: window_position.x + cursor_position.x,
|
||||||
y: window_position.y + cursor_position.y,
|
y: window_position.y + cursor_position.y,
|
||||||
};
|
};
|
||||||
cgerr(unsafe { CGWarpMouseCursorPosition(point) })?;
|
cgerr(CGWarpMouseCursorPosition(point))?;
|
||||||
cgerr(unsafe { CGAssociateMouseAndMouseCursorPosition(true) })?;
|
cgerr(CGAssociateMouseAndMouseCursorPosition(true))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1356,7 +1352,7 @@ impl WindowDelegate {
|
|||||||
if minimized {
|
if minimized {
|
||||||
self.window().miniaturize(Some(self));
|
self.window().miniaturize(Some(self));
|
||||||
} else {
|
} else {
|
||||||
unsafe { self.window().deminiaturize(Some(self)) };
|
self.window().deminiaturize(Some(self));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1450,7 +1446,7 @@ impl WindowDelegate {
|
|||||||
|
|
||||||
let old_screen = self.window().screen().unwrap();
|
let old_screen = self.window().screen().unwrap();
|
||||||
if old_screen != new_screen {
|
if old_screen != new_screen {
|
||||||
unsafe { self.window().setFrameOrigin(new_screen.frame().origin) };
|
self.window().setFrameOrigin(new_screen.frame().origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1475,25 +1471,23 @@ impl WindowDelegate {
|
|||||||
self.ivars().save_presentation_opts.replace(Some(app.presentationOptions()));
|
self.ivars().save_presentation_opts.replace(Some(app.presentationOptions()));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
// Fade to black (and wait for the fade to complete) to hide the
|
||||||
// Fade to black (and wait for the fade to complete) to hide the
|
// flicker from capturing the display and switching display mode
|
||||||
// flicker from capturing the display and switching display mode
|
if cgerr(unsafe { CGAcquireDisplayFadeReservation(5.0, &mut fade_token) }).is_ok() {
|
||||||
if cgerr(CGAcquireDisplayFadeReservation(5.0, &mut fade_token)).is_ok() {
|
CGDisplayFade(
|
||||||
CGDisplayFade(
|
fade_token,
|
||||||
fade_token,
|
0.3,
|
||||||
0.3,
|
kCGDisplayBlendNormal,
|
||||||
kCGDisplayBlendNormal,
|
kCGDisplayBlendSolidColor,
|
||||||
kCGDisplayBlendSolidColor,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
true,
|
||||||
true,
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
cgerr(CGDisplayCapture(display_id)).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cgerr(CGDisplayCapture(display_id)).unwrap();
|
||||||
|
|
||||||
let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
|
let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
|
||||||
let video_mode =
|
let video_mode =
|
||||||
match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) {
|
match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) {
|
||||||
@@ -1501,25 +1495,25 @@ impl WindowDelegate {
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
cgerr(unsafe {
|
||||||
cgerr(CGDisplaySetDisplayMode(display_id, Some(&video_mode.native_mode.0), None))
|
CGDisplaySetDisplayMode(display_id, Some(&video_mode.native_mode.0), None)
|
||||||
.expect("failed to set video mode");
|
})
|
||||||
|
.expect("failed to set video mode");
|
||||||
|
|
||||||
// After the display has been configured, fade back in
|
// After the display has been configured, fade back in
|
||||||
// asynchronously
|
// asynchronously
|
||||||
if fade_token != kCGDisplayFadeReservationInvalidToken {
|
if fade_token != kCGDisplayFadeReservationInvalidToken {
|
||||||
CGDisplayFade(
|
CGDisplayFade(
|
||||||
fade_token,
|
fade_token,
|
||||||
0.6,
|
0.6,
|
||||||
kCGDisplayBlendSolidColor,
|
kCGDisplayBlendSolidColor,
|
||||||
kCGDisplayBlendNormal,
|
kCGDisplayBlendNormal,
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
CGReleaseDisplayFadeReservation(fade_token);
|
CGReleaseDisplayFadeReservation(fade_token);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1582,7 +1576,7 @@ impl WindowDelegate {
|
|||||||
| NSApplicationPresentationOptions::HideMenuBar;
|
| NSApplicationPresentationOptions::HideMenuBar;
|
||||||
app.setPresentationOptions(presentation_options);
|
app.setPresentationOptions(presentation_options);
|
||||||
|
|
||||||
let window_level = unsafe { CGShieldingWindowLevel() } as NSWindowLevel + 1;
|
let window_level = CGShieldingWindowLevel() as NSWindowLevel + 1;
|
||||||
self.window().setLevel(window_level);
|
self.window().setLevel(window_level);
|
||||||
},
|
},
|
||||||
(Some(Fullscreen::Exclusive(monitor, _)), Some(Fullscreen::Borderless(_))) => {
|
(Some(Fullscreen::Exclusive(monitor, _)), Some(Fullscreen::Borderless(_))) => {
|
||||||
@@ -1797,9 +1791,8 @@ impl WindowDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn theme(&self) -> Option<Theme> {
|
pub fn theme(&self) -> Option<Theme> {
|
||||||
unsafe { self.window().appearance() }
|
self.window().appearance().map(|appearance| appearance_to_theme(&appearance)).or_else(
|
||||||
.map(|appearance| appearance_to_theme(&appearance))
|
|| {
|
||||||
.or_else(|| {
|
|
||||||
let mtm = MainThreadMarker::from(self);
|
let mtm = MainThreadMarker::from(self);
|
||||||
let app = NSApplication::sharedApplication(mtm);
|
let app = NSApplication::sharedApplication(mtm);
|
||||||
|
|
||||||
@@ -1808,11 +1801,12 @@ impl WindowDelegate {
|
|||||||
} else {
|
} else {
|
||||||
Some(Theme::Light)
|
Some(Theme::Light)
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_theme(&self, theme: Option<Theme>) {
|
pub fn set_theme(&self, theme: Option<Theme>) {
|
||||||
unsafe { self.window().setAppearance(theme_to_appearance(theme).as_deref()) };
|
self.window().setAppearance(theme_to_appearance(theme).as_deref());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1836,10 +1830,8 @@ impl WindowDelegate {
|
|||||||
fn restore_and_release_display(monitor: &MonitorHandle) {
|
fn restore_and_release_display(monitor: &MonitorHandle) {
|
||||||
let available_monitors = monitor::available_monitors();
|
let available_monitors = monitor::available_monitors();
|
||||||
if available_monitors.contains(monitor) {
|
if available_monitors.contains(monitor) {
|
||||||
unsafe {
|
CGRestorePermanentDisplayConfiguration();
|
||||||
CGRestorePermanentDisplayConfiguration();
|
cgerr(CGDisplayRelease(monitor.native_id() as _)).unwrap();
|
||||||
cgerr(CGDisplayRelease(monitor.native_id() as _)).unwrap();
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
monitor = monitor.name().map(|name| name.to_string()),
|
monitor = monitor.name().map(|name| name.to_string()),
|
||||||
@@ -1901,7 +1893,7 @@ impl WindowExtMacOS for WindowDelegate {
|
|||||||
|
|
||||||
// Configure the safe area rectangle, to ensure that we don't obscure the notch.
|
// Configure the safe area rectangle, to ensure that we don't obscure the notch.
|
||||||
if NSScreen::class().responds_to(sel!(safeAreaInsets)) {
|
if NSScreen::class().responds_to(sel!(safeAreaInsets)) {
|
||||||
unsafe { self.view().setAdditionalSafeAreaInsets(screen.safeAreaInsets()) };
|
self.view().setAdditionalSafeAreaInsets(screen.safeAreaInsets());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fullscreen windows can't be resized, minimized, or moved
|
// Fullscreen windows can't be resized, minimized, or moved
|
||||||
@@ -1920,14 +1912,12 @@ impl WindowExtMacOS for WindowDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if NSScreen::class().responds_to(sel!(safeAreaInsets)) {
|
if NSScreen::class().responds_to(sel!(safeAreaInsets)) {
|
||||||
unsafe {
|
self.view().setAdditionalSafeAreaInsets(NSEdgeInsets {
|
||||||
self.view().setAdditionalSafeAreaInsets(NSEdgeInsets {
|
top: 0.0,
|
||||||
top: 0.0,
|
left: 0.0,
|
||||||
left: 0.0,
|
bottom: 0.0,
|
||||||
bottom: 0.0,
|
right: 0.0,
|
||||||
right: 0.0,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window().setFrame_display(frame, true);
|
self.window().setFrame_display(frame, true);
|
||||||
@@ -1965,7 +1955,7 @@ impl WindowExtMacOS for WindowDelegate {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn select_previous_tab(&self) {
|
fn select_previous_tab(&self) {
|
||||||
unsafe { self.window().selectPreviousTab(None) }
|
self.window().selectPreviousTab(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1975,7 +1965,7 @@ impl WindowExtMacOS for WindowDelegate {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(group) = self.window().tabGroup() {
|
if let Some(group) = self.window().tabGroup() {
|
||||||
if let Some(windows) = unsafe { self.window().tabbedWindows() } {
|
if let Some(windows) = self.window().tabbedWindows() {
|
||||||
if index < windows.len() {
|
if index < windows.len() {
|
||||||
group.setSelectedWindow(Some(&windows.objectAtIndex(index)));
|
group.setSelectedWindow(Some(&windows.objectAtIndex(index)));
|
||||||
}
|
}
|
||||||
@@ -1985,7 +1975,7 @@ impl WindowExtMacOS for WindowDelegate {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn num_tabs(&self) -> usize {
|
fn num_tabs(&self) -> usize {
|
||||||
unsafe { self.window().tabbedWindows() }.map(|windows| windows.len()).unwrap_or(1)
|
self.window().tabbedWindows().map(|windows| windows.len()).unwrap_or(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_document_edited(&self) -> bool {
|
fn is_document_edited(&self) -> bool {
|
||||||
@@ -2018,26 +2008,20 @@ impl WindowExtMacOS for WindowDelegate {
|
|||||||
if unified_titlebar {
|
if unified_titlebar {
|
||||||
let mtm = MainThreadMarker::from(self);
|
let mtm = MainThreadMarker::from(self);
|
||||||
|
|
||||||
unsafe {
|
// The toolbar style is ignored if there is no toolbar, so it is
|
||||||
// The toolbar style is ignored if there is no toolbar, so it is
|
// necessary to add one.
|
||||||
// necessary to add one.
|
window.setToolbar(Some(&NSToolbar::new(mtm)));
|
||||||
window.setToolbar(Some(&NSToolbar::new(mtm)));
|
window.setToolbarStyle(NSWindowToolbarStyle::Unified);
|
||||||
window.setToolbarStyle(NSWindowToolbarStyle::Unified);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
window.setToolbar(None);
|
||||||
window.setToolbar(None);
|
window.setToolbarStyle(NSWindowToolbarStyle::Automatic);
|
||||||
window.setToolbarStyle(NSWindowToolbarStyle::Automatic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unified_titlebar(&self) -> bool {
|
fn unified_titlebar(&self) -> bool {
|
||||||
let window = self.window();
|
let window = self.window();
|
||||||
|
|
||||||
unsafe {
|
window.toolbar().is_some() && window.toolbarStyle() == NSWindowToolbarStyle::Unified
|
||||||
window.toolbar().is_some() && window.toolbarStyle() == NSWindowToolbarStyle::Unified
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ impl EventLoop {
|
|||||||
// this line sets up the main run loop before `UIApplicationMain`
|
// this line sets up the main run loop before `UIApplicationMain`
|
||||||
setup_control_flow_observers();
|
setup_control_flow_observers();
|
||||||
|
|
||||||
let center = unsafe { NSNotificationCenter::defaultCenter() };
|
let center = NSNotificationCenter::defaultCenter();
|
||||||
|
|
||||||
let _did_finish_launching_observer = create_observer(
|
let _did_finish_launching_observer = create_observer(
|
||||||
¢er,
|
¢er,
|
||||||
@@ -181,7 +181,7 @@ impl EventLoop {
|
|||||||
// `applicationWillEnterForeground:`
|
// `applicationWillEnterForeground:`
|
||||||
unsafe { UIApplicationWillEnterForegroundNotification },
|
unsafe { UIApplicationWillEnterForegroundNotification },
|
||||||
move |notification| {
|
move |notification| {
|
||||||
let app = unsafe { notification.object() }.expect(
|
let app = notification.object().expect(
|
||||||
"UIApplicationWillEnterForegroundNotification to have application object",
|
"UIApplicationWillEnterForegroundNotification to have application object",
|
||||||
);
|
);
|
||||||
// The `object` in `UIApplicationWillEnterForegroundNotification` is documented to
|
// The `object` in `UIApplicationWillEnterForegroundNotification` is documented to
|
||||||
@@ -195,7 +195,7 @@ impl EventLoop {
|
|||||||
// `applicationDidEnterBackground:`
|
// `applicationDidEnterBackground:`
|
||||||
unsafe { UIApplicationDidEnterBackgroundNotification },
|
unsafe { UIApplicationDidEnterBackgroundNotification },
|
||||||
move |notification| {
|
move |notification| {
|
||||||
let app = unsafe { notification.object() }.expect(
|
let app = notification.object().expect(
|
||||||
"UIApplicationDidEnterBackgroundNotification to have application object",
|
"UIApplicationDidEnterBackgroundNotification to have application object",
|
||||||
);
|
);
|
||||||
// The `object` in `UIApplicationDidEnterBackgroundNotification` is documented to be
|
// The `object` in `UIApplicationDidEnterBackgroundNotification` is documented to be
|
||||||
@@ -209,7 +209,8 @@ impl EventLoop {
|
|||||||
// `applicationWillTerminate:`
|
// `applicationWillTerminate:`
|
||||||
unsafe { UIApplicationWillTerminateNotification },
|
unsafe { UIApplicationWillTerminateNotification },
|
||||||
move |notification| {
|
move |notification| {
|
||||||
let app = unsafe { notification.object() }
|
let app = notification
|
||||||
|
.object()
|
||||||
.expect("UIApplicationWillTerminateNotification to have application object");
|
.expect("UIApplicationWillTerminateNotification to have application object");
|
||||||
// The `object` in `UIApplicationWillTerminateNotification` is (somewhat) documented
|
// The `object` in `UIApplicationWillTerminateNotification` is (somewhat) documented
|
||||||
// to be `UIApplication`.
|
// to be `UIApplication`.
|
||||||
|
|||||||
@@ -271,8 +271,8 @@ mod tests {
|
|||||||
let main = UIScreen::mainScreen(mtm);
|
let main = UIScreen::mainScreen(mtm);
|
||||||
assert!(UIScreen::screens(mtm).iter().any(|screen| ptr::eq(&*screen, &*main)));
|
assert!(UIScreen::screens(mtm).iter().any(|screen| ptr::eq(&*screen, &*main)));
|
||||||
|
|
||||||
assert!(unsafe {
|
assert!(
|
||||||
NSSet::setWithArray(&UIScreen::screens(mtm)).containsObject(&UIScreen::mainScreen(mtm))
|
NSSet::setWithArray(&UIScreen::screens(mtm)).containsObject(&UIScreen::mainScreen(mtm))
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,8 +161,7 @@ impl Inner {
|
|||||||
|
|
||||||
pub fn surface_position(&self) -> PhysicalPosition<i32> {
|
pub fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||||
let view_position = self.view.frame().origin;
|
let view_position = self.view.frame().origin;
|
||||||
let position =
|
let position = self.window.convertPoint_fromView(view_position, Some(&self.view));
|
||||||
unsafe { self.window.convertPoint_fromView(view_position, Some(&self.view)) };
|
|
||||||
let position = LogicalPosition::new(position.x, position.y);
|
let position = LogicalPosition::new(position.x, position.y);
|
||||||
position.to_physical(self.scale_factor())
|
position.to_physical(self.scale_factor())
|
||||||
}
|
}
|
||||||
@@ -393,9 +392,7 @@ impl Inner {
|
|||||||
}
|
}
|
||||||
*current_caps = Some(capabilities);
|
*current_caps = Some(capabilities);
|
||||||
|
|
||||||
unsafe {
|
self.view.becomeFirstResponder();
|
||||||
self.view.becomeFirstResponder();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ImeRequest::Update(_) => {
|
ImeRequest::Update(_) => {
|
||||||
if current_caps.is_none() {
|
if current_caps.is_none() {
|
||||||
@@ -404,9 +401,7 @@ impl Inner {
|
|||||||
},
|
},
|
||||||
ImeRequest::Disable => {
|
ImeRequest::Disable => {
|
||||||
*current_caps = None;
|
*current_caps = None;
|
||||||
unsafe {
|
self.view.resignFirstResponder();
|
||||||
self.view.resignFirstResponder();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user