From 3ccd9a4eae6227efa84555231566bd2a5f7472bb Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Tue, 2 Nov 2021 19:57:04 +0100 Subject: [PATCH 01/20] Unofficial support for 10.14 --- MonitorControl.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj index cdc9cba7..95fc229d 100644 --- a/MonitorControl.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -751,8 +751,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 4.0.0; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 4.0.1; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -786,8 +786,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 4.0.0; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 4.0.1; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -821,7 +821,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 10.14; MARKETING_VERSION = 4.0.1; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -850,7 +850,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 10.14; MARKETING_VERSION = 4.0.1; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper; PRODUCT_NAME = "$(TARGET_NAME)"; From b4e9b2e6edb77fcf2703b0814718e52772a711f4 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Tue, 2 Nov 2021 20:03:47 +0100 Subject: [PATCH 02/20] Updated readme --- README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 80793604..457fcf9a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

MonitorControl - for Apple Silicon and Intel

-

Controls your external display brightness and volume and shows native OSD.
+

Controls your external display brightness and volume and shows native OSD. Use menulet sliders or the keyboard, including native Apple keys!

Download for macOS
@@ -96,17 +96,22 @@ Note to f.lux users: the app is now compatible with [f.lux](https://justgetflux. ## Supported hardware -* Most modern LCD displays from all major manufacturers supported implemented DDC/CI protocol via DisplayPort, HDMI, USB-C or VGA to allow for hardware backlight control. -* Apple (and LG-Apple) displays and built-in displays are supported using native protocol. -* LCD and LED Televisions usually do not implement DDC, these are supported using software alternatives to dim the image (some higher-end sets are able to translate this into hardware backlight dimming). -* OLED or mini/micro-LED displays and televisions are fully supported using gamma table manipulation (this is a no-compromise solution for this class of displays). -* DisplayLink, Airplay and Sidecar are supported using shade (dark overlay) control. +- Most modern LCD displays from all major manufacturers supported implemented DDC/CI protocol via DisplayPort, HDMI, USB-C or VGA to allow for hardware backlight control. +- Apple (and LG-Apple) displays and built-in displays are supported using native protocol. +- LCD and LED Televisions usually do not implement DDC, these are supported using software alternatives to dim the image (some higher-end sets are able to translate this into hardware backlight dimming). +- OLED or mini/micro-LED displays and televisions are fully supported using gamma table manipulation (this is a no-compromise solution for this class of displays). +- DisplayLink, Airplay and Sidecar are supported using shade (dark overlay) control. + +Dummy compatibility: + +- The app is compatible with [BetterDummy](https://github.com/waydabber/BetterDummy) mirrored sets. +- The app is compatible with mirrored sets that include a dummy dongle identifying as `28E850` Notable exceptions for hardware control: -* Some displays (notably EIZO) use MCCS over USB or an entirely custom protocol for control. These displays are supported with software dimming only. -* The HDMI port of the 2018 Intel Mac mini and 2020 M1 Mac mini prohibit DDC communication. Software control is still available. We recommend connecting the display via the USB-C port (USB-C to HDMI dongles usually work). -* DisplayLink docks and dongles do not allow for DDC control on Macs, only software dimming is available for these connections. +- Some displays (notably EIZO) use MCCS over USB or an entirely custom protocol for control. These displays are supported with software dimming only. +- The HDMI port of the 2018 Intel Mac mini and 2020 M1 Mac mini prohibit DDC communication. Software control is still available. We recommend connecting the display via the USB-C port (USB-C to HDMI dongles usually work). +- DisplayLink docks and dongles do not allow for DDC control on Macs, only software dimming is available for these connections. ## How to help From 4aea8a1752f9bfc70f1c68aa077e0b9e848ff117 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Tue, 2 Nov 2021 20:08:20 +0100 Subject: [PATCH 03/20] Updated readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 457fcf9a..00bcece7 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and Screenshot
-## Compatibility +## macOS compatibility | MonitorControl version | macOS version | | ---------------------- | ----------------- | @@ -92,9 +92,7 @@ Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and _* With some limitations - full functionality available on macOS 11 Big Sur or newer._ -Note to f.lux users: the app is now compatible with [f.lux](https://justgetflux.com) as well - please activate `Avoid gamma table manipulation` under `Preferences` » `Displays`! This step is not needed if you use Night Shift. - -## Supported hardware +## Supported displays - Most modern LCD displays from all major manufacturers supported implemented DDC/CI protocol via DisplayPort, HDMI, USB-C or VGA to allow for hardware backlight control. - Apple (and LG-Apple) displays and built-in displays are supported using native protocol. @@ -107,12 +105,14 @@ Dummy compatibility: - The app is compatible with [BetterDummy](https://github.com/waydabber/BetterDummy) mirrored sets. - The app is compatible with mirrored sets that include a dummy dongle identifying as `28E850` -Notable exceptions for hardware control: +Notable exceptions for hardware control compatibility: - Some displays (notably EIZO) use MCCS over USB or an entirely custom protocol for control. These displays are supported with software dimming only. - The HDMI port of the 2018 Intel Mac mini and 2020 M1 Mac mini prohibit DDC communication. Software control is still available. We recommend connecting the display via the USB-C port (USB-C to HDMI dongles usually work). - DisplayLink docks and dongles do not allow for DDC control on Macs, only software dimming is available for these connections. +Note to f.lux users - please activate `Avoid gamma table manipulation` under `Preferences` » `Displays`! This step is not needed if you use Night Shift. + ## How to help Open [issues](https://github.com/MonitorControl/MonitorControl/issues) if you have a question, an enhancement to suggest or a bug you've found. If you want, you can fork the code yourself and submit a pull request to improve the app. From 0e5d649026d9bafe34c0e326e03a16044477ab98 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Tue, 2 Nov 2021 20:14:27 +0100 Subject: [PATCH 04/20] Updated code for compatibility with 10.14 --- MonitorControl/Info.plist | 2 +- MonitorControl/Support/DisplayManager.swift | 6 +++++- MonitorControlHelper/Info.plist | 2 +- README.md | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 1c3560c6..d92f3fec 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6851 + 6855 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index c98c4762..b1eb1e30 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -485,7 +485,11 @@ class DisplayManager { } } if let screen = getByDisplayID(displayID: displayID) { // MARK: This, and NSScreen+Extension.swift will not be needed when we drop MacOS 10 support. - return screen.localizedName + if #available(macOS 10.15, *) { + return screen.localizedName + } else { + return screen.displayName ?? defaultName + } } return defaultName } diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index a30473e1..80d65e6a 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6851 + 6855 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly diff --git a/README.md b/README.md index 00bcece7..8a43efc1 100644 --- a/README.md +++ b/README.md @@ -76,10 +76,10 @@ Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and ## Screenshots (Preferences)
-Screenshot -Screenshot
-Screenshot -Screenshot
+Screenshot +Screenshot +Screenshot +Screenshot
## macOS compatibility From 00dc8ff460c029d08a8db0d94732be99d9bdda0f Mon Sep 17 00:00:00 2001 From: Istvan T <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 11:39:07 +0100 Subject: [PATCH 05/20] Update .swiftlint.yml --- .swiftlint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 92526482..7cc44deb 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -4,7 +4,7 @@ disabled_rules: - identifier_name - trailing_comma type_body_length: 500 -file_length: 500 +file_length: 750 cyclomatic_complexity: ignores_case_statements: true opening_brace: From 057b8e1ba76e119a516be81bc0da2b7a4684f87f Mon Sep 17 00:00:00 2001 From: Istvan T <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 11:41:33 +0100 Subject: [PATCH 06/20] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8a43efc1..763d1241 100644 --- a/README.md +++ b/README.md @@ -76,10 +76,10 @@ Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and ## Screenshots (Preferences)
-Screenshot -Screenshot -Screenshot -Screenshot +Screenshot +Screenshot +Screenshot +Screenshot
## macOS compatibility From c8f3337420ceb546e050939e4209a3261d504287 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 11:53:06 +0100 Subject: [PATCH 07/20] Working on fixes --- MonitorControl.xcodeproj/project.pbxproj | 16 ++++++++-------- MonitorControl/Info.plist | 2 +- MonitorControl/Support/DisplayManager.swift | 16 ++++++++++------ MonitorControlHelper/Info.plist | 2 +- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj index 95fc229d..4dedd779 100644 --- a/MonitorControl.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -736,11 +736,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = MonitorControl/MonitorControlDebug.entitlements; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1179; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 299YSU96J7; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PROJECT_DIR)/**", @@ -771,11 +771,11 @@ buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1179; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 299YSU96J7; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PROJECT_DIR)/**", @@ -809,11 +809,11 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 631; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 299YSU96J7; ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = MonitorControlHelper/Info.plist; @@ -838,11 +838,11 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 631; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 299YSU96J7; ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = MonitorControlHelper/Info.plist; diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index d92f3fec..bfba4ef2 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6855 + 6866 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index b1eb1e30..5af17a15 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -142,6 +142,15 @@ class DisplayManager { return false } + func isTreatedAsDummy(displayID: CGDirectDisplayID) -> Bool { + let rawName = DisplayManager.getDisplayRawNameByID(displayID: displayID) + if rawName == "28E850" || rawName.lowercased().contains("dummy") { + os_log("NOTE: Display is a dummy!", type: .info) + return true + } + return false + } + func configureDisplays() { self.clearDisplays() var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 16) @@ -151,17 +160,12 @@ 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 + let isDummy: Bool = isTreatedAsDummy(displayID: onlineDisplayID) 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 diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 80d65e6a..89d8ea30 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6855 + 6866 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From f90e2085f415196a91ed51876132b8dee45226e8 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 17:40:00 +0100 Subject: [PATCH 08/20] Async DDC write + much smoother DDC sliders --- MonitorControl/Info.plist | 2 +- MonitorControl/Model/OtherDisplay.swift | 57 ++++++++++++---------- MonitorControl/Support/SliderHandler.swift | 4 +- MonitorControlHelper/Info.plist | 2 +- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index bfba4ef2..377be7cc 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6866 + 6889 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/OtherDisplay.swift b/MonitorControl/Model/OtherDisplay.swift index f95afcc7..a4654a2e 100644 --- a/MonitorControl/Model/OtherDisplay.swift +++ b/MonitorControl/Model/OtherDisplay.swift @@ -76,11 +76,11 @@ class OtherDisplay: Display { if !self.smoothBrightnessRunning, !self.isSw(), !self.readPrefAsBool(key: .unavailableDDC, for: command), self.readPrefAsBool(key: .isTouched, for: command), prefs.integer(forKey: PrefKey.startupAction.rawValue) == StartupAction.write.rawValue, !app.safeMode { let restoreValue = self.getDDCValueFromPrefs(command) os_log("Restoring %{public}@ DDC value %{public}@ for %{public}@", type: .info, String(reflecting: command), String(restoreValue), self.name) - _ = self.writeDDCValues(command: command, value: restoreValue) + self.writeDDCValues(command: command, value: restoreValue) if command == .audioSpeakerVolume, self.readPrefAsBool(key: .enableMuteUnmute) { let currentMuteValue = self.readPrefAsInt(for: .audioMuteScreenBlank) == 0 ? 2 : self.readPrefAsInt(for: .audioMuteScreenBlank) os_log("- Writing last saved DDC value for Mute: %{public}@", type: .info, String(currentMuteValue)) - _ = self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(currentMuteValue)) + self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(currentMuteValue)) } } } @@ -178,13 +178,11 @@ class OtherDisplay: Display { let isAlreadySet = volumeOSDValue == self.readPrefAsFloat(for: .audioSpeakerVolume) if !isAlreadySet { if let muteValue = muteValue, self.readPrefAsBool(key: .enableMuteUnmute) { - guard self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else { - return - } + self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) self.savePref(muteValue, for: .audioMuteScreenBlank) } if !self.readPrefAsBool(key: .enableMuteUnmute) || volumeOSDValue != 0 { - _ = self.writeDDCValues(command: .audioSpeakerVolume, value: self.convValueToDDC(for: .audioSpeakerVolume, from: volumeOSDValue)) + self.writeDDCValues(command: .audioSpeakerVolume, value: self.convValueToDDC(for: .audioSpeakerVolume, from: volumeOSDValue)) } } if !self.readPrefAsBool(key: .hideOsd) { @@ -206,7 +204,7 @@ class OtherDisplay: Display { let contrastOSDValue = self.calcNewValue(currentValue: currentValue, isUp: isUp, isSmallIncrement: isSmallIncrement) let isAlreadySet = contrastOSDValue == self.readPrefAsFloat(for: .contrast) if !isAlreadySet { - _ = self.writeDDCValues(command: .contrast, value: self.convValueToDDC(for: .contrast, from: contrastOSDValue)) + self.writeDDCValues(command: .contrast, value: self.convValueToDDC(for: .contrast, from: contrastOSDValue)) } OSDUtils.showOsd(displayID: self.identifier, command: .contrast, value: contrastOSDValue, roundChiclet: !isSmallIncrement) if !isAlreadySet { @@ -237,13 +235,11 @@ class OtherDisplay: Display { } } if self.readPrefAsBool(key: .enableMuteUnmute) { - guard self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else { - return - } + self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) } self.savePref(muteValue, for: .audioMuteScreenBlank) if !self.readPrefAsBool(key: .enableMuteUnmute) || volumeOSDValue > 0 { - _ = self.writeDDCValues(command: .audioSpeakerVolume, value: self.convValueToDDC(for: .audioSpeakerVolume, from: volumeOSDValue)) + self.writeDDCValues(command: .audioSpeakerVolume, value: self.convValueToDDC(for: .audioSpeakerVolume, from: volumeOSDValue)) } if !fromVolumeSlider { if !self.readPrefAsBool(key: .hideOsd) { @@ -345,12 +341,12 @@ class OtherDisplay: Display { brightnessValue = 0 brightnessSwValue = (value / self.combinedBrightnessSwitchingValue()) } - _ = self.writeDDCValues(command: .brightness, value: self.convValueToDDC(for: .brightness, from: brightnessValue)) + self.writeDDCValues(command: .brightness, value: self.convValueToDDC(for: .brightness, from: brightnessValue)) if self.readPrefAsFloat(key: .SwBrightness) != brightnessSwValue { _ = self.setSwBrightness(brightnessSwValue) } } else { - _ = self.writeDDCValues(command: .brightness, value: self.convValueToDDC(for: .brightness, from: value)) + self.writeDDCValues(command: .brightness, value: self.convValueToDDC(for: .brightness, from: value)) } if !transient { self.savePref(value, for: .brightness) @@ -378,28 +374,39 @@ class OtherDisplay: Display { return intCodes } - public func writeDDCValues(command: Command, value: UInt16, errorRecoveryWaitTime _: UInt32? = nil) -> Bool? { + var writeDDCNextValue: [Command: UInt16] = [:] + var writeDDCLastSavedValue: [Command: UInt16] = [:] + + public func writeDDCValues(command: Command, value: UInt16) { guard app.sleepID == 0, app.reconfigureID == 0, !self.readPrefAsBool(key: .forceSw), !self.readPrefAsBool(key: .unavailableDDC, for: command) else { - return false + return + } + self.writeDDCNextValue[command] = value + DisplayManager.shared.ddcQueue.async { + self.asyncPerformWriteDDCValues(command: command) } - var success: Bool = false + } + + func asyncPerformWriteDDCValues(command: Command) { + let value = self.writeDDCNextValue[command] ?? 100 + guard value != self.writeDDCLastSavedValue[command] else { + return + } + self.writeDDCLastSavedValue[command] = value + self.savePref(true, key: PrefKey.isTouched, for: command) var controlCodes = self.getRemapControlCodes(command: command) if controlCodes.count == 0 { controlCodes.append(command.rawValue) } for controlCode in controlCodes { - DisplayManager.shared.ddcQueue.sync { - if Arm64DDC.isArm64 { - if self.arm64ddc { - success = Arm64DDC.write(service: self.arm64avService, command: controlCode, value: value) - } - } else { - success = self.ddc?.write(command: command.rawValue, value: value, errorRecoveryWaitTime: 2000) ?? false + if Arm64DDC.isArm64 { + if self.arm64ddc { + _ = Arm64DDC.write(service: self.arm64avService, command: controlCode, value: value) } - self.savePref(true, key: PrefKey.isTouched, for: command) // We deliberatly consider the value tuched no matter if the call succeeded + } else { + _ = self.ddc?.write(command: command.rawValue, value: value, errorRecoveryWaitTime: 2000) ?? false } } - return success } func readDDCValues(for command: Command, tries: UInt, minReplyDelay delay: UInt64?) -> (current: UInt16, max: UInt16)? { diff --git a/MonitorControl/Support/SliderHandler.swift b/MonitorControl/Support/SliderHandler.swift index 51fcb09f..a1c2cc4e 100644 --- a/MonitorControl/Support/SliderHandler.swift +++ b/MonitorControl/Support/SliderHandler.swift @@ -295,10 +295,10 @@ class SliderHandler { } else if !otherDisplay.isSw() { if self.command == Command.audioSpeakerVolume { if !otherDisplay.readPrefAsBool(key: .enableMuteUnmute) || value != 0 { - _ = otherDisplay.writeDDCValues(command: self.command, value: otherDisplay.convValueToDDC(for: self.command, from: value)) + otherDisplay.writeDDCValues(command: self.command, value: otherDisplay.convValueToDDC(for: self.command, from: value)) } } else { - _ = otherDisplay.writeDDCValues(command: self.command, value: otherDisplay.convValueToDDC(for: self.command, from: value)) + otherDisplay.writeDDCValues(command: self.command, value: otherDisplay.convValueToDDC(for: self.command, from: value)) } otherDisplay.savePref(value, for: self.command) } diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 89d8ea30..c8caf963 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6866 + 6889 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 7ff0ebf8fe9b8227e69403fc0e58fb3c55369aa5 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 18:32:08 +0100 Subject: [PATCH 09/20] Made async stuff thread safe... --- MonitorControl/Info.plist | 2 +- MonitorControl/Model/OtherDisplay.swift | 25 +++++++++++++++++-------- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 377be7cc..2b03b58f 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6889 + 6893 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/OtherDisplay.swift b/MonitorControl/Model/OtherDisplay.swift index a4654a2e..eac783a1 100644 --- a/MonitorControl/Model/OtherDisplay.swift +++ b/MonitorControl/Model/OtherDisplay.swift @@ -22,6 +22,9 @@ class OtherDisplay: Display { } set { prefs.set(newValue, forKey: PrefKey.pollingCount.rawValue + self.prefsId) } } + let writeDDCQueue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent) + var writeDDCNextValue: [Command: UInt16] = [:] + var writeDDCLastSavedValue: [Command: UInt16] = [:] 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) @@ -374,26 +377,32 @@ class OtherDisplay: Display { return intCodes } - var writeDDCNextValue: [Command: UInt16] = [:] - var writeDDCLastSavedValue: [Command: UInt16] = [:] - public func writeDDCValues(command: Command, value: UInt16) { guard app.sleepID == 0, app.reconfigureID == 0, !self.readPrefAsBool(key: .forceSw), !self.readPrefAsBool(key: .unavailableDDC, for: command) else { return } - self.writeDDCNextValue[command] = value + self.writeDDCQueue.async(flags: .barrier) { + self.writeDDCNextValue[command] = value + } DisplayManager.shared.ddcQueue.async { self.asyncPerformWriteDDCValues(command: command) } } func asyncPerformWriteDDCValues(command: Command) { - let value = self.writeDDCNextValue[command] ?? 100 - guard value != self.writeDDCLastSavedValue[command] else { + var value = UInt16.max + var lastValue = UInt16.max + self.writeDDCQueue.sync { + value = self.writeDDCNextValue[command] ?? UInt16.max + lastValue = self.writeDDCLastSavedValue[command] ?? UInt16.max + } + guard value != UInt16.max, value != lastValue else { return } - self.writeDDCLastSavedValue[command] = value - self.savePref(true, key: PrefKey.isTouched, for: command) + self.writeDDCQueue.async(flags: .barrier) { + self.writeDDCLastSavedValue[command] = value + self.savePref(true, key: PrefKey.isTouched, for: command) + } var controlCodes = self.getRemapControlCodes(command: command) if controlCodes.count == 0 { controlCodes.append(command.rawValue) diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index c8caf963..a36d6aa0 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6889 + 6893 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From e3b79b862092b1ede76d0dd67076e0bced10c585 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 20:41:35 +0100 Subject: [PATCH 10/20] Identify points to fix for virtual-virtual mirror shading scenario --- MonitorControl/Info.plist | 2 +- MonitorControl/Model/OtherDisplay.swift | 1 + MonitorControl/Support/DisplayManager.swift | 23 ++++++++++++--------- MonitorControlHelper/Info.plist | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 2b03b58f..c75f94f8 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6893 + 6896 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/OtherDisplay.swift b/MonitorControl/Model/OtherDisplay.swift index eac783a1..c3a80002 100644 --- a/MonitorControl/Model/OtherDisplay.swift +++ b/MonitorControl/Model/OtherDisplay.swift @@ -22,6 +22,7 @@ class OtherDisplay: Display { } set { prefs.set(newValue, forKey: PrefKey.pollingCount.rawValue + self.prefsId) } } + let writeDDCQueue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent) var writeDDCNextValue: [Command: UInt16] = [:] var writeDDCLastSavedValue: [Command: UInt16] = [:] diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index 5af17a15..28c60f58 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -44,6 +44,7 @@ class DisplayManager { internal var shadeGrave: [NSWindow] = [] func isDisqualifiedFromShade(_ displayID: CGDirectDisplayID) -> Bool { // We ban mirror members from shade control as it might lead to double control + // TODO: Fix scenario of virtual->virtual mirrors to support BetterDummy return (CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0) ? true : false } @@ -142,15 +143,6 @@ class DisplayManager { return false } - func isTreatedAsDummy(displayID: CGDirectDisplayID) -> Bool { - let rawName = DisplayManager.getDisplayRawNameByID(displayID: displayID) - if rawName == "28E850" || rawName.lowercased().contains("dummy") { - os_log("NOTE: Display is a dummy!", type: .info) - return true - } - return false - } - func configureDisplays() { self.clearDisplays() var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 16) @@ -164,7 +156,7 @@ class DisplayManager { let id = onlineDisplayID let vendorNumber = CGDisplayVendorNumber(onlineDisplayID) let modelNumber = CGDisplayModelNumber(onlineDisplayID) - let isDummy: Bool = isTreatedAsDummy(displayID: onlineDisplayID) + let isDummy: Bool = DisplayManager.isTreatedAsDummy(displayID: onlineDisplayID) var isVirtual: Bool = false if !DEBUG_MACOS10, #available(macOS 11.0, *) { if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(onlineDisplayID))?.takeRetainedValue() as NSDictionary?) { @@ -395,6 +387,17 @@ class DisplayManager { return affectedDisplays } + static func isTreatedAsDummy(displayID: CGDirectDisplayID) -> Bool { + let rawName = DisplayManager.getDisplayRawNameByID(displayID: displayID) + var isDummy: Bool = false + if rawName == "28E850" || rawName.lowercased().contains("dummy") { + os_log("NOTE: Display is a dummy!", type: .info) + isDummy = false + } + // TODO: Fix scenario of virtual->virtual mirrors to support BetterDummy + return isDummy + } + static func engageMirror() -> Bool { var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 16) var displayCount: UInt32 = 0 diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index a36d6aa0..e56dde4d 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6893 + 6896 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 3a4f8acdcc882cd2979722f44395e8fd7098277d Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Wed, 3 Nov 2021 23:54:25 +0100 Subject: [PATCH 11/20] Better support for virtual->virtual and dummy->virtual scenarios (needs more testing) --- MonitorControl/Info.plist | 2 +- MonitorControl/Model/Display.swift | 6 +-- MonitorControl/Support/DisplayManager.swift | 50 ++++++++++++++------- MonitorControlHelper/Info.plist | 2 +- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index c75f94f8..56a75084 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6896 + 6904 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/Display.swift b/MonitorControl/Model/Display.swift index b68e5186..0563b501 100644 --- a/MonitorControl/Model/Display.swift +++ b/MonitorControl/Model/Display.swift @@ -230,7 +230,7 @@ class Display: Equatable { return } if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) { - _ = DisplayManager.shared.setShadeAlpha(value: 1 - transientValue, displayID: self.identifier) + _ = DisplayManager.shared.setShadeAlpha(value: 1 - transientValue, displayID: DisplayManager.resolveEffectiveDisplayID(self.identifier)) } else { let gammaTableRed = self.defaultGammaTableRed.map { $0 * transientValue } let gammaTableGreen = self.defaultGammaTableGreen.map { $0 * transientValue } @@ -243,7 +243,7 @@ class Display: Equatable { } else { if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) { self.swBrightnessSemaphore.signal() - return DisplayManager.shared.setShadeAlpha(value: 1 - newValue, displayID: self.identifier) + return DisplayManager.shared.setShadeAlpha(value: 1 - newValue, displayID: DisplayManager.resolveEffectiveDisplayID(self.identifier)) } else { let gammaTableRed = self.defaultGammaTableRed.map { $0 * newValue } let gammaTableGreen = self.defaultGammaTableGreen.map { $0 * newValue } @@ -267,7 +267,7 @@ class Display: Equatable { } self.swBrightnessSemaphore.wait() if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) { - let rawBrightnessValue = 1 - (DisplayManager.shared.getShadeAlpha(displayID: self.identifier) ?? 1) + let rawBrightnessValue = 1 - (DisplayManager.shared.getShadeAlpha(displayID: DisplayManager.resolveEffectiveDisplayID(self.identifier)) ?? 1) self.swBrightnessSemaphore.signal() return self.swBrightnessTransform(value: rawBrightnessValue, reverse: true) } diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index 28c60f58..4a63982f 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -43,9 +43,22 @@ class DisplayManager { internal var shades: [CGDirectDisplayID: NSWindow] = [:] internal var shadeGrave: [NSWindow] = [] - func isDisqualifiedFromShade(_ displayID: CGDirectDisplayID) -> Bool { // We ban mirror members from shade control as it might lead to double control - // TODO: Fix scenario of virtual->virtual mirrors to support BetterDummy - return (CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0) ? true : false + func isDisqualifiedFromShade(_ displayID: CGDirectDisplayID) -> Bool { + if CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0 { + if displayID == DisplayManager.resolveEffectiveDisplayID(displayID), DisplayManager.isVirtual(displayID: displayID) || DisplayManager.isDummy(displayID: displayID) { + var displayIDs = [CGDirectDisplayID](repeating: 0, count: 16) + var displayCount: UInt32 = 0 + guard CGGetOnlineDisplayList(16, &displayIDs, &displayCount) == .success else { + return true + } + for displayId in displayIDs where CGDisplayMirrorsDisplay(displayId) == displayID && !DisplayManager.isVirtual(displayID: displayID) { + return true + } + return false + } + return true + } + return false } internal func createShadeOnDisplay(displayID: CGDirectDisplayID) -> NSWindow? { @@ -156,18 +169,8 @@ class DisplayManager { let id = onlineDisplayID let vendorNumber = CGDisplayVendorNumber(onlineDisplayID) let modelNumber = CGDisplayModelNumber(onlineDisplayID) - let isDummy: Bool = DisplayManager.isTreatedAsDummy(displayID: onlineDisplayID) - var isVirtual: Bool = false - 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 - } - } - } + let isDummy: Bool = DisplayManager.isDummy(displayID: onlineDisplayID) + let isVirtual: Bool = DisplayManager.isVirtual(displayID: onlineDisplayID) 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, isDummy: isDummy) os_log("Apple display found - %{public}@", type: .info, "ID: \(appleDisplay.identifier), Name: \(appleDisplay.name) (Vendor: \(appleDisplay.vendorNumber ?? 0), Model: \(appleDisplay.modelNumber ?? 0))") @@ -387,17 +390,30 @@ class DisplayManager { return affectedDisplays } - static func isTreatedAsDummy(displayID: CGDirectDisplayID) -> Bool { + static func isDummy(displayID: CGDirectDisplayID) -> Bool { let rawName = DisplayManager.getDisplayRawNameByID(displayID: displayID) var isDummy: Bool = false if rawName == "28E850" || rawName.lowercased().contains("dummy") { os_log("NOTE: Display is a dummy!", type: .info) isDummy = false } - // TODO: Fix scenario of virtual->virtual mirrors to support BetterDummy return isDummy } + static func isVirtual(displayID: CGDirectDisplayID) -> Bool { + var isVirtual: Bool = false + if !DEBUG_MACOS10, #available(macOS 11.0, *) { + if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary?) { + let isVirtualDevice = dictionary["kCGDisplayIsVirtualDevice"] as? Bool + let displayIsAirplay = dictionary["kCGDisplayIsAirPlay"] as? Bool + if isVirtualDevice ?? displayIsAirplay ?? false { + isVirtual = true + } + } + } + return isVirtual + } + static func engageMirror() -> Bool { var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 16) var displayCount: UInt32 = 0 diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index e56dde4d..b00a2ce5 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6896 + 6904 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 8c00f8d28a552e70aa0f238aa6140811761f37e6 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 00:02:10 +0100 Subject: [PATCH 12/20] Fixed display reset settings disabling Use hardware DDC --- MonitorControl/Info.plist | 2 +- MonitorControl/View Controllers/DisplaysPrefsCellView.swift | 2 +- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 56a75084..064780ba 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6904 + 6905 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/View Controllers/DisplaysPrefsCellView.swift b/MonitorControl/View Controllers/DisplaysPrefsCellView.swift index 7bc4e8df..ccb0d9ec 100644 --- a/MonitorControl/View Controllers/DisplaysPrefsCellView.swift +++ b/MonitorControl/View Controllers/DisplaysPrefsCellView.swift @@ -359,7 +359,7 @@ class DisplaysPrefsCellView: NSTableCellView { self.ddcButton.state = .on self.ddcButtonToggled(self.ddcButton) self.avoidGamma.state = .off - self.ddcButtonToggled(self.avoidGamma) + self.avoidGamma(self.avoidGamma) self.disableVolumeOSDButton.state = .off self.disableVolumeOSDButton(self.disableVolumeOSDButton) self.pollingModeMenu.selectItem(withTag: 2) diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index b00a2ce5..844dd21d 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6904 + 6905 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From d087ada7d239bfe15ee7c706dd694270f14b6fb7 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:11:28 +0100 Subject: [PATCH 13/20] Fixed custom control codes on Intel --- MonitorControl/Info.plist | 2 +- MonitorControl/Model/OtherDisplay.swift | 2 +- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 064780ba..566b10bc 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6905 + 6906 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/OtherDisplay.swift b/MonitorControl/Model/OtherDisplay.swift index c3a80002..8d7a45ae 100644 --- a/MonitorControl/Model/OtherDisplay.swift +++ b/MonitorControl/Model/OtherDisplay.swift @@ -414,7 +414,7 @@ class OtherDisplay: Display { _ = Arm64DDC.write(service: self.arm64avService, command: controlCode, value: value) } } else { - _ = self.ddc?.write(command: command.rawValue, value: value, errorRecoveryWaitTime: 2000) ?? false + _ = self.ddc?.write(command: controlCode, value: value, errorRecoveryWaitTime: 2000) ?? false } } } diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 844dd21d..97ec5a48 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6905 + 6906 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 4e49ceb19c0daf932c9c6417e64b3695096d9cf5 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:01:47 +0100 Subject: [PATCH 14/20] Further improvement in Dummy and Mirrored virtual display scenario --- MonitorControl/Info.plist | 2 +- MonitorControl/Model/OtherDisplay.swift | 13 ++++++------- MonitorControl/Support/DisplayManager.swift | 6 +++--- MonitorControl/Support/MenuHandler.swift | 2 +- MonitorControlHelper/Info.plist | 2 +- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 566b10bc..b525e467 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6906 + 6924 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/OtherDisplay.swift b/MonitorControl/Model/OtherDisplay.swift index 8d7a45ae..9c95cb58 100644 --- a/MonitorControl/Model/OtherDisplay.swift +++ b/MonitorControl/Model/OtherDisplay.swift @@ -9,6 +9,9 @@ class OtherDisplay: Display { var arm64ddc: Bool = false var arm64avService: IOAVService? var isDiscouraged: Bool = false + let writeDDCQueue = DispatchQueue(label: "Local write DDC queue") + var writeDDCNextValue: [Command: UInt16] = [:] + var writeDDCLastSavedValue: [Command: UInt16] = [:] var pollingCount: Int { get { switch self.readPrefAsInt(key: .pollingMode) { @@ -23,10 +26,6 @@ class OtherDisplay: Display { set { prefs.set(newValue, forKey: PrefKey.pollingCount.rawValue + self.prefsId) } } - let writeDDCQueue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent) - var writeDDCNextValue: [Command: UInt16] = [:] - var writeDDCLastSavedValue: [Command: UInt16] = [:] - 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 { @@ -385,7 +384,7 @@ class OtherDisplay: Display { self.writeDDCQueue.async(flags: .barrier) { self.writeDDCNextValue[command] = value } - DisplayManager.shared.ddcQueue.async { + DisplayManager.shared.globalDDCQueue.async(flags: .barrier) { self.asyncPerformWriteDDCValues(command: command) } } @@ -430,7 +429,7 @@ class OtherDisplay: Display { guard self.arm64ddc else { return nil } - DisplayManager.shared.ddcQueue.sync { + DisplayManager.shared.globalDDCQueue.sync { if let unwrappedDelay = delay { values = Arm64DDC.read(service: self.arm64avService, command: controlCode, tries: UInt8(min(tries, 255)), minReplyDelay: UInt32(unwrappedDelay / 1000)) } else { @@ -438,7 +437,7 @@ class OtherDisplay: Display { } } } else { - DisplayManager.shared.ddcQueue.sync { + DisplayManager.shared.globalDDCQueue.sync { values = self.ddc?.read(command: controlCode, tries: tries, minReplyDelay: delay) } } diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index 4a63982f..b2468763 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -9,7 +9,7 @@ class DisplayManager { var displays: [Display] = [] var audioControlTargetDisplays: [OtherDisplay] = [] - let ddcQueue = DispatchQueue(label: "DDC queue") + let globalDDCQueue = DispatchQueue(label: "Global DDC queue") let gammaActivityEnforcer = NSWindow(contentRect: .init(origin: NSPoint(x: 0, y: 0), size: .init(width: DEBUG_GAMMA_ENFORCER ? 15 : 1, height: DEBUG_GAMMA_ENFORCER ? 15 : 1)), styleMask: [], backing: .buffered, defer: false) var gammaInterferenceCounter = 0 var gammaInterferenceWarningShown = false @@ -395,7 +395,7 @@ class DisplayManager { var isDummy: Bool = false if rawName == "28E850" || rawName.lowercased().contains("dummy") { os_log("NOTE: Display is a dummy!", type: .info) - isDummy = false + isDummy = true } return isDummy } @@ -501,7 +501,7 @@ class DisplayManager { 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) + name.append(" | " + mirroredName) } } return name diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index 2a61c19c..22e30eb8 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -177,7 +177,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { let title = NSLocalizedString("Brightness", comment: "Shown in menu") addedSliderHandlers.append(self.setupMenuSliderHandler(command: .brightness, display: display, title: title)) } - if prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.combine.rawValue { + if prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.combine.rawValue, !(display.isDummy && prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.separate.rawValue) { self.addDisplayMenuBlock(addedSliderHandlers: addedSliderHandlers, blockName: display.readPrefAsString(key: .friendlyName) != "" ? display.readPrefAsString(key: .friendlyName) : display.name, monitorSubMenu: monitorSubMenu, numOfDisplays: numOfDisplays, asSubMenu: asSubMenu) } if addedSliderHandlers.count > 0, prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.sliderOnly.rawValue { diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 97ec5a48..7b38822a 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6906 + 6924 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 1e210632c05f44974de199a5e5dbb363e8748fd2 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:11:22 +0100 Subject: [PATCH 15/20] Better support for dummies, hide them from menu --- MonitorControl/Info.plist | 2 +- MonitorControl/Support/MenuHandler.swift | 4 ++-- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index b525e467..ca0dd2b2 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6924 + 6928 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index 22e30eb8..43712509 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -43,7 +43,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { if numOfDisplays != 0 { let asSubMenu: Bool = (displays.count > 3 && !relevant && !combine && app.macOS10()) ? true : false var iterator = 0 - for display in displays where !relevant || display == currentDisplay { + for display in displays where !relevant || DisplayManager.resolveEffectiveDisplayID(display.identifier) == DisplayManager.resolveEffectiveDisplayID(currentDisplay!.identifier) { iterator += 1 if !relevant, !combine, iterator != 1, app.macOS10() { self.insertItem(NSMenuItem.separator(), at: 0) @@ -177,7 +177,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { let title = NSLocalizedString("Brightness", comment: "Shown in menu") addedSliderHandlers.append(self.setupMenuSliderHandler(command: .brightness, display: display, title: title)) } - if prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.combine.rawValue, !(display.isDummy && prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.separate.rawValue) { + if prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.combine.rawValue, !(display.isDummy) { self.addDisplayMenuBlock(addedSliderHandlers: addedSliderHandlers, blockName: display.readPrefAsString(key: .friendlyName) != "" ? display.readPrefAsString(key: .friendlyName) : display.name, monitorSubMenu: monitorSubMenu, numOfDisplays: numOfDisplays, asSubMenu: asSubMenu) } if addedSliderHandlers.count > 0, prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.sliderOnly.rawValue { diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 7b38822a..9a259758 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6924 + 6928 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 5ff66e2a0d8adf6b56657663b3c08e6ba1719aa3 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:32:16 +0100 Subject: [PATCH 16/20] Further improved support for dummies --- MonitorControl/Info.plist | 2 +- MonitorControl/Support/MenuHandler.swift | 9 ++++++--- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index ca0dd2b2..bbe8f31a 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6928 + 6934 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index 43712509..8fb652d9 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -39,11 +39,14 @@ class MenuHandler: NSMenu, NSMenuDelegate { displays.append(contentsOf: DisplayManager.shared.getOtherDisplays()) let relevant = prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.relevant.rawValue let combine = prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.combine.rawValue - let numOfDisplays = displays.count + var numOfDisplays = 0 + for display in displays { + numOfDisplays += display.isDummy ? 0 : 1 + } if numOfDisplays != 0 { let asSubMenu: Bool = (displays.count > 3 && !relevant && !combine && app.macOS10()) ? true : false var iterator = 0 - for display in displays where !relevant || DisplayManager.resolveEffectiveDisplayID(display.identifier) == DisplayManager.resolveEffectiveDisplayID(currentDisplay!.identifier) { + for display in displays where (!relevant || DisplayManager.resolveEffectiveDisplayID(display.identifier) == DisplayManager.resolveEffectiveDisplayID(currentDisplay!.identifier)) && !display.isDummy { iterator += 1 if !relevant, !combine, iterator != 1, app.macOS10() { self.insertItem(NSMenuItem.separator(), at: 0) @@ -177,7 +180,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { let title = NSLocalizedString("Brightness", comment: "Shown in menu") addedSliderHandlers.append(self.setupMenuSliderHandler(command: .brightness, display: display, title: title)) } - if prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.combine.rawValue, !(display.isDummy) { + if prefs.integer(forKey: PrefKey.multiSliders.rawValue) != MultiSliders.combine.rawValue { self.addDisplayMenuBlock(addedSliderHandlers: addedSliderHandlers, blockName: display.readPrefAsString(key: .friendlyName) != "" ? display.readPrefAsString(key: .friendlyName) : display.name, monitorSubMenu: monitorSubMenu, numOfDisplays: numOfDisplays, asSubMenu: asSubMenu) } if addedSliderHandlers.count > 0, prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.sliderOnly.rawValue { diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 9a259758..ec8f04fa 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6928 + 6934 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From 1d8c1c2031659b8cd637c657f91181e7763f45f7 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:42:25 +0100 Subject: [PATCH 17/20] Update readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 763d1241..f7d3e01c 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and - Modern, stylish and highly customizable menulet reflecting the design of Control Control introduced in Big Sur. - Simple, unobstrusive UI to blend in to the general aesthetics of macOS (even the menu icon can be hidden). - Supports automatic updates for a hassle-free experience. -- The best app of its kind, completely FREE (donations accepted) with the source code transparently available! +- The best app of its kind, completely FREE ([donations welcome](https://opencollective.com/monitorcontrol)) with the source code transparently available! ## How to install and use the app @@ -115,7 +115,9 @@ Note to f.lux users - please activate `Avoid gamma table manipulation` under `Pr ## How to help -Open [issues](https://github.com/MonitorControl/MonitorControl/issues) if you have a question, an enhancement to suggest or a bug you've found. If you want, you can fork the code yourself and submit a pull request to improve the app. +- You can greatly help out [by financing the project with your donation or by being a Sponsor](https://opencollective.com/monitorcontrol)! +- Open [issues](https://github.com/MonitorControl/MonitorControl/issues) if you have a question, an enhancement to suggest or a bug you've found. +- If you want, you can fork the code yourself and submit a pull request to improve the app (Note: accepting a PR is solely in the collective hands of the maintainers). ## Localizations From 603aed364bb6f8501118f909e2c9a9e385cebcb1 Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:00:17 +0100 Subject: [PATCH 18/20] Fix black background upon space change with shade dimming --- MonitorControl/Info.plist | 2 +- MonitorControl/Support/DisplayManager.swift | 11 +++++++---- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index bbe8f31a..8dfe861d 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6934 + 6940 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index b2468763..f4269721 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -66,13 +66,16 @@ class DisplayManager { let shade = NSWindow(contentRect: .init(origin: NSPoint(x: 0, y: 0), size: .init(width: 10, height: 1)), styleMask: [], backing: .buffered, defer: false) shade.title = "Monitor Control Window Shade for Display " + String(displayID) shade.isMovableByWindowBackground = false - shade.backgroundColor = .black + shade.backgroundColor = .clear shade.ignoresMouseEvents = true shade.level = NSWindow.Level(rawValue: Int(CGShieldingWindowLevel())) - shade.alphaValue = 0 shade.orderFrontRegardless() shade.collectionBehavior = [.stationary, .canJoinAllSpaces, .ignoresCycle] shade.setFrame(screen.frame, display: true) + shade.contentView?.wantsLayer = true + shade.contentView?.alphaValue = 0.0 + shade.contentView?.layer?.backgroundColor = .black + shade.contentView?.setNeedsDisplay(shade.frame) os_log("Window shade created for display %{public}@", type: .info, String(displayID)) return shade } @@ -139,7 +142,7 @@ class DisplayManager { return 1 } if let shade = getShade(displayID: displayID) { - return Float(shade.alphaValue) + return Float(shade.contentView?.alphaValue ?? 1) } else { return 1 } @@ -150,7 +153,7 @@ class DisplayManager { return false } if let shade = getShade(displayID: displayID) { - shade.alphaValue = CGFloat(value) + shade.contentView?.alphaValue = CGFloat(value) return true } return false diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index ec8f04fa..5f34fa15 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6934 + 6940 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From aed8b6af2f844f9f69e267ce32fad3014e218fdc Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:37:20 +0100 Subject: [PATCH 19/20] Fix signing --- MonitorControl.xcodeproj/project.pbxproj | 16 ++++++++-------- MonitorControl/Info.plist | 2 +- MonitorControlHelper/Info.plist | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj index 4dedd779..95fc229d 100644 --- a/MonitorControl.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -736,11 +736,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = MonitorControl/MonitorControlDebug.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1179; - DEVELOPMENT_TEAM = 299YSU96J7; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PROJECT_DIR)/**", @@ -771,11 +771,11 @@ buildSettings = { ARCHS = "$(ARCHS_STANDARD)"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1179; - DEVELOPMENT_TEAM = 299YSU96J7; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PROJECT_DIR)/**", @@ -809,11 +809,11 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 631; - DEVELOPMENT_TEAM = 299YSU96J7; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = MonitorControlHelper/Info.plist; @@ -838,11 +838,11 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 631; - DEVELOPMENT_TEAM = 299YSU96J7; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = MonitorControlHelper/Info.plist; diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 8dfe861d..1b6ff213 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6940 + 6941 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 5f34fa15..955c2f9d 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 6940 + 6941 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From f8f2d5e118386125adb930f61db90412d7f01a67 Mon Sep 17 00:00:00 2001 From: Istvan T <37590873+waydabber@users.noreply.github.com> Date: Thu, 4 Nov 2021 17:52:06 +0100 Subject: [PATCH 20/20] Update MenuHandler.swift --- MonitorControl/Support/MenuHandler.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index 8fb652d9..34615a7f 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -39,10 +39,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { displays.append(contentsOf: DisplayManager.shared.getOtherDisplays()) let relevant = prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.relevant.rawValue let combine = prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.combine.rawValue - var numOfDisplays = 0 - for display in displays { - numOfDisplays += display.isDummy ? 0 : 1 - } + let numOfDisplays = displays.filter { !$0.isDummy }.count if numOfDisplays != 0 { let asSubMenu: Bool = (displays.count > 3 && !relevant && !combine && app.macOS10()) ? true : false var iterator = 0