mirror of
https://github.com/MonitorControl/MonitorControl.git
synced 2026-05-15 14:15:55 -06:00
Some additional fixes (#738)
- Fix naming of wakeNotification() - Fix for failing to update Advanced Settings checkbox on Preferences Reset. - Better handling of known dummy displays.
This commit is contained in:
parent
5d3d08ddfc
commit
6248d582ac
10 changed files with 70 additions and 26 deletions
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>6828</string>
|
||||
<string>6850</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
|||
|
|
@ -6,18 +6,24 @@ import os.log
|
|||
class AppleDisplay: Display {
|
||||
private var displayQueue: DispatchQueue
|
||||
|
||||
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) {
|
||||
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false, isDummy: Bool = false) {
|
||||
self.displayQueue = DispatchQueue(label: String("displayQueue-\(identifier)"))
|
||||
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
|
||||
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual, isDummy: isDummy)
|
||||
}
|
||||
|
||||
public func getAppleBrightness() -> Float {
|
||||
guard !self.isDummy else {
|
||||
return 1
|
||||
}
|
||||
var brightness: Float = 0
|
||||
DisplayServicesGetBrightness(self.identifier, &brightness)
|
||||
return brightness
|
||||
}
|
||||
|
||||
public func setAppleBrightness(value: Float) {
|
||||
guard !self.isDummy else {
|
||||
return
|
||||
}
|
||||
self.displayQueue.sync {
|
||||
DisplayServicesSetBrightness(self.identifier, value)
|
||||
DisplayServicesBrightnessChanged(self.identifier, Double(value))
|
||||
|
|
@ -25,6 +31,9 @@ class AppleDisplay: Display {
|
|||
}
|
||||
|
||||
override func setDirectBrightness(_ to: Float, transient: Bool = false) -> Bool {
|
||||
guard !self.isDummy else {
|
||||
return false
|
||||
}
|
||||
let value = max(min(to, 1), 0)
|
||||
self.setAppleBrightness(value: value)
|
||||
if !transient {
|
||||
|
|
@ -36,6 +45,9 @@ class AppleDisplay: Display {
|
|||
}
|
||||
|
||||
override func getBrightness() -> Float {
|
||||
guard !self.isDummy else {
|
||||
return 1
|
||||
}
|
||||
if self.prefExists(for: .brightness) {
|
||||
return self.readPrefAsFloat(for: .brightness)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class Display: Equatable {
|
|||
var sliderHandler: [Command: SliderHandler] = [:]
|
||||
var brightnessSyncSourceValue: Float = 1
|
||||
var isVirtual: Bool = false
|
||||
var isDummy: Bool = false
|
||||
|
||||
var defaultGammaTableRed = [CGGammaValue](repeating: 0, count: 256)
|
||||
var defaultGammaTableGreen = [CGGammaValue](repeating: 0, count: 256)
|
||||
|
|
@ -61,7 +62,7 @@ class Display: Equatable {
|
|||
return (key ?? PrefKey.value).rawValue + (command != nil ? String((command ?? Command.none).rawValue) : "") + self.prefsId
|
||||
}
|
||||
|
||||
internal init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) {
|
||||
internal init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false, isDummy: Bool = false) {
|
||||
self.identifier = identifier
|
||||
self.name = name
|
||||
self.vendorNumber = vendorNumber
|
||||
|
|
@ -69,13 +70,14 @@ class Display: Equatable {
|
|||
self.prefsId = "(" + String(name.filter { !$0.isWhitespace }) + String(vendorNumber ?? 0) + String(modelNumber ?? 0) + "@" + String(identifier) + ")"
|
||||
os_log("Display init with prefsIdentifier %{public}@", type: .info, self.prefsId)
|
||||
self.isVirtual = DEBUG_VIRTUAL ? true : isVirtual
|
||||
self.isDummy = isDummy
|
||||
self.swUpdateDefaultGammaTable()
|
||||
self.smoothBrightnessTransient = self.getBrightness()
|
||||
if self.isVirtual {
|
||||
os_log("Creating or updating shade for virtual display %{public}@", type: .info, String(self.identifier))
|
||||
if self.isVirtual || self.readPrefAsBool(key: PrefKey.avoidGamma), !self.isDummy {
|
||||
os_log("Creating or updating shade for display %{public}@", type: .info, String(self.identifier))
|
||||
_ = DisplayManager.shared.updateShade(displayID: self.identifier)
|
||||
} else {
|
||||
os_log("Destroying shade (if exists) for real display %{public}@", type: .info, String(self.identifier))
|
||||
os_log("Destroying shade (if exists) for display %{public}@", type: .info, String(self.identifier))
|
||||
_ = DisplayManager.shared.destroyShade(displayID: self.identifier)
|
||||
}
|
||||
self.brightnessSyncSourceValue = self.getBrightness()
|
||||
|
|
@ -187,6 +189,9 @@ class Display: Equatable {
|
|||
}
|
||||
|
||||
func swUpdateDefaultGammaTable() {
|
||||
guard !self.isDummy else {
|
||||
return
|
||||
}
|
||||
CGGetDisplayTransferByTable(self.identifier, 256, &self.defaultGammaTableRed, &self.defaultGammaTableGreen, &self.defaultGammaTableBlue, &self.defaultGammaTableSampleCount)
|
||||
let redPeak = self.defaultGammaTableRed.max() ?? 0
|
||||
let greenPeak = self.defaultGammaTableGreen.max() ?? 0
|
||||
|
|
@ -210,6 +215,10 @@ class Display: Equatable {
|
|||
if !noPrefSave {
|
||||
self.savePref(brightnessValue, key: .SwBrightness)
|
||||
}
|
||||
guard !self.isDummy else {
|
||||
self.swBrightnessSemaphore.signal()
|
||||
return true
|
||||
}
|
||||
var newValue = brightnessValue
|
||||
currentValue = self.swBrightnessTransform(value: currentValue)
|
||||
newValue = self.swBrightnessTransform(value: newValue)
|
||||
|
|
@ -249,6 +258,13 @@ class Display: Equatable {
|
|||
}
|
||||
|
||||
func getSwBrightness() -> Float {
|
||||
guard !self.isDummy else {
|
||||
if self.prefExists(key: .SwBrightness) {
|
||||
return self.readPrefAsFloat(key: .SwBrightness)
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
self.swBrightnessSemaphore.wait()
|
||||
if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) {
|
||||
let rawBrightnessValue = 1 - (DisplayManager.shared.getShadeAlpha(displayID: self.identifier) ?? 1)
|
||||
|
|
@ -274,7 +290,7 @@ class Display: Equatable {
|
|||
|
||||
func checkGammaInterference() {
|
||||
let currentSwBrightness = self.getSwBrightness()
|
||||
guard !DisplayManager.shared.gammaInterferenceWarningShown, !(prefs.bool(forKey: PrefKey.disableCombinedBrightness.rawValue)), !self.readPrefAsBool(key: .avoidGamma), !self.isVirtual, !self.smoothBrightnessRunning, self.prefExists(key: .SwBrightness), abs(currentSwBrightness - self.readPrefAsFloat(key: .SwBrightness)) > 0.02 else {
|
||||
guard !self.isDummy, !DisplayManager.shared.gammaInterferenceWarningShown, !(prefs.bool(forKey: PrefKey.disableCombinedBrightness.rawValue)), !self.readPrefAsBool(key: .avoidGamma), !self.isVirtual, !self.smoothBrightnessRunning, self.prefExists(key: .SwBrightness), abs(currentSwBrightness - self.readPrefAsFloat(key: .SwBrightness)) > 0.02 else {
|
||||
return
|
||||
}
|
||||
DisplayManager.shared.gammaInterferenceCounter += 1
|
||||
|
|
@ -309,7 +325,7 @@ class Display: Equatable {
|
|||
}
|
||||
|
||||
func isSwBrightnessNotDefault() -> Bool {
|
||||
guard !self.isVirtual else {
|
||||
guard !self.isVirtual, !self.isDummy else {
|
||||
return false
|
||||
}
|
||||
if self.getSwBrightness() < 1 {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ class OtherDisplay: Display {
|
|||
set { prefs.set(newValue, forKey: PrefKey.pollingCount.rawValue + self.prefsId) }
|
||||
}
|
||||
|
||||
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) {
|
||||
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
|
||||
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false, isDummy: Bool = false) {
|
||||
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual, isDummy: isDummy)
|
||||
if !isVirtual, !Arm64DDC.isArm64 {
|
||||
self.ddc = IntelDDC(for: identifier)
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ class OtherDisplay: Display {
|
|||
}
|
||||
|
||||
func isSwOnly() -> Bool {
|
||||
return (!self.arm64ddc && self.ddc == nil) || self.isVirtual
|
||||
return (!self.arm64ddc && self.ddc == nil) || self.isVirtual || self.isDummy
|
||||
}
|
||||
|
||||
func isSw() -> Bool {
|
||||
|
|
|
|||
|
|
@ -168,9 +168,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(self.audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil) // subscribe Audio output detector (SimplyCoreAudio)
|
||||
DistributedNotificationCenter.default.addObserver(self, selector: #selector(self.displayReconfigured), name: NSNotification.Name(rawValue: kColorSyncDisplayDeviceProfilesNotification.takeRetainedValue() as String), object: nil) // ColorSync change
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.screensDidSleepNotification, object: nil) // sleep and wake listeners
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotofication), name: NSWorkspace.screensDidWakeNotification, object: nil)
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotification), name: NSWorkspace.screensDidWakeNotification, object: nil)
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.willSleepNotification, object: nil)
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotofication), name: NSWorkspace.didWakeNotification, object: nil)
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotification), name: NSWorkspace.didWakeNotification, object: nil)
|
||||
_ = DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name(rawValue: NSNotification.Name.accessibilityApi.rawValue), object: nil, queue: nil) { _ in DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { self.updateMediaKeyTap() } } // listen for accessibility status changes
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
os_log("Sleeping with sleep %{public}@", type: .info, String(self.sleepID))
|
||||
}
|
||||
|
||||
@objc private func wakeNotofication() {
|
||||
@objc private func wakeNotification() {
|
||||
if self.sleepID != 0 {
|
||||
os_log("Waking up from sleep %{public}@", type: .info, String(self.sleepID))
|
||||
let dispatchedSleepID = self.sleepID
|
||||
|
|
|
|||
|
|
@ -271,6 +271,10 @@ class Arm64DDC: NSObject {
|
|||
if ioregService.manufacturerID == "AOC", ioregService.productName == "28E850" {
|
||||
return true
|
||||
}
|
||||
// If the display contains the string "Dummy", then it is highly suspicious
|
||||
if ioregService.productName.contains("Dummy") || ioregService.productName.contains("dummy") {
|
||||
return true
|
||||
}
|
||||
// First service location of Mac Mini HDMI is broken for DDC communication
|
||||
if ioregService.transportDownstream == "HDMI", ioregService.serviceLocation == 1, modelIdentifier == "Macmini9,1" {
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -151,27 +151,34 @@ class DisplayManager {
|
|||
return
|
||||
}
|
||||
for onlineDisplayID in onlineDisplayIDs where onlineDisplayID != 0 {
|
||||
let rawName = DisplayManager.getDisplayRawNameByID(displayID: onlineDisplayID)
|
||||
let name = DisplayManager.getDisplayNameByID(displayID: onlineDisplayID)
|
||||
let id = onlineDisplayID
|
||||
let vendorNumber = CGDisplayVendorNumber(onlineDisplayID)
|
||||
let modelNumber = CGDisplayModelNumber(onlineDisplayID)
|
||||
var isDummy: Bool = false
|
||||
var isVirtual: Bool = false
|
||||
if rawName == "28E850" || rawName.lowercased().contains("dummy") {
|
||||
os_log("NOTE: Display is a dummy!", type: .info)
|
||||
isDummy = true
|
||||
}
|
||||
if !DEBUG_MACOS10, #available(macOS 11.0, *) {
|
||||
if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(onlineDisplayID))?.takeRetainedValue() as NSDictionary?) {
|
||||
let isVirtualDevice = dictionary["kCGDisplayIsVirtualDevice"] as? Bool
|
||||
let displayIsAirplay = dictionary["kCGDisplayIsAirPlay"] as? Bool
|
||||
if isVirtualDevice ?? displayIsAirplay ?? false {
|
||||
os_log("NOTE: Display is virtual!", type: .info)
|
||||
isVirtual = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !DEBUG_SW, DisplayManager.isAppleDisplay(displayID: onlineDisplayID) { // MARK: (point of interest for testing)
|
||||
let appleDisplay = AppleDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
|
||||
os_log("Apple display found - %{public}@", type: .info, "ID: \(appleDisplay.identifier) Name: \(appleDisplay.name) (Vendor: \(appleDisplay.vendorNumber ?? 0), Model: \(appleDisplay.modelNumber ?? 0))")
|
||||
let appleDisplay = AppleDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual, isDummy: isDummy)
|
||||
os_log("Apple display found - %{public}@", type: .info, "ID: \(appleDisplay.identifier), Name: \(appleDisplay.name) (Vendor: \(appleDisplay.vendorNumber ?? 0), Model: \(appleDisplay.modelNumber ?? 0))")
|
||||
self.addDisplay(display: appleDisplay)
|
||||
} else {
|
||||
let otherDisplay = OtherDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
|
||||
os_log("Other display found - %{public}@", type: .info, "ID: \(otherDisplay.identifier) Name: \(otherDisplay.name) (Vendor: \(otherDisplay.vendorNumber ?? 0), Model: \(otherDisplay.modelNumber ?? 0))")
|
||||
let otherDisplay = OtherDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual, isDummy: isDummy)
|
||||
os_log("Other display found - %{public}@", type: .info, "ID: \(otherDisplay.identifier), Name: \(otherDisplay.name) (Vendor: \(otherDisplay.vendorNumber ?? 0), Model: \(otherDisplay.modelNumber ?? 0))")
|
||||
self.addDisplay(display: otherDisplay)
|
||||
}
|
||||
}
|
||||
|
|
@ -351,7 +358,7 @@ class DisplayManager {
|
|||
}
|
||||
}
|
||||
|
||||
func getAffectedDisplays(isBrightness: Bool = false, isVolume: Bool = false, isContrast _: Bool = false) -> [Display]? {
|
||||
func getAffectedDisplays(isBrightness: Bool = false, isVolume: Bool = false) -> [Display]? {
|
||||
var affectedDisplays: [Display]
|
||||
let allDisplays = self.getAllDisplays()
|
||||
var currentDisplay: Display?
|
||||
|
|
|
|||
|
|
@ -25,9 +25,13 @@ class DisplaysPrefsViewController: NSViewController, PreferencePane, NSTableView
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.showAdvancedDisplays.state = prefs.bool(forKey: PrefKey.showAdvancedSettings.rawValue) ? .on : .off
|
||||
self.loadDisplayList()
|
||||
self.displayScrollView.scrollerStyle = .legacy
|
||||
self.populateSettings()
|
||||
self.loadDisplayList()
|
||||
}
|
||||
|
||||
func populateSettings() {
|
||||
self.showAdvancedDisplays.state = prefs.bool(forKey: PrefKey.showAdvancedSettings.rawValue) ? .on : .off
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
|
|
@ -88,12 +92,12 @@ class DisplaysPrefsViewController: NSViewController, PreferencePane, NSTableView
|
|||
var displayImage = "display.trianglebadge.exclamationmark"
|
||||
var controlMethod = NSLocalizedString("No Control", comment: "Shown in the Display Preferences") + " ⚠️"
|
||||
var controlStatus = NSLocalizedString("This display has an unspecified control status.", comment: "Shown in the Display Preferences")
|
||||
if display.isVirtual {
|
||||
if display.isVirtual, !display.isDummy {
|
||||
displayType = NSLocalizedString("Virtual Display", comment: "Shown in the Display Preferences")
|
||||
displayImage = "tv.and.mediabox"
|
||||
controlMethod = NSLocalizedString("Software (shade)", comment: "Shown in the Display Preferences") + " ⚠️"
|
||||
controlStatus = NSLocalizedString("This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode.", comment: "Shown in the Display Preferences")
|
||||
} else if display is OtherDisplay {
|
||||
} else if display is OtherDisplay, !display.isDummy {
|
||||
displayType = NSLocalizedString("External Display", comment: "Shown in the Display Preferences")
|
||||
displayImage = "display"
|
||||
if let otherDisplay: OtherDisplay = display as? OtherDisplay {
|
||||
|
|
@ -119,7 +123,7 @@ class DisplaysPrefsViewController: NSViewController, PreferencePane, NSTableView
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if let appleDisplay: AppleDisplay = display as? AppleDisplay {
|
||||
} else if !display.isDummy, let appleDisplay: AppleDisplay = display as? AppleDisplay {
|
||||
if appleDisplay.isBuiltIn() {
|
||||
displayType = NSLocalizedString("Built-in Display", comment: "Shown in the Display Preferences")
|
||||
if self.isImac() {
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ class MainPrefsViewController: NSViewController, PreferencePane {
|
|||
self.populateSettings()
|
||||
menuslidersPrefsVc?.populateSettings()
|
||||
keyboardPrefsVc?.populateSettings()
|
||||
displaysPrefsVc?.populateSettings()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>6828</string>
|
||||
<string>6850</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue