You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
44 lines
1.8 KiB
44 lines
1.8 KiB
/// A display mode reduced to what matters for picking one. Mirrors CGDisplayMode.
|
|
public struct DisplayModeInfo: Hashable, Sendable {
|
|
public var width: Int // points
|
|
public var height: Int
|
|
public var pixelWidth: Int
|
|
public var pixelHeight: Int
|
|
public var refreshRate: Double // Hz, 0 for some built-in panels
|
|
|
|
public init(width: Int, height: Int, pixelWidth: Int, pixelHeight: Int, refreshRate: Double) {
|
|
self.width = width
|
|
self.height = height
|
|
self.pixelWidth = pixelWidth
|
|
self.pixelHeight = pixelHeight
|
|
self.refreshRate = refreshRate
|
|
}
|
|
|
|
public var isHiDPI: Bool { pixelWidth > width }
|
|
}
|
|
|
|
public enum DisplayModeSelection {
|
|
/// Picks the mode with the same size as `current` and a refresh rate within
|
|
/// `tolerance` of `targetHz`. Returns nil if `current` already matches or no such mode exists.
|
|
public static func mode(
|
|
matching targetHz: Double,
|
|
current: DisplayModeInfo,
|
|
available: [DisplayModeInfo],
|
|
tolerance: Double = 0.1
|
|
) -> DisplayModeInfo? {
|
|
if abs(current.refreshRate - targetHz) <= tolerance { return nil }
|
|
return available
|
|
.filter {
|
|
$0.width == current.width && $0.height == current.height
|
|
&& abs($0.refreshRate - targetHz) <= tolerance
|
|
}
|
|
// Prefer the same backing resolution, then the closest rate.
|
|
.min { lhs, rhs in
|
|
let lhsSame = lhs.pixelWidth == current.pixelWidth && lhs.pixelHeight == current.pixelHeight
|
|
let rhsSame = rhs.pixelWidth == current.pixelWidth && rhs.pixelHeight == current.pixelHeight
|
|
if lhsSame != rhsSame { return lhsSame }
|
|
return abs(lhs.refreshRate - targetHz) < abs(rhs.refreshRate - targetHz)
|
|
}
|
|
}
|
|
}
|