From 19ef0efa115c84112bb2a1920dc409956a1f3072 Mon Sep 17 00:00:00 2001
From: waydabber <37590873+waydabber@users.noreply.github.com>
Date: Tue, 10 Aug 2021 21:46:33 +0200
Subject: [PATCH] Stability and functionality improvements - Displays with
screens that are shadowed by a mirror are now controlled along with the
mirror master. - Fixed OSD when a display is shadowed by an uncontrollable
master (first potent shadowed will provide OSD) - Fixed scenario of constant
screen configuration changes (like when user closes and opens lid or
plugs/unplugs displays rapidly)
---
MonitorControl/AppDelegate.swift | 90 +++++++++++--------
MonitorControl/Info.plist | 2 +-
MonitorControl/Manager/DisplayManager.swift | 2 -
MonitorControl/Model/Display.swift | 19 +++-
MonitorControl/Model/ExternalDisplay.swift | 18 ++--
.../Support/de.lproj/Localizable.strings | 3 -
.../Support/en.lproj/Localizable.strings | 3 -
.../Support/fr.lproj/Localizable.strings | 3 -
.../Support/hu.lproj/Localizable.strings | 3 -
.../Support/it.lproj/Localizable.strings | 3 -
.../Support/ja.lproj/Localizable.strings | 3 -
.../Support/pl.lproj/Localizable.strings | 3 -
.../Support/ru.lproj/Localizable.strings | 3 -
.../Support/uk.lproj/Localizable.strings | 3 -
.../Support/zh-Hans.lproj/Localizable.strings | 3 -
MonitorControl/UI/SliderHandler.swift | 7 +-
MonitorControlHelper/Info.plist | 2 +-
17 files changed, 86 insertions(+), 84 deletions(-)
diff --git a/MonitorControl/AppDelegate.swift b/MonitorControl/AppDelegate.swift
index a3a4e7e..9f63fda 100644
--- a/MonitorControl/AppDelegate.swift
+++ b/MonitorControl/AppDelegate.swift
@@ -17,8 +17,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var keyRepeatTimers: [MediaKey: Timer] = [:]
let coreAudio = SimplyCoreAudio()
var accessibilityObserver: NSObjectProtocol!
- var willReconfigureDisplay: Bool = false // A reconfigure display command is already dispatched
- var displaySleep: Int = 0 // Don't reconfigure display as the system or display is sleeping or wake just recently.
+ var reconfigureID: Int = 0 // dispatched reconfigure command ID
+ var sleepID: Int = 0 // Don't reconfigure display as the system or display is sleeping or wake just recently.
lazy var preferencesWindowController: PreferencesWindowController = {
let storyboard = NSStoryboard(name: "Main", bundle: Bundle.main)
let mainPrefsVc = storyboard.instantiateController(withIdentifier: "MainPrefsVC") as? MainPrefsViewController
@@ -108,7 +108,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
func getDisplayName(displayID: CGDirectDisplayID) -> String {
let defaultName: String = NSLocalizedString("Unknown", comment: "Unknown display name") // + String(CGDisplaySerialNumber(displayID))
- if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], let name = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value {
+ if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], var name = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value {
+ if CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0 {
+ let mirroredDisplayID = CGDisplayMirrorsDisplay(displayID)
+ if mirroredDisplayID != 0, let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(mirroredDisplayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], let mirroredName = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value {
+ name.append("~" + mirroredName)
+ }
+ }
return name
}
if let screen = NSScreen.getByDisplayID(displayID: displayID) {
@@ -118,16 +124,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return screen.displayName ?? defaultName
}
}
- if CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0 {
- if let mirroredScreen = NSScreen.getByDisplayID(displayID: CGDisplayMirrorsDisplay(displayID)) {
- let name = NSLocalizedString("Mirror of", comment: "Shown in case a display mirrors an other display - like 'Mirror of DisplayName")
- if #available(OSX 10.15, *) {
- return "" + name + " " + String(mirroredScreen.localizedName)
- } else {
- return "" + name + " " + String(mirroredScreen.displayName ?? defaultName)
- }
- }
- }
return defaultName
}
@@ -155,21 +151,22 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func displayReconfigured() {
- if !self.willReconfigureDisplay, self.displaySleep == 0 {
- self.willReconfigureDisplay = true
- os_log("Display to be reconfigured via updateDisplay in 2 seconds", type: .info)
+ if self.sleepID == 0 {
+ self.reconfigureID += 1
+ let dispatchedReconfigureID = self.reconfigureID
+ os_log("Display to be reconfigured with reconfigureID %{public}@", type: .info, String(dispatchedReconfigureID))
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
- self.updateDisplays()
+ self.updateDisplays(dispatchedReconfigureID: dispatchedReconfigureID)
}
}
}
- func updateDisplays() {
- guard self.displaySleep == 0 else {
+ func updateDisplays(dispatchedReconfigureID: Int = 0) {
+ guard self.sleepID == 0, dispatchedReconfigureID == self.reconfigureID else {
return
}
- os_log("Request for updateDisplay", type: .info)
- self.willReconfigureDisplay = false
+ os_log("Request for updateDisplay with reconfigreID %{public}@", type: .info, String(dispatchedReconfigureID))
+ self.reconfigureID = 0
self.clearDisplays()
var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 10)
var displayCount: UInt32 = 0
@@ -286,24 +283,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
@objc private func sleepNotification() {
- self.displaySleep += 1
- os_log("Sleeping with sleep %{public}@", type: .info, String(self.displaySleep))
+ self.sleepID += 1
+ os_log("Sleeping with sleep %{public}@", type: .info, String(self.sleepID))
}
@objc private func wakeNotofication() {
- if self.displaySleep != 0 {
- os_log("Waking up from sleep %{public}@", type: .info, String(self.displaySleep))
- let sleepID = self.displaySleep
+ if self.sleepID != 0 {
+ os_log("Waking up from sleep %{public}@", type: .info, String(self.sleepID))
+ let dispatchedSleepID = self.sleepID
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) { // Some displays take time to recover...
- self.soberNow(sleepID: sleepID)
+ self.soberNow(dispatchedSleepID: dispatchedSleepID)
}
}
}
- private func soberNow(sleepID: Int) {
- if self.displaySleep == sleepID {
- os_log("Sober from sleep %{public}@", type: .info, String(self.displaySleep))
- self.displaySleep = 0
+ private func soberNow(dispatchedSleepID: Int) {
+ if self.sleepID == dispatchedSleepID {
+ os_log("Sober from sleep %{public}@", type: .info, String(self.sleepID))
+ self.sleepID = 0
self.updateDisplays()
}
}
@@ -345,7 +342,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
extension AppDelegate: MediaKeyTapDelegate {
func handle(mediaKey: MediaKey, event: KeyEvent?, modifiers: NSEvent.ModifierFlags?) {
- guard self.displaySleep == 0 && !self.willReconfigureDisplay else {
+ guard self.sleepID == 0, self.reconfigureID == 0 else {
return
}
if self.handleOpenPrefPane(mediaKey: mediaKey, event: event, modifiers: modifiers) {
@@ -375,20 +372,37 @@ extension AppDelegate: MediaKeyTapDelegate {
self.sendDisplayCommand(mediaKey: mediaKey, isRepeat: isRepeat, isSmallIncrement: isSmallIncrement)
}
+ private func getAffectedDisplays() -> [Display]? {
+ var affectedDisplays: [Display]
+ let allDisplays = DisplayManager.shared.getAllDisplays()
+ guard let currentDisplay = DisplayManager.shared.getCurrentDisplay() else {
+ return nil
+ }
+ // let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay]
+ if prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) {
+ affectedDisplays = allDisplays
+ } else {
+ affectedDisplays = [currentDisplay]
+ if CGDisplayIsInHWMirrorSet(currentDisplay.identifier) != 0 || CGDisplayIsInMirrorSet(currentDisplay.identifier) != 0, CGDisplayMirrorsDisplay(currentDisplay.identifier) == 0 {
+ for display in allDisplays where CGDisplayMirrorsDisplay(display.identifier) == currentDisplay.identifier {
+ affectedDisplays.append(display)
+ }
+ }
+ }
+ return affectedDisplays
+ }
+
private func sendDisplayCommand(mediaKey: MediaKey, isRepeat: Bool, isSmallIncrement: Bool) {
- guard self.displaySleep == 0, !self.willReconfigureDisplay else {
+ guard self.sleepID == 0, self.reconfigureID == 0, let affectedDisplays = self.getAffectedDisplays() else {
return
}
- let displays = DisplayManager.shared.getAllDisplays()
- guard let currentDisplay = DisplayManager.shared.getCurrentDisplay() else { return }
- let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay]
let delay = isRepeat ? 0.05 : 0 // Introduce a small delay to handle the media key being held down
var isAnyDisplayInContrastAfterBrightnessMode: Bool = false
- for display in allDisplays where (display as? ExternalDisplay)?.isContrastAfterBrightnessMode ?? false {
+ for display in affectedDisplays where (display as? ExternalDisplay)?.isContrastAfterBrightnessMode ?? false {
isAnyDisplayInContrastAfterBrightnessMode = true
}
self.keyRepeatTimers[mediaKey] = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { _ in
- for display in allDisplays where display.isEnabled && !display.isVirtual {
+ for display in affectedDisplays where display.isEnabled && !display.isVirtual {
switch mediaKey {
case .brightnessUp:
if !(isAnyDisplayInContrastAfterBrightnessMode && !((display as? ExternalDisplay)?.isContrastAfterBrightnessMode ?? false)) {
diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist
index 1981894..871f940 100644
--- a/MonitorControl/Info.plist
+++ b/MonitorControl/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- 1686
+ 1722
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
diff --git a/MonitorControl/Manager/DisplayManager.swift b/MonitorControl/Manager/DisplayManager.swift
index a5d99a7..f0d4d35 100644
--- a/MonitorControl/Manager/DisplayManager.swift
+++ b/MonitorControl/Manager/DisplayManager.swift
@@ -17,8 +17,6 @@ class DisplayManager {
self.displays = displays
}
- // cell.button.state = ((display as? ExternalDisplay)?.arm64ddc ?? false) ? .on : .off
-
func getExternalDisplays() -> [ExternalDisplay] {
return self.displays.compactMap { $0 as? ExternalDisplay }
}
diff --git a/MonitorControl/Model/Display.swift b/MonitorControl/Model/Display.swift
index 120232a..03c3284 100644
--- a/MonitorControl/Model/Display.swift
+++ b/MonitorControl/Model/Display.swift
@@ -51,6 +51,23 @@ class Display {
return self.prefs.string(forKey: "friendlyName-\(self.identifier)") ?? self.name
}
+ func getShowOsdDisplayId() -> CGDirectDisplayID {
+ if CGDisplayIsInHWMirrorSet(self.identifier) != 0 || CGDisplayIsInMirrorSet(self.identifier) != 0, CGDisplayMirrorsDisplay(self.identifier) != 0 {
+ for mirrorMaestro in DisplayManager.shared.getAllDisplays() where CGDisplayMirrorsDisplay(self.identifier) == mirrorMaestro.identifier {
+ if let externalMirrorMaestro = mirrorMaestro as? ExternalDisplay, !externalMirrorMaestro.arm64ddc, externalMirrorMaestro.ddc == nil {
+ var thereAreOthers = false
+ for mirrorMember in DisplayManager.shared.getAllDisplays() where CGDisplayMirrorsDisplay(mirrorMember.identifier) == CGDisplayMirrorsDisplay(self.identifier) && mirrorMember.identifier != self.identifier {
+ thereAreOthers = true
+ }
+ if !thereAreOthers {
+ return externalMirrorMaestro.identifier
+ }
+ }
+ }
+ }
+ return self.identifier
+ }
+
func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100, roundChiclet: Bool = false) {
guard let manager = OSDManager.sharedManager() as? OSDManager else {
return
@@ -80,7 +97,7 @@ class Display {
}
manager.showImage(osdImage.rawValue,
- onDisplayID: self.identifier,
+ onDisplayID: self.getShowOsdDisplayId(),
priority: 0x1F4,
msecUntilFade: 1000,
filledChiclets: UInt32(filledChiclets),
diff --git a/MonitorControl/Model/ExternalDisplay.swift b/MonitorControl/Model/ExternalDisplay.swift
index 4e4fece..fbcbcf6 100644
--- a/MonitorControl/Model/ExternalDisplay.swift
+++ b/MonitorControl/Model/ExternalDisplay.swift
@@ -187,13 +187,11 @@ class ExternalDisplay: Display {
}
if !self.isContrastAfterBrightnessMode {
let ddcValue = UInt16(osdValue)
- if !isAlreadySet {
- guard self.writeDDCValues(command: .brightness, value: ddcValue) == true else {
- return
- }
- if let slider = brightnessSliderHandler?.slider {
- slider.intValue = Int32(ddcValue)
- }
+ guard self.writeDDCValues(command: .brightness, value: ddcValue) == true else {
+ return
+ }
+ if let slider = brightnessSliderHandler?.slider {
+ slider.intValue = Int32(ddcValue)
}
self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement)
self.saveValue(osdValue, for: .brightness)
@@ -201,6 +199,9 @@ class ExternalDisplay: Display {
}
public func writeDDCValues(command: DDC.Command, value: UInt16, errorRecoveryWaitTime _: UInt32? = nil) -> Bool? {
+ guard app.sleepID == 0, app.reconfigureID == 0 else {
+ return false
+ }
if Arm64DDCUtils.isArm64 {
guard self.arm64ddc else {
return false
@@ -219,6 +220,9 @@ class ExternalDisplay: Display {
func readDDCValues(for command: DDC.Command, tries: UInt, minReplyDelay delay: UInt64?) -> (current: UInt16, max: UInt16)? {
var values: (UInt16, UInt16)?
+ guard app.sleepID == 0, app.reconfigureID == 0 else {
+ return values
+ }
if Arm64DDCUtils.isArm64 {
guard self.arm64ddc else {
return nil
diff --git a/MonitorControl/Support/de.lproj/Localizable.strings b/MonitorControl/Support/de.lproj/Localizable.strings
index 9308840..0b4814d 100644
--- a/MonitorControl/Support/de.lproj/Localizable.strings
+++ b/MonitorControl/Support/de.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Allgemein";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/en.lproj/Localizable.strings b/MonitorControl/Support/en.lproj/Localizable.strings
index 0b32fa2..ccb5aa4 100644
--- a/MonitorControl/Support/en.lproj/Localizable.strings
+++ b/MonitorControl/Support/en.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "General";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/fr.lproj/Localizable.strings b/MonitorControl/Support/fr.lproj/Localizable.strings
index f1f790a..ddc62ef 100644
--- a/MonitorControl/Support/fr.lproj/Localizable.strings
+++ b/MonitorControl/Support/fr.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Général";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/hu.lproj/Localizable.strings b/MonitorControl/Support/hu.lproj/Localizable.strings
index 7e4a2aa..6f5471e 100644
--- a/MonitorControl/Support/hu.lproj/Localizable.strings
+++ b/MonitorControl/Support/hu.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Általános";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Tükrözött";
-
/* Shown in the alert dialog */
"No" = "Nem";
diff --git a/MonitorControl/Support/it.lproj/Localizable.strings b/MonitorControl/Support/it.lproj/Localizable.strings
index 8bcb8f1..8316e32 100644
--- a/MonitorControl/Support/it.lproj/Localizable.strings
+++ b/MonitorControl/Support/it.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Generale";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/ja.lproj/Localizable.strings b/MonitorControl/Support/ja.lproj/Localizable.strings
index 310f752..e45b6ca 100644
--- a/MonitorControl/Support/ja.lproj/Localizable.strings
+++ b/MonitorControl/Support/ja.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "一般";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/pl.lproj/Localizable.strings b/MonitorControl/Support/pl.lproj/Localizable.strings
index 015025c..85d2595 100644
--- a/MonitorControl/Support/pl.lproj/Localizable.strings
+++ b/MonitorControl/Support/pl.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Ogólne";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "Nie";
diff --git a/MonitorControl/Support/ru.lproj/Localizable.strings b/MonitorControl/Support/ru.lproj/Localizable.strings
index e92a860..e348d7b 100644
--- a/MonitorControl/Support/ru.lproj/Localizable.strings
+++ b/MonitorControl/Support/ru.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Основные";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/uk.lproj/Localizable.strings b/MonitorControl/Support/uk.lproj/Localizable.strings
index 3fdcd1b..106627b 100644
--- a/MonitorControl/Support/uk.lproj/Localizable.strings
+++ b/MonitorControl/Support/uk.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "Загальні";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/Support/zh-Hans.lproj/Localizable.strings b/MonitorControl/Support/zh-Hans.lproj/Localizable.strings
index bce5233..8d3e70a 100644
--- a/MonitorControl/Support/zh-Hans.lproj/Localizable.strings
+++ b/MonitorControl/Support/zh-Hans.lproj/Localizable.strings
@@ -31,9 +31,6 @@
/* Shown in the main prefs window */
"General" = "通用";
-/* Shown in case a display mirrors an other display - like 'Mirror of DisplayName */
-"Mirror of" = "Mirror of";
-
/* Shown in the alert dialog */
"No" = "No";
diff --git a/MonitorControl/UI/SliderHandler.swift b/MonitorControl/UI/SliderHandler.swift
index 328ac93..b0b77c8 100644
--- a/MonitorControl/UI/SliderHandler.swift
+++ b/MonitorControl/UI/SliderHandler.swift
@@ -12,6 +12,9 @@ class SliderHandler {
}
@objc func valueChanged(slider: NSSlider) {
+ guard app.sleepID == 0, app.reconfigureID == 0 else {
+ return
+ }
let snapInterval = 25
let snapThreshold = 3
@@ -37,10 +40,6 @@ class SliderHandler {
}
}
- guard app.displaySleep == 0, !app.willReconfigureDisplay else {
- return
- }
-
_ = self.display.writeDDCValues(command: self.cmd, value: UInt16(value))
self.display.saveValue(value, for: self.cmd)
}
diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist
index a0964d2..00cb818 100644
--- a/MonitorControlHelper/Info.plist
+++ b/MonitorControlHelper/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- 1686
+ 1722
LSApplicationCategoryType
public.app-category.utilities
LSBackgroundOnly