Refactor and Rename to CommandNotch
This commit is contained in:
85
Downterm/CommandNotch/Extensions/NSScreen+Extensions.swift
Normal file
85
Downterm/CommandNotch/Extensions/NSScreen+Extensions.swift
Normal file
@@ -0,0 +1,85 @@
|
||||
import AppKit
|
||||
|
||||
extension NSScreen {
|
||||
|
||||
// MARK: - Stable display identifier
|
||||
|
||||
/// Returns a stable UUID string for this screen by querying CoreGraphics.
|
||||
/// Falls back to the localized name if the CG UUID is unavailable.
|
||||
var displayUUID: String {
|
||||
guard let screenNumber = deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? CGDirectDisplayID else {
|
||||
return localizedName
|
||||
}
|
||||
guard let uuid = CGDisplayCreateUUIDFromDisplayID(screenNumber) else {
|
||||
return localizedName
|
||||
}
|
||||
return CFUUIDCreateString(nil, uuid.takeUnretainedValue()) as String
|
||||
}
|
||||
|
||||
// MARK: - Notch detection
|
||||
|
||||
/// `true` when this screen has a physical camera notch (safe area inset at top > 0).
|
||||
var hasNotch: Bool {
|
||||
safeAreaInsets.top > 0
|
||||
}
|
||||
|
||||
// MARK: - Closed notch sizing
|
||||
|
||||
/// Computes the closed-state notch size for this screen,
|
||||
/// respecting the user's height mode and custom height preferences.
|
||||
func closedNotchSize() -> CGSize {
|
||||
let height = closedNotchHeight()
|
||||
let width = closedNotchWidth()
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
/// Height of the closed notch bar, determined by the user's chosen mode.
|
||||
private func closedNotchHeight() -> CGFloat {
|
||||
let defaults = UserDefaults.standard
|
||||
|
||||
if hasNotch {
|
||||
let mode = NotchHeightMode(rawValue: defaults.integer(forKey: NotchSettings.Keys.notchHeightMode))
|
||||
?? .matchRealNotchSize
|
||||
switch mode {
|
||||
case .matchRealNotchSize:
|
||||
return safeAreaInsets.top
|
||||
case .matchMenuBar:
|
||||
return menuBarHeight()
|
||||
case .custom:
|
||||
return defaults.double(forKey: NotchSettings.Keys.notchHeight)
|
||||
}
|
||||
} else {
|
||||
let mode = NonNotchHeightMode(rawValue: defaults.integer(forKey: NotchSettings.Keys.nonNotchHeightMode))
|
||||
?? .matchMenuBar
|
||||
switch mode {
|
||||
case .matchMenuBar:
|
||||
return menuBarHeight()
|
||||
case .custom:
|
||||
return defaults.double(forKey: NotchSettings.Keys.nonNotchHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Width of the closed notch.
|
||||
/// On notch screens, spans from one auxiliary top area to the other.
|
||||
/// On non-notch screens, uses a reasonable fixed width.
|
||||
private func closedNotchWidth() -> CGFloat {
|
||||
if hasNotch {
|
||||
if let topLeft = auxiliaryTopLeftArea,
|
||||
let topRight = auxiliaryTopRightArea {
|
||||
// The notch occupies the space between the two menu bar segments
|
||||
return frame.width - topLeft.width - topRight.width + 4
|
||||
}
|
||||
// Fallback for older API — approximate from safe area
|
||||
return 220
|
||||
} else {
|
||||
// Non-notch screens: a compact simulated notch
|
||||
return 220
|
||||
}
|
||||
}
|
||||
|
||||
/// The effective menu bar height for this screen.
|
||||
private func menuBarHeight() -> CGFloat {
|
||||
return frame.maxY - visibleFrame.maxY
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user