Skip to content

Commit 0a502c7

Browse files
authored
Watch for gamma table interference from external app (#696)
1 parent fade88a commit 0a502c7

File tree

22 files changed

+236
-9
lines changed

22 files changed

+236
-9
lines changed

.github/screenshot.png

-55.7 KB
Loading

MonitorControl/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<key>CFBundleShortVersionString</key>
2020
<string>$(MARKETING_VERSION)</string>
2121
<key>CFBundleVersion</key>
22-
<string>6581</string>
22+
<string>6632</string>
2323
<key>LSApplicationCategoryType</key>
2424
<string>public.app-category.utilities</string>
2525
<key>LSMinimumSystemVersion</key>

MonitorControl/Model/Display.swift

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Display: Equatable {
1313
internal var smoothBrightnessTransient: Float = 1
1414
internal var smoothBrightnessRunning: Bool = false
1515
internal var smoothBrightnessSlow: Bool = false
16+
let swBrightnessSemaphore = DispatchSemaphore(value: 1)
1617

1718
static func == (lhs: Display, rhs: Display) -> Bool {
1819
return lhs.identifier == rhs.identifier
@@ -199,8 +200,8 @@ class Display: Equatable {
199200
}
200201
}
201202

202-
let swBrightnessSemaphore = DispatchSemaphore(value: 1)
203203
func setSwBrightness(_ value: Float, smooth: Bool = false) -> Bool {
204+
self.swBrightnessSemaphore.wait()
204205
let brightnessValue = min(1, value)
205206
var currentValue = self.readPrefAsFloat(key: .SwBrightness)
206207
self.savePref(brightnessValue, key: .SwBrightness)
@@ -209,9 +210,9 @@ class Display: Equatable {
209210
newValue = self.swBrightnessTransform(value: newValue)
210211
if smooth {
211212
DispatchQueue.global(qos: .userInteractive).async {
212-
self.swBrightnessSemaphore.wait()
213213
for transientValue in stride(from: currentValue, to: newValue, by: 0.005 * (currentValue > newValue ? -1 : 1)) {
214214
guard app.reconfigureID == 0 else {
215+
self.swBrightnessSemaphore.signal()
215216
return
216217
}
217218
if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) {
@@ -224,10 +225,10 @@ class Display: Equatable {
224225
}
225226
Thread.sleep(forTimeInterval: 0.001) // Let's make things quick if not performed in the background
226227
}
227-
self.swBrightnessSemaphore.signal()
228228
}
229229
} else {
230230
if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) {
231+
self.swBrightnessSemaphore.signal()
231232
return DisplayManager.shared.setShadeAlpha(value: 1 - newValue, displayID: self.identifier)
232233
} else {
233234
let gammaTableRed = self.defaultGammaTableRed.map { $0 * newValue }
@@ -238,28 +239,64 @@ class Display: Equatable {
238239
DisplayManager.shared.enforceGammaActivity()
239240
}
240241
}
242+
self.swBrightnessSemaphore.signal()
241243
return true
242244
}
243245

244246
func getSwBrightness() -> Float {
247+
self.swBrightnessSemaphore.wait()
245248
if self.isVirtual || self.readPrefAsBool(key: .avoidGamma) {
246249
let rawBrightnessValue = 1 - (DisplayManager.shared.getShadeAlpha(displayID: self.identifier) ?? 1)
250+
self.swBrightnessSemaphore.signal()
247251
return self.swBrightnessTransform(value: rawBrightnessValue, reverse: true)
248252
}
249253
var gammaTableRed = [CGGammaValue](repeating: 0, count: 256)
250254
var gammaTableGreen = [CGGammaValue](repeating: 0, count: 256)
251255
var gammaTableBlue = [CGGammaValue](repeating: 0, count: 256)
252256
var gammaTableSampleCount: UInt32 = 0
257+
var brightnessValue: Float = 1
253258
if CGGetDisplayTransferByTable(self.identifier, 256, &gammaTableRed, &gammaTableGreen, &gammaTableBlue, &gammaTableSampleCount) == CGError.success {
254259
let redPeak = gammaTableRed.max() ?? 0
255260
let greenPeak = gammaTableGreen.max() ?? 0
256261
let bluePeak = gammaTableBlue.max() ?? 0
257262
let gammaTablePeak = max(redPeak, greenPeak, bluePeak)
258263
let peakRatio = gammaTablePeak / self.defaultGammaTablePeak
259-
let brightnessValue = round(self.swBrightnessTransform(value: peakRatio, reverse: true) * 256) / 256
260-
return brightnessValue
264+
brightnessValue = round(self.swBrightnessTransform(value: peakRatio, reverse: true) * 256) / 256
265+
}
266+
self.swBrightnessSemaphore.signal()
267+
return brightnessValue
268+
}
269+
270+
func checkGammaInterference() {
271+
let currentSwBrightness = self.getSwBrightness()
272+
guard !DisplayManager.shared.gammaInterferenceWarningShown, !(prefs.bool(forKey: PrefKey.disableSoftwareFallback.rawValue) && prefs.bool(forKey: PrefKey.disableCombinedBrightness.rawValue)), !self.readPrefAsBool(key: .avoidGamma), !self.smoothBrightnessRunning, self.prefExists(key: .SwBrightness), abs(currentSwBrightness - self.readPrefAsFloat(key: .SwBrightness)) > 0.02 else {
273+
return
274+
}
275+
DisplayManager.shared.gammaInterferenceCounter += 1
276+
_ = self.setSwBrightness(1)
277+
os_log("Gamma table interference detected, number of events: %{public}@", type: .debug, String(DisplayManager.shared.gammaInterferenceCounter))
278+
if DisplayManager.shared.gammaInterferenceCounter >= 3 {
279+
DisplayManager.shared.gammaInterferenceWarningShown = true
280+
let alert = NSAlert()
281+
alert.messageText = NSLocalizedString("Is f.lux or similar running?", comment: "Shown in the alert dialog")
282+
alert.informativeText = NSLocalizedString("An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!", comment: "Shown in the alert dialog")
283+
alert.addButton(withTitle: NSLocalizedString("I'll quit the other app", comment: "Shown in the alert dialog"))
284+
alert.addButton(withTitle: NSLocalizedString("Disable gamma control for my displays", comment: "Shown in the alert dialog"))
285+
alert.alertStyle = NSAlert.Style.critical
286+
if alert.runModal() != .alertFirstButtonReturn {
287+
for otherDisplay in DisplayManager.shared.getOtherDisplays() {
288+
_ = otherDisplay.setSwBrightness(1)
289+
_ = otherDisplay.setDirectBrightness(1)
290+
otherDisplay.savePref(true, key: .avoidGamma)
291+
_ = otherDisplay.setSwBrightness(1)
292+
DisplayManager.shared.gammaInterferenceWarningShown = false
293+
DisplayManager.shared.gammaInterferenceCounter = 0
294+
displaysPrefsVc?.loadDisplayList()
295+
}
296+
} else {
297+
os_log("We won't watch for gamma table interference anymore", type: .debug)
298+
}
261299
}
262-
return 1
263300
}
264301

265302
func resetSwBrightness() -> Bool {

MonitorControl/Model/OtherDisplay.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ class OtherDisplay: Display {
327327
}
328328
}
329329

330+
override func setBrightness(_ to: Float = -1, slow: Bool = false) -> Bool {
331+
self.checkGammaInterference()
332+
return super.setBrightness(to, slow: slow)
333+
}
334+
330335
override func setDirectBrightness(_ to: Float, transient: Bool = false) -> Bool {
331336
let value = max(min(to, 1), 0)
332337
if !self.isSw() {
@@ -341,7 +346,9 @@ class OtherDisplay: Display {
341346
brightnessSwValue = (value / self.combinedBrightnessSwitchingValue())
342347
}
343348
_ = self.writeDDCValues(command: .brightness, value: self.convValueToDDC(for: .brightness, from: brightnessValue))
344-
_ = self.setSwBrightness(brightnessSwValue)
349+
if self.readPrefAsFloat(key: .SwBrightness) != brightnessSwValue {
350+
_ = self.setSwBrightness(brightnessSwValue)
351+
}
345352
} else {
346353
_ = self.writeDDCValues(command: .brightness, value: self.convValueToDDC(for: .brightness, from: value))
347354
}

MonitorControl/Support/AppDelegate.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
131131
}
132132
os_log("Request for configuration with reconfigreID %{public}@", type: .info, String(dispatchedReconfigureID))
133133
self.reconfigureID = 0
134+
DisplayManager.shared.gammaInterferenceCounter = 0
134135
DisplayManager.shared.configureDisplays()
135136
DisplayManager.shared.addDisplayCounterSuffixes()
136137
DisplayManager.shared.updateArm64AVServices()

MonitorControl/Support/DisplayManager.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class DisplayManager {
1111
var audioControlTargetDisplays: [OtherDisplay] = []
1212
let ddcQueue = DispatchQueue(label: "DDC queue")
1313
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)
14+
var gammaInterferenceCounter = 0
15+
var gammaInterferenceWarningShown = false
1416

1517
func createGammaActivityEnforcer() {
1618
self.gammaActivityEnforcer.title = "Monior Control Gamma Activity Enforcer"

MonitorControl/UI/de.lproj/Localizable.strings

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* Shown in the main prefs window */
22
"About" = "Über";
33

4+
/* Shown in the alert dialog */
5+
"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!";
6+
47
/* Shown in the main prefs window */
58
"App menu" = "App Menü";
69

@@ -34,6 +37,9 @@
3437
/* Shown in record shortcut box */
3538
"Decrease" = "Verringern";
3639

40+
/* Shown in the alert dialog */
41+
"Disable gamma control for my displays" = "Disable gamma control for my displays";
42+
3743
/* Shown in the main prefs window */
3844
"Displays" = "Monitore";
3945

@@ -52,6 +58,9 @@
5258
/* Shown in the Display Preferences */
5359
"Hardware (DDC)" = "Hardware (DDC)";
5460

61+
/* Shown in the alert dialog */
62+
"I'll quit the other app" = "I'll quit the other app";
63+
5564
/* Shown in the alert dialog */
5665
"Incompatible previous version" = "Inkompatible Vorgängerversion";
5766

@@ -61,6 +70,9 @@
6170
/* Intel designation (shown after the version number in Preferences) */
6271
"Intel" = "Intel";
6372

73+
/* Shown in the alert dialog */
74+
"Is f.lux or similar running?" = "Is f.lux or similar running?";
75+
6476
/* Shown in the main prefs window */
6577
"Keyboard" = "Tastatur";
6678

MonitorControl/UI/en.lproj/Localizable.strings

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* Shown in the main prefs window */
22
"About" = "About";
33

4+
/* Shown in the alert dialog */
5+
"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!";
6+
47
/* Shown in the main prefs window */
58
"App menu" = "App menu";
69

@@ -34,6 +37,9 @@
3437
/* Shown in record shortcut box */
3538
"Decrease" = "Decrease";
3639

40+
/* Shown in the alert dialog */
41+
"Disable gamma control for my displays" = "Disable gamma control for my displays";
42+
3743
/* Shown in the main prefs window */
3844
"Displays" = "Displays";
3945

@@ -52,6 +58,9 @@
5258
/* Shown in the Display Preferences */
5359
"Hardware (DDC)" = "Hardware (DDC)";
5460

61+
/* Shown in the alert dialog */
62+
"I'll quit the other app" = "I'll quit the other app";
63+
5564
/* Shown in the alert dialog */
5665
"Incompatible previous version" = "Incompatible previous version";
5766

@@ -61,6 +70,9 @@
6170
/* Intel designation (shown after the version number in Preferences) */
6271
"Intel" = "Intel";
6372

73+
/* Shown in the alert dialog */
74+
"Is f.lux or similar running?" = "Is f.lux or similar running?";
75+
6476
/* Shown in the main prefs window */
6577
"Keyboard" = "Keyboard";
6678

MonitorControl/UI/es-419.lproj/Localizable.strings

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* Shown in the main prefs window */
22
"About" = "Acerca de";
33

4+
/* Shown in the alert dialog */
5+
"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!";
6+
47
/* Shown in the main prefs window */
58
"App menu" = "App menu";
69

@@ -34,6 +37,9 @@
3437
/* Shown in record shortcut box */
3538
"Decrease" = "Decrease";
3639

40+
/* Shown in the alert dialog */
41+
"Disable gamma control for my displays" = "Disable gamma control for my displays";
42+
3743
/* Shown in the main prefs window */
3844
"Displays" = "Pantallas";
3945

@@ -52,6 +58,9 @@
5258
/* Shown in the Display Preferences */
5359
"Hardware (DDC)" = "Hardware (DDC)";
5460

61+
/* Shown in the alert dialog */
62+
"I'll quit the other app" = "I'll quit the other app";
63+
5564
/* Shown in the alert dialog */
5665
"Incompatible previous version" = "Incompatible previous version";
5766

@@ -61,6 +70,9 @@
6170
/* Intel designation (shown after the version number in Preferences) */
6271
"Intel" = "Intel";
6372

73+
/* Shown in the alert dialog */
74+
"Is f.lux or similar running?" = "Is f.lux or similar running?";
75+
6476
/* Shown in the main prefs window */
6577
"Keyboard" = "Keyboard";
6678

MonitorControl/UI/fr.lproj/Localizable.strings

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* Shown in the main prefs window */
22
"About" = "À Propos";
33

4+
/* Shown in the alert dialog */
5+
"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!";
6+
47
/* Shown in the main prefs window */
58
"App menu" = "Menu de l'app";
69

@@ -34,6 +37,9 @@
3437
/* Shown in record shortcut box */
3538
"Decrease" = "Diminuer";
3639

40+
/* Shown in the alert dialog */
41+
"Disable gamma control for my displays" = "Disable gamma control for my displays";
42+
3743
/* Shown in the main prefs window */
3844
"Displays" = "Écrans";
3945

@@ -52,6 +58,9 @@
5258
/* Shown in the Display Preferences */
5359
"Hardware (DDC)" = "Matériel (DDC)";
5460

61+
/* Shown in the alert dialog */
62+
"I'll quit the other app" = "I'll quit the other app";
63+
5564
/* Shown in the alert dialog */
5665
"Incompatible previous version" = "Version précédente incompatible";
5766

@@ -61,6 +70,9 @@
6170
/* Intel designation (shown after the version number in Preferences) */
6271
"Intel" = "Intel";
6372

73+
/* Shown in the alert dialog */
74+
"Is f.lux or similar running?" = "Is f.lux or similar running?";
75+
6476
/* Shown in the main prefs window */
6577
"Keyboard" = "Clavier";
6678

0 commit comments

Comments
 (0)