Restore software brightness upon startup + some other tweaks. (#719)

- Software brightness changes are reapplied upon startup when 'Apply last saved values to the display' is selected under 'Upon startup or wake'.
- On some rare occasions, macOS does not reset gamma tables upon display reconfiguration which caused an erroneus baseline and double dimming in software and combined mode. Now there is a manual reset upon receiving a reconfiguration request as a safety measure to avoid this.
- Some minor tweaks regarding how software dimming and gamma table manipulation behaves.
- (also I fixed my name in About.)
This commit is contained in:
Istvan T 2021-10-18 16:59:33 +02:00 committed by GitHub
parent e7f8f04a46
commit 8309d1dd5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 48 additions and 85 deletions

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>6695</string>
<string>6767</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>

View file

@ -200,11 +200,13 @@ class Display: Equatable {
}
}
func setSwBrightness(_ value: Float, smooth: Bool = false) -> Bool {
func setSwBrightness(_ value: Float, smooth: Bool = false, noPrefSave: Bool = false) -> Bool {
self.swBrightnessSemaphore.wait()
let brightnessValue = min(1, value)
var currentValue = self.readPrefAsFloat(key: .SwBrightness)
self.savePref(brightnessValue, key: .SwBrightness)
if !noPrefSave {
self.savePref(brightnessValue, key: .SwBrightness)
}
var newValue = brightnessValue
currentValue = self.swBrightnessTransform(value: currentValue)
newValue = self.swBrightnessTransform(value: newValue)

View file

@ -40,7 +40,7 @@ class OtherDisplay: Display {
os_log("- Combined brightness mapping on DDC data.", type: .info)
if currentValue > 0 {
currentValue = self.combinedBrightnessSwitchingValue() + currentValue * (1 - self.combinedBrightnessSwitchingValue())
} else if currentValue == 0, firstrun {
} else if currentValue == 0, firstrun, prefs.integer(forKey: PrefKey.startupAction.rawValue) != StartupAction.write.rawValue {
currentValue = self.combinedBrightnessSwitchingValue()
} else if self.prefExists(for: command), self.readPrefAsFloat(for: command) <= self.combinedBrightnessSwitchingValue() {
currentValue = self.readPrefAsFloat(for: command)
@ -58,7 +58,7 @@ class OtherDisplay: Display {
os_log("- Combined brightness mapping on saved data.", type: .info)
if !self.prefExists(for: command) {
currentValue = self.combinedBrightnessSwitchingValue() + self.convDDCToValue(for: command, from: currentDDCValue) * (1 - self.combinedBrightnessSwitchingValue())
} else if firstrun, currentValue < self.combinedBrightnessSwitchingValue() {
} else if firstrun, currentValue < self.combinedBrightnessSwitchingValue(), prefs.integer(forKey: PrefKey.startupAction.rawValue) != StartupAction.write.rawValue {
currentValue = self.combinedBrightnessSwitchingValue()
}
} else {

View file

@ -100,7 +100,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
func applicationWillTerminate(_: Notification) {
os_log("Goodbye!", type: .info)
DisplayManager.shared.resetSwBrightnessForAllDisplays()
DisplayManager.shared.resetSwBrightnessForAllDisplays(noPrefSave: true)
self.statusItem.isVisible = true
}
@ -112,7 +112,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
}
func displayReconfigured() {
@objc func displayReconfigured() {
DisplayManager.shared.resetSwBrightnessForAllDisplays(noPrefSave: true)
CGDisplayRestoreColorSyncSettings()
self.reconfigureID += 1
os_log("Bumping reconfigureID to %{public}@", type: .info, String(self.reconfigureID))
_ = DisplayManager.shared.destroyAllShades()
@ -135,12 +137,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
DisplayManager.shared.configureDisplays()
DisplayManager.shared.addDisplayCounterSuffixes()
DisplayManager.shared.updateArm64AVServices()
if firstrun {
DisplayManager.shared.resetSwBrightnessForAllDisplays(settingsOnly: true)
if firstrun && prefs.integer(forKey: PrefKey.startupAction.rawValue) != StartupAction.write.rawValue {
DisplayManager.shared.resetSwBrightnessForAllDisplays(prefsOnly: true)
}
DisplayManager.shared.setupOtherDisplays(firstrun: firstrun)
self.updateMenusAndKeys()
if !firstrun {
if !firstrun || prefs.integer(forKey: PrefKey.startupAction.rawValue) == StartupAction.write.rawValue {
if !prefs.bool(forKey: PrefKey.disableCombinedBrightness.rawValue) {
DisplayManager.shared.restoreSwBrightnessForAllDisplays(async: !prefs.bool(forKey: PrefKey.disableSmoothBrightness.rawValue))
}
@ -163,7 +165,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private func subscribeEventListeners() {
NotificationCenter.default.addObserver(self, selector: #selector(self.audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil) // subscribe Audio output detector (SimplyCoreAudio)
DistributedNotificationCenter.default.addObserver(self, selector: #selector(self.colorSyncSettingsChanged), name: NSNotification.Name(rawValue: kColorSyncDisplayDeviceProfilesNotification.takeRetainedValue() as String), object: nil) // ColorSync change
DistributedNotificationCenter.default.addObserver(self, selector: #selector(self.displayReconfigured), name: NSNotification.Name(rawValue: kColorSyncDisplayDeviceProfilesNotification.takeRetainedValue() as String), object: nil) // ColorSync change
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.screensDidSleepNotification, object: nil) // sleep and wake listeners
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotofication), name: NSWorkspace.screensDidWakeNotification, object: nil)
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.willSleepNotification, object: nil)
@ -192,7 +194,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
self.sleepID = 0
if self.reconfigureID != 0 {
let dispatchedReconfigureID = self.reconfigureID
os_log("Display needs reconfig after sober with reconfigureID %{public}@", type: .info, String(dispatchedReconfigureID))
os_log("Displays need reconfig after sober with reconfigureID %{public}@", type: .info, String(dispatchedReconfigureID))
self.configure(dispatchedReconfigureID: dispatchedReconfigureID)
} else if Arm64DDC.isArm64 {
os_log("Displays don't need reconfig after sober but might need AVServices update", type: .info)
@ -238,11 +240,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
}
@objc private func colorSyncSettingsChanged() {
CGDisplayRestoreColorSyncSettings()
self.displayReconfigured()
}
func handleListenForChanged() {
self.checkPermissions()
self.updateMediaKeyTap()

View file

@ -309,16 +309,18 @@ class DisplayManager {
}
}
func resetSwBrightnessForAllDisplays(settingsOnly: Bool = false, async: Bool = false) {
func resetSwBrightnessForAllDisplays(prefsOnly: Bool = false, noPrefSave: Bool = false, async: Bool = false) {
for otherDisplay in self.getOtherDisplays() {
if !settingsOnly {
_ = otherDisplay.setSwBrightness(1, smooth: async)
otherDisplay.smoothBrightnessTransient = 1
} else {
if !prefsOnly {
_ = otherDisplay.setSwBrightness(1, smooth: async, noPrefSave: noPrefSave)
if !noPrefSave {
otherDisplay.smoothBrightnessTransient = 1
}
} else if !noPrefSave {
otherDisplay.savePref(1, key: .SwBrightness)
otherDisplay.smoothBrightnessTransient = 1
}
if otherDisplay.isSw() {
if otherDisplay.isSw(), !noPrefSave {
otherDisplay.savePref(1, for: .brightness)
}
}
@ -329,7 +331,7 @@ class DisplayManager {
if (otherDisplay.readPrefAsFloat(for: .brightness) == 0 && !prefs.bool(forKey: PrefKey.disableCombinedBrightness.rawValue)) || (otherDisplay.readPrefAsFloat(for: .brightness) < otherDisplay.combinedBrightnessSwitchingValue() && !prefs.bool(forKey: PrefKey.separateCombinedScale.rawValue) && !prefs.bool(forKey: PrefKey.disableCombinedBrightness.rawValue)) || otherDisplay.isSw() {
let savedPrefValue = otherDisplay.readPrefAsFloat(key: .SwBrightness)
if otherDisplay.getSwBrightness() != savedPrefValue {
OSDUtils.popEmptyOsd(displayID: otherDisplay.identifier, command: Command.brightness) // This will give the user a hint why is the brightness suddenly changes and also give screen activity to counter the 'no gamma change when there is no screen activity' issue on some macs
OSDUtils.popEmptyOsd(displayID: otherDisplay.identifier, command: Command.brightness) // This will give the user a hint why is the brightness suddenly changes.
}
otherDisplay.savePref(otherDisplay.getSwBrightness(), key: .SwBrightness)
os_log("Restoring sw brightness to %{public}@ on other display %{public}@", type: .info, String(savedPrefValue), String(otherDisplay.identifier))

View file

@ -1259,7 +1259,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" tableStyle="inset" selectionHighlightStyle="none" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="520" viewBased="YES" id="zC9-dS-Tr3">
<rect key="frame" x="0.0" y="0.0" width="740" height="520"/>
<rect key="frame" x="0.0" y="0.0" width="740" height="502"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="14" height="0.0"/>
<color key="backgroundColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
@ -2018,7 +2018,7 @@
<font key="font" metaFont="systemMedium" size="13"/>
<string key="title">@the0neyouseek (Guillaume B.)
@JoniVR (Joni Van Roost)
@waydabber (Istvan T.)</string>
@waydabber (István T.)</string>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "Stil der Menüpunkte:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Menü-Symbol:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "General menu items style:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Menu Icon:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "Style des éléments généraux du menu :";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Icône du menu :";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "Általános menüpontok stílusa:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Menü ikon:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "Stile elementi del menu:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Icona menu:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "일반 메뉴 항목 스타일:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "메뉴 아이콘:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "Stijl algemene menu-items:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Menu Icoon:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "Genel menü öğeleri stili:";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "Menü ikonu:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "通用选项的风格";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "选项图标:";

View file

@ -295,8 +295,8 @@
/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */
"thh-DG-ecH.title" = "一般選單項目的風格";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (Istvan T.)";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)";
/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */
"u6s-Pb-BCG.title" = "選單圖示:";

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>6695</string>
<string>6767</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSBackgroundOnly</key>

View file

@ -1 +0,0 @@
monitorcontrol.app

View file

@ -1,22 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>MonitorControl</title>
<link>https://monitorcontrol.app</link>
<item>
<title>v4.0.0-beta1</title>
<!-- TODO: Use correct channels once setting is present. (after 4.0.0 release) -->
<!-- <sparkle:channel>beta</sparkle:channel> -->
<pubDate>Thu, 30 Sep 2021 21:43:20 +0200</pubDate>
<sparkle:version>6293</sparkle:version>
<sparkle:shortVersionString>4.0.0-beta1</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>10.15</sparkle:minimumSystemVersion>
<enclosure
url="https://github.com/MonitorControl/MonitorControl/releases/download/v4.0.0-beta1/MonitorControl.4.0.0-beta1.dmg"
type="application/octet-stream"
sparkle:edSignature="vb1yP7PHUbfKXARe3oHw+2y7V79fW/lsOAj8zlr03K1vXWq0l/LfBnjmJySCRnJjtkfn6TbkEwNVi0Q64pwJDA=="
length="4127428"
/>
</item>
</channel>
</rss>

View file

@ -1,15 +0,0 @@
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=https://github.com/MonitorControl/MonitorControl#readme">
<script type="text/javascript">
window.location.href = "https://github.com/MonitorControl/MonitorControl#readme"
</script>
<title>MonitorControl - redirect</title>
</head>
<body>
<!-- Note: don't tell people to `click` the link, just tell them that it is a link. -->
If you are not redirected automatically, <a href='https://github.com/MonitorControl/MonitorControl#readme'>follow this link</a>!.
</body>
</html>