This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
import AppKit
|
||||
import CoreGraphics
|
||||
import Foundation
|
||||
import OSLog
|
||||
import MacToolsPluginKit
|
||||
|
||||
@MainActor
|
||||
protocol DisplayResolutionControlling {
|
||||
func listConnectedDisplays() -> [DisplayInfo]
|
||||
func listAvailableResolutions(for displayID: CGDirectDisplayID) -> [DisplayResolutionInfo]
|
||||
func applyResolution(
|
||||
_ info: DisplayResolutionInfo,
|
||||
for displayID: CGDirectDisplayID
|
||||
) -> Result<Void, DisplayResolutionError>
|
||||
}
|
||||
|
||||
@MainActor
|
||||
final class DisplayResolutionController {
|
||||
private let displayProvider: DisplayProviding
|
||||
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "cc.ggbond.mactools", category: "DisplayResolutionController")
|
||||
|
||||
init(displayProvider: DisplayProviding = SystemDisplayService()) {
|
||||
self.displayProvider = displayProvider
|
||||
}
|
||||
|
||||
func listConnectedDisplays() -> [DisplayInfo] {
|
||||
displayProvider.listConnectedDisplays()
|
||||
}
|
||||
|
||||
func listAvailableResolutions(for displayID: CGDirectDisplayID) -> [DisplayResolutionInfo] {
|
||||
let options = [kCGDisplayShowDuplicateLowResolutionModes: kCFBooleanTrue] as CFDictionary
|
||||
guard let rawModes = CGDisplayCopyAllDisplayModes(displayID, options) as? [CGDisplayMode] else {
|
||||
logger.error("CGDisplayCopyAllDisplayModes returned nil for displayID \(displayID)")
|
||||
return []
|
||||
}
|
||||
|
||||
let currentID = CGDisplayCopyDisplayMode(displayID)?.ioDisplayModeID ?? 0
|
||||
|
||||
let candidates = rawModes.filter { mode in
|
||||
let flags = mode.ioFlags
|
||||
return mode.isUsableForDesktopGUI() && flags & DisplayModeFlags.safe != 0 && flags & DisplayModeFlags.notPreset == 0
|
||||
}
|
||||
|
||||
let infos = candidates.map { mode in
|
||||
let flags = mode.ioFlags
|
||||
return DisplayResolutionInfo(
|
||||
modeId: mode.ioDisplayModeID,
|
||||
width: mode.width,
|
||||
height: mode.height,
|
||||
pixelWidth: mode.pixelWidth,
|
||||
pixelHeight: mode.pixelHeight,
|
||||
refreshRate: mode.refreshRate,
|
||||
isHiDPI: mode.pixelWidth > mode.width,
|
||||
isNative: flags & DisplayModeFlags.native != 0,
|
||||
isDefault: flags & DisplayModeFlags.default != 0,
|
||||
isCurrent: mode.ioDisplayModeID == currentID
|
||||
)
|
||||
}
|
||||
return Self.sortModes(Self.deduplicateModes(infos))
|
||||
}
|
||||
|
||||
nonisolated static func deduplicateModes(_ modes: [DisplayResolutionInfo]) -> [DisplayResolutionInfo] {
|
||||
var bestByKey: [String: DisplayResolutionInfo] = [:]
|
||||
|
||||
for mode in modes {
|
||||
let key = deduplicationKey(for: mode)
|
||||
|
||||
if let existing = bestByKey[key] {
|
||||
bestByKey[key] = preferredMode(existing: existing, candidate: mode)
|
||||
} else {
|
||||
bestByKey[key] = mode
|
||||
}
|
||||
}
|
||||
|
||||
return Array(bestByKey.values)
|
||||
}
|
||||
|
||||
nonisolated static func sortModes(_ modes: [DisplayResolutionInfo]) -> [DisplayResolutionInfo] {
|
||||
modes.sorted {
|
||||
if $0.width != $1.width {
|
||||
return $0.width > $1.width
|
||||
}
|
||||
|
||||
if $0.height != $1.height {
|
||||
return $0.height > $1.height
|
||||
}
|
||||
|
||||
if $0.isCurrent != $1.isCurrent {
|
||||
return $0.isCurrent
|
||||
}
|
||||
|
||||
if $0.isHiDPI != $1.isHiDPI {
|
||||
return $0.isHiDPI
|
||||
}
|
||||
|
||||
return $0.refreshRate > $1.refreshRate
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func applyResolution(
|
||||
_ info: DisplayResolutionInfo,
|
||||
for displayID: CGDirectDisplayID
|
||||
) -> Result<Void, DisplayResolutionError> {
|
||||
guard let target = fetchCGDisplayMode(modeId: info.modeId, displayID: displayID) else {
|
||||
return .failure(.modeNotFound(modeId: info.modeId))
|
||||
}
|
||||
|
||||
var config: CGDisplayConfigRef?
|
||||
let beginError = CGBeginDisplayConfiguration(&config)
|
||||
guard beginError == .success, let config else {
|
||||
return .failure(.beginConfigFailed(beginError))
|
||||
}
|
||||
|
||||
let configureError = CGConfigureDisplayWithDisplayMode(config, displayID, target, nil)
|
||||
guard configureError == .success else {
|
||||
CGCancelDisplayConfiguration(config)
|
||||
return .failure(.configureFailed(configureError))
|
||||
}
|
||||
|
||||
let completeError = CGCompleteDisplayConfiguration(config, .permanently)
|
||||
guard completeError == .success else {
|
||||
return .failure(.completeFailed(completeError))
|
||||
}
|
||||
|
||||
return .success(())
|
||||
}
|
||||
|
||||
private func fetchCGDisplayMode(modeId: Int32, displayID: CGDirectDisplayID) -> CGDisplayMode? {
|
||||
let options = [kCGDisplayShowDuplicateLowResolutionModes: kCFBooleanTrue] as CFDictionary
|
||||
guard let modes = CGDisplayCopyAllDisplayModes(displayID, options) as? [CGDisplayMode] else {
|
||||
return nil
|
||||
}
|
||||
return modes.first(where: { $0.ioDisplayModeID == modeId })
|
||||
}
|
||||
|
||||
nonisolated private static func deduplicationKey(for mode: DisplayResolutionInfo) -> String {
|
||||
"\(mode.width)x\(mode.height)"
|
||||
}
|
||||
|
||||
nonisolated private static func preferredMode(
|
||||
existing: DisplayResolutionInfo,
|
||||
candidate: DisplayResolutionInfo
|
||||
) -> DisplayResolutionInfo {
|
||||
if existing.isCurrent != candidate.isCurrent {
|
||||
return existing.isCurrent ? existing : candidate
|
||||
}
|
||||
|
||||
if existing.isHiDPI != candidate.isHiDPI {
|
||||
return existing.isHiDPI ? existing : candidate
|
||||
}
|
||||
|
||||
return existing.refreshRate >= candidate.refreshRate ? existing : candidate
|
||||
}
|
||||
}
|
||||
|
||||
extension DisplayResolutionController: DisplayResolutionControlling {}
|
||||
Reference in New Issue
Block a user