use objc2_app_kit::{NSScreen, NSWindow};
use objc2_core_foundation::{CFDictionary, CFRetained, Type, kCFBooleanTrue};
use objc2_core_graphics::{
CGDirectDisplayID, CGDisplayCopyAllDisplayModes, CGDisplayCopyDisplayMode, CGDisplayMode,
CGDisplaySetDisplayMode, CGError, CGMainDisplayID, kCGDisplayShowDuplicateLowResolutionModes,
};
use objc2_foundation::{NSNumber, ns_string};
use crate::gfx::display_mode::DisplayMode;
fn display_id(window: Option<&NSWindow>) -> CGDirectDisplayID {
window
.and_then(|w| w.screen())
.and_then(|s| screen_display_id(&s))
.unwrap_or_else(|| CGMainDisplayID())
}
fn screen_display_id(screen: &NSScreen) -> Option<CGDirectDisplayID> {
let desc = screen.deviceDescription();
let obj = desc.objectForKey(ns_string!("NSScreenNumber"))?;
let num = obj.downcast_ref::<NSNumber>()?;
Some(num.unsignedIntValue())
}
pub(super) fn enumerate(window: Option<&NSWindow>) -> Vec<DisplayMode> {
let display = display_id(window);
let mut out = Vec::new();
for mode in copy_all_modes(display) {
if !CGDisplayMode::is_usable_for_desktop_gui(Some(&mode)) {
continue;
}
if let Some(dm) = display_mode_of(&mode) {
out.push(dm);
}
}
out
}
pub(super) fn current(window: Option<&NSWindow>) -> Option<DisplayMode> {
let mode = CGDisplayCopyDisplayMode(display_id(window))?;
display_mode_of(&mode)
}
fn copy_all_modes(display: CGDirectDisplayID) -> Vec<CFRetained<CGDisplayMode>> {
let options = unsafe {
kCFBooleanTrue.map(|yes| {
CFDictionary::from_slices(&[kCGDisplayShowDuplicateLowResolutionModes], &[yes])
})
};
let array =
unsafe { CGDisplayCopyAllDisplayModes(display, options.as_deref().map(|d| d.as_opaque())) };
let Some(array) = array else {
return Vec::new();
};
let mut out = Vec::new();
for i in 0..array.count() {
let ptr = unsafe { array.value_at_index(i) };
if ptr.is_null() {
continue;
}
let mode: &CGDisplayMode = unsafe { &*ptr.cast() };
out.push(mode.retain());
}
out
}
fn display_mode_of(mode: &CGDisplayMode) -> Option<DisplayMode> {
let width = CGDisplayMode::pixel_width(Some(mode)) as u32;
let height = CGDisplayMode::pixel_height(Some(mode)) as u32;
if width == 0 || height == 0 {
return None;
}
let refresh_hz = CGDisplayMode::refresh_rate(Some(mode)).round().max(0.0) as u32;
Some(DisplayMode {
width,
height,
refresh_hz,
})
}
fn find_native_mode(
display: CGDirectDisplayID,
want: DisplayMode,
) -> Option<CFRetained<CGDisplayMode>> {
let mut best: Option<(u32, CFRetained<CGDisplayMode>)> = None;
for mode in copy_all_modes(display) {
let Some(dm) = display_mode_of(&mode) else {
continue;
};
if dm.width != want.width || dm.height != want.height {
continue;
}
if want.refresh_hz != 0 && dm.refresh_hz == want.refresh_hz {
return Some(mode);
}
if best.as_ref().is_none_or(|(hz, _)| dm.refresh_hz > *hz) {
best = Some((dm.refresh_hz, mode));
}
}
best.map(|(_, mode)| mode)
}
pub(super) struct FullscreenDisplayMode {
desired: Option<DisplayMode>,
original: Option<CFRetained<CGDisplayMode>>,
display: Option<CGDirectDisplayID>,
applied: Option<DisplayMode>,
}
impl std::fmt::Debug for FullscreenDisplayMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FullscreenDisplayMode")
.field("desired", &self.desired)
.field("applied", &self.applied)
.field("holds_original", &self.original.is_some())
.finish()
}
}
impl FullscreenDisplayMode {
pub(super) fn new() -> Self {
Self {
desired: None,
original: None,
display: None,
applied: None,
}
}
pub(super) fn set_desired(&mut self, mode: DisplayMode) {
self.desired = Some(mode);
}
pub(super) fn reconcile(&mut self, window: Option<&NSWindow>, fullscreen: bool) {
if !fullscreen {
self.restore();
return;
}
let Some(desired) = self.desired else {
return;
};
if self.applied == Some(desired) {
return;
}
let display = *self.display.get_or_insert_with(|| display_id(window));
let Some(mode) = find_native_mode(display, desired) else {
tracing::warn!(
"display has no {}x{} mode; keeping the current mode",
desired.width,
desired.height
);
self.desired = None;
return;
};
if self.original.is_none() {
self.original = CGDisplayCopyDisplayMode(display);
}
let err = unsafe { CGDisplaySetDisplayMode(display, Some(&mode), None) };
if err == CGError::Success {
self.applied = Some(desired);
} else {
tracing::warn!(
"CGDisplaySetDisplayMode({}x{}@{}Hz) failed: {:?}",
desired.width,
desired.height,
desired.refresh_hz,
err
);
self.desired = None;
}
}
pub(super) fn restore(&mut self) {
let Some(original) = self.original.take() else {
return;
};
let Some(display) = self.display else {
return;
};
let err = unsafe { CGDisplaySetDisplayMode(display, Some(&original), None) };
if err != CGError::Success {
tracing::warn!("restoring the desktop display mode failed: {:?}", err);
}
self.applied = None;
}
}
impl Drop for FullscreenDisplayMode {
fn drop(&mut self) {
self.restore();
}
}