mirror of
https://github.com/MonitorControl/MonitorControl.git
synced 2026-05-15 14:15:55 -06:00
Add Advanced Preferences panel (#97)
- Removed whitelist which caused some issues for some people #105 - Added `hide OSD` option to `AdvancedPrefsViewController` - Added `Longer Delay` option to `AdvancedPrefsViewController` - Added `PollingMode` and `PollingCount` to `AdvancedPrefsViewController` (should help #37) - Added option to reset all preferences to `AdvancedPrefsViewController` See the wiki for more info: https://github.com/the0neyouseek/MonitorControl/wiki/Advanced-Preferences
This commit is contained in:
parent
98d9952d35
commit
dd3d026db3
23 changed files with 894 additions and 108 deletions
|
|
@ -7,3 +7,5 @@ excluded:
|
|||
- Carthage
|
||||
type_body_length: 500
|
||||
file_length: 500
|
||||
cyclomatic_complexity:
|
||||
ignores_case_statements: true
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
github "reitermarkus/DDC.swift" "5c03666e17a1a850892c08a5db6f4a208f762f26"
|
||||
github "rnine/AMCoreAudio" "3.3"
|
||||
github "reitermarkus/DDC.swift" "f8e7dc7f2fea41ec4e27672fdbc7051be218ad02"
|
||||
github "rnine/AMCoreAudio" "3.3.1"
|
||||
github "shpakovski/MASPreferences" "1.3"
|
||||
github "the0neyouseek/MediaKeyTap" "3.1.0"
|
||||
|
|
|
|||
|
|
@ -26,8 +26,16 @@
|
|||
28D1DE15227FD006004CB494 /* DDC.framework.dSYM in [Carthage] Copy Framework Debug Symbols */ = {isa = PBXBuildFile; fileRef = 28D1DE11227FD006004CB494 /* DDC.framework.dSYM */; };
|
||||
56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */; };
|
||||
56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB01D9A4016007BCDC5 /* Assets.xcassets */; };
|
||||
8C0E20562296ABBA000CBF15 /* NSNotification+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C0E20552296ABBA000CBF15 /* NSNotification+Extension.swift */; };
|
||||
F01B067922822141008E64DB /* Display+Whitelist.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B067822822141008E64DB /* Display+Whitelist.swift */; };
|
||||
6C0CCB26228F4F720037D2C5 /* AdvancedPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */; };
|
||||
6C20466C23153E4F00859767 /* Display+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C20466B23153E4F00859767 /* Display+Extension.swift */; };
|
||||
6C2EA1CD228F644B00060E3F /* OnlyIntegerValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */; };
|
||||
6C2EA1CF228F7DFB00060E3F /* PollingMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */; };
|
||||
6C85EFDA22C941B000227EA1 /* DisplayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFD922C941B000227EA1 /* DisplayManager.swift */; };
|
||||
6C85EFDD22CBAA8F00227EA1 /* PollingModeCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */; };
|
||||
6C85EFDF22CBB54100227EA1 /* PollingCountCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */; };
|
||||
6C85EFE122CC00AD00227EA1 /* NSNotification+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFE022CC00AD00227EA1 /* NSNotification+Extension.swift */; };
|
||||
6CCB278622D5315200619B05 /* HideOsdCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCB278522D5315200619B05 /* HideOsdCellView.swift */; };
|
||||
6CD444C322D4FBB8005BFD3D /* LongerDelayCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */; };
|
||||
F01B0699228221B7008E64DB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F01B0680228221B6008E64DB /* Localizable.strings */; };
|
||||
F01B069A228221B7008E64DB /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B0683228221B6008E64DB /* Utils.swift */; };
|
||||
F01B069E228221B7008E64DB /* ButtonCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B068E228221B6008E64DB /* ButtonCellView.swift */; };
|
||||
|
|
@ -106,8 +114,16 @@
|
|||
56754EAB1D9A4016007BCDC5 /* MonitorControl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControl.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
56754EB01D9A4016007BCDC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
8C0E20552296ABBA000CBF15 /* NSNotification+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSNotification+Extension.swift"; sourceTree = "<group>"; };
|
||||
F01B067822822141008E64DB /* Display+Whitelist.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Display+Whitelist.swift"; sourceTree = "<group>"; };
|
||||
6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsViewController.swift; sourceTree = "<group>"; tabWidth = 4; };
|
||||
6C20466B23153E4F00859767 /* Display+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Display+Extension.swift"; sourceTree = "<group>"; };
|
||||
6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlyIntegerValueFormatter.swift; sourceTree = "<group>"; };
|
||||
6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollingMode.swift; sourceTree = "<group>"; };
|
||||
6C85EFD922C941B000227EA1 /* DisplayManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayManager.swift; sourceTree = "<group>"; };
|
||||
6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollingModeCellView.swift; sourceTree = "<group>"; };
|
||||
6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = PollingCountCellView.swift; sourceTree = "<group>"; tabWidth = 4; };
|
||||
6C85EFE022CC00AD00227EA1 /* NSNotification+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSNotification+Extension.swift"; sourceTree = "<group>"; };
|
||||
6CCB278522D5315200619B05 /* HideOsdCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideOsdCellView.swift; sourceTree = "<group>"; };
|
||||
6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongerDelayCellView.swift; sourceTree = "<group>"; };
|
||||
F01B0681228221B6008E64DB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
F01B0682228221B6008E64DB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
F01B0683228221B6008E64DB /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -179,10 +195,10 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
2894D9B72280B30500DF58DA /* CGDirectDisplayID+Extension.swift */,
|
||||
F01B067822822141008E64DB /* Display+Whitelist.swift */,
|
||||
28D1DDEC227FB8F2004CB494 /* EDID+Extension.swift */,
|
||||
28D1DDF1227FBE71004CB494 /* NSScreen+Extension.swift */,
|
||||
8C0E20552296ABBA000CBF15 /* NSNotification+Extension.swift */,
|
||||
6C85EFE022CC00AD00227EA1 /* NSNotification+Extension.swift */,
|
||||
6C20466B23153E4F00859767 /* Display+Extension.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -210,6 +226,8 @@
|
|||
56754EAD1D9A4016007BCDC5 /* MonitorControl */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F01B0686228221B6008E64DB /* Info.plist */,
|
||||
6C85EFD622C74B0E00227EA1 /* Manager */,
|
||||
56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */,
|
||||
56754EB01D9A4016007BCDC5 /* Assets.xcassets */,
|
||||
F03A8DF11FFBAA6F0034DC27 /* Display.swift */,
|
||||
|
|
@ -221,13 +239,35 @@
|
|||
path = MonitorControl;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6C85EFD622C74B0E00227EA1 /* Manager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6C85EFD922C941B000227EA1 /* DisplayManager.swift */,
|
||||
);
|
||||
path = Manager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6C85EFDB22CBA77600227EA1 /* Cells */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */,
|
||||
F01B068E228221B6008E64DB /* ButtonCellView.swift */,
|
||||
6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */,
|
||||
6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */,
|
||||
6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */,
|
||||
6CCB278522D5315200619B05 /* HideOsdCellView.swift */,
|
||||
);
|
||||
path = Cells;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F01B067F228221B6008E64DB /* Support */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F01B0685228221B6008E64DB /* Bridging-Header.h */,
|
||||
F01B0686228221B6008E64DB /* Info.plist */,
|
||||
F01B0680228221B6008E64DB /* Localizable.strings */,
|
||||
F01B0683228221B6008E64DB /* Utils.swift */,
|
||||
6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */,
|
||||
6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */,
|
||||
);
|
||||
path = Support;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -235,8 +275,7 @@
|
|||
F01B0687228221B6008E64DB /* UI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */,
|
||||
F01B068E228221B6008E64DB /* ButtonCellView.swift */,
|
||||
6C85EFDB22CBA77600227EA1 /* Cells */,
|
||||
F01B0690228221B7008E64DB /* Main.storyboard */,
|
||||
F01B0692228221B7008E64DB /* MainMenu.xib */,
|
||||
F01B068F228221B7008E64DB /* SliderHandler.swift */,
|
||||
|
|
@ -250,6 +289,7 @@
|
|||
F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */,
|
||||
F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */,
|
||||
F0445D3720023E710025AE82 /* MainPrefsViewController.swift */,
|
||||
6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */,
|
||||
);
|
||||
path = "View Controllers";
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -320,13 +360,13 @@
|
|||
TargetAttributes = {
|
||||
56754EAA1D9A4016007BCDC5 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
DevelopmentTeam = KGY56RWR9A;
|
||||
DevelopmentTeam = CYC8C8R4K9;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
F06792E6200A73460066C438 = {
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
DevelopmentTeam = KGY56RWR9A;
|
||||
DevelopmentTeam = CYC8C8R4K9;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
|
|
@ -454,18 +494,26 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */,
|
||||
6C85EFE122CC00AD00227EA1 /* NSNotification+Extension.swift in Sources */,
|
||||
6C85EFDF22CBB54100227EA1 /* PollingCountCellView.swift in Sources */,
|
||||
6C0CCB26228F4F720037D2C5 /* AdvancedPrefsViewController.swift in Sources */,
|
||||
F01B069E228221B7008E64DB /* ButtonCellView.swift in Sources */,
|
||||
6C2EA1CD228F644B00060E3F /* OnlyIntegerValueFormatter.swift in Sources */,
|
||||
2894D9B82280B30500DF58DA /* CGDirectDisplayID+Extension.swift in Sources */,
|
||||
6CCB278622D5315200619B05 /* HideOsdCellView.swift in Sources */,
|
||||
6CD444C322D4FBB8005BFD3D /* LongerDelayCellView.swift in Sources */,
|
||||
F03FE4C0228DF62B001F59A4 /* FriendlyNameCellView.swift in Sources */,
|
||||
F01B067922822141008E64DB /* Display+Whitelist.swift in Sources */,
|
||||
6C2EA1CF228F7DFB00060E3F /* PollingMode.swift in Sources */,
|
||||
F03A8DF21FFBAA6F0034DC27 /* Display.swift in Sources */,
|
||||
F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */,
|
||||
8C0E20562296ABBA000CBF15 /* NSNotification+Extension.swift in Sources */,
|
||||
28D1DDF0227FBD99004CB494 /* EDID+Extension.swift in Sources */,
|
||||
6C85EFDD22CBAA8F00227EA1 /* PollingModeCellView.swift in Sources */,
|
||||
F0445D3D200254FA0025AE82 /* KeysPrefsViewController.swift in Sources */,
|
||||
6C20466C23153E4F00859767 /* Display+Extension.swift in Sources */,
|
||||
F0445D3820023E710025AE82 /* MainPrefsViewController.swift in Sources */,
|
||||
28D1DDF2227FBE71004CB494 /* NSScreen+Extension.swift in Sources */,
|
||||
F01B069F228221B7008E64DB /* SliderHandler.swift in Sources */,
|
||||
6C85EFDA22C941B000227EA1 /* DisplayManager.swift in Sources */,
|
||||
F01B069A228221B7008E64DB /* Utils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -641,8 +689,8 @@
|
|||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 560;
|
||||
DEVELOPMENT_TEAM = KGY56RWR9A;
|
||||
CURRENT_PROJECT_VERSION = 570;
|
||||
DEVELOPMENT_TEAM = CYC8C8R4K9;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
|
@ -668,8 +716,8 @@
|
|||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 560;
|
||||
DEVELOPMENT_TEAM = KGY56RWR9A;
|
||||
CURRENT_PROJECT_VERSION = 570;
|
||||
DEVELOPMENT_TEAM = CYC8C8R4K9;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
|
@ -699,8 +747,8 @@
|
|||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 560;
|
||||
DEVELOPMENT_TEAM = KGY56RWR9A;
|
||||
CURRENT_PROJECT_VERSION = 570;
|
||||
DEVELOPMENT_TEAM = CYC8C8R4K9;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = MonitorControlHelper/Info.plist;
|
||||
|
|
@ -724,8 +772,8 @@
|
|||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 560;
|
||||
DEVELOPMENT_TEAM = KGY56RWR9A;
|
||||
CURRENT_PROJECT_VERSION = 570;
|
||||
DEVELOPMENT_TEAM = CYC8C8R4K9;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = MonitorControlHelper/Info.plist;
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||
|
||||
var monitorItems: [NSMenuItem] = []
|
||||
var displays: [Display] = []
|
||||
|
||||
let step = 100 / 16
|
||||
|
||||
var displayManager: DisplayManager?
|
||||
var mediaKeyTap: MediaKeyTap?
|
||||
var prefsController: NSWindowController?
|
||||
|
||||
|
|
@ -29,7 +29,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
func applicationDidFinishLaunching(_: Notification) {
|
||||
app = self
|
||||
|
||||
self.setupLayout()
|
||||
self.displayManager = DisplayManager()
|
||||
self.setupViewControllers()
|
||||
self.subscribeEventListeners()
|
||||
self.startOrRestartMediaKeyTap()
|
||||
self.statusItem.image = NSImage(named: "status")
|
||||
|
|
@ -40,11 +41,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
self.updateDisplays()
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_: Notification) {
|
||||
AMCoreAudio.NotificationCenter.defaultCenter.unsubscribe(self, eventType: AudioHardwareEvent.self)
|
||||
DistributedNotificationCenter.default().removeObserver(self.accessibilityObserver as Any, name: .accessibilityApi, object: nil)
|
||||
}
|
||||
|
||||
@IBAction func quitClicked(_: AnyObject) {
|
||||
NSApplication.shared.terminate(self)
|
||||
}
|
||||
|
|
@ -59,7 +55,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
/// Set the default prefs of the app
|
||||
func setDefaultPrefs() {
|
||||
let prefs = UserDefaults.standard
|
||||
if !prefs.bool(forKey: Utils.PrefKeys.appAlreadyLaunched.rawValue) {
|
||||
prefs.set(true, forKey: Utils.PrefKeys.appAlreadyLaunched.rawValue)
|
||||
|
||||
|
|
@ -83,7 +78,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
|
||||
self.monitorItems = []
|
||||
self.displays = []
|
||||
self.displayManager?.clearDisplays()
|
||||
}
|
||||
|
||||
func updateDisplays() {
|
||||
|
|
@ -94,7 +89,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
if screen.isBuiltin {
|
||||
return false
|
||||
}
|
||||
|
||||
return DDC(for: screen.displayID)?.edid() != nil
|
||||
}
|
||||
|
||||
|
|
@ -128,8 +122,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
if let edid = ddc?.edid() {
|
||||
let name = Utils.getDisplayName(forEdid: edid)
|
||||
let isEnabled = (prefs.object(forKey: "\(id)-state") as? Bool) ?? true
|
||||
|
||||
let display = Display(id, name: name, isBuiltin: screen.isBuiltin)
|
||||
let display = Display(id, name: name, isBuiltin: screen.isBuiltin, isEnabled: isEnabled)
|
||||
|
||||
let monitorSubMenu: NSMenu = asSubMenu ? NSMenu() : self.statusMenu
|
||||
|
||||
|
|
@ -153,7 +148,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
display.volumeSliderHandler = volumeSliderHandler
|
||||
display.brightnessSliderHandler = brightnessSliderHandler
|
||||
self.displays.append(display)
|
||||
self.displayManager?.addDisplay(display: display)
|
||||
|
||||
let monitorMenuItem = NSMenuItem()
|
||||
monitorMenuItem.title = "\(display.getFriendlyName())"
|
||||
|
|
@ -166,27 +161,39 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
private func setupLayout() {
|
||||
private func setupViewControllers() {
|
||||
let storyboard: NSStoryboard = NSStoryboard(name: "Main", bundle: Bundle.main)
|
||||
let mainPrefsVc = storyboard.instantiateController(withIdentifier: "MainPrefsVC")
|
||||
let keyPrefsVc = storyboard.instantiateController(withIdentifier: "KeysPrefsVC")
|
||||
let displayPrefsVc = storyboard.instantiateController(withIdentifier: "DisplayPrefsVC")
|
||||
let advancedPrefsVc = storyboard.instantiateController(withIdentifier: "AdvancedPrefsVC")
|
||||
let views = [
|
||||
storyboard.instantiateController(withIdentifier: "MainPrefsVC"),
|
||||
storyboard.instantiateController(withIdentifier: "KeysPrefsVC"),
|
||||
storyboard.instantiateController(withIdentifier: "DisplayPrefsVC"),
|
||||
mainPrefsVc,
|
||||
keyPrefsVc,
|
||||
displayPrefsVc,
|
||||
advancedPrefsVc,
|
||||
]
|
||||
prefsController = MASPreferencesWindowController(viewControllers: views, title: NSLocalizedString("Preferences", comment: "Shown in Preferences window"))
|
||||
if let displayPrefs = displayPrefsVc as? DisplayPrefsViewController {
|
||||
displayPrefs.displayManager = self.displayManager
|
||||
}
|
||||
if let advancedPrefs = advancedPrefsVc as? AdvancedPrefsViewController {
|
||||
advancedPrefs.displayManager = self.displayManager
|
||||
}
|
||||
}
|
||||
|
||||
private func subscribeEventListeners() {
|
||||
// subscribe KeyTap event listener
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleListenForChanged), name: NSNotification.Name(Utils.PrefKeys.listenFor.rawValue), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleShowContrastChanged), name: NSNotification.Name(Utils.PrefKeys.showContrast.rawValue), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleFriendlyNameChanged), name: NSNotification.Name(Utils.PrefKeys.friendlyName.rawValue), object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleListenForChanged), name: .listenFor, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleShowContrastChanged), name: .showContrast, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleFriendlyNameChanged), name: .friendlyName, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handlePreferenceReset), name: .preferenceReset, object: nil)
|
||||
|
||||
// subscribe Audio output detector (AMCoreAudio)
|
||||
AMCoreAudio.NotificationCenter.defaultCenter.subscribe(self, eventType: AudioHardwareEvent.self, dispatchQueue: DispatchQueue.main)
|
||||
|
||||
// listen for accessibility status changes
|
||||
self.accessibilityObserver = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in
|
||||
_ = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.startOrRestartMediaKeyTap()
|
||||
}
|
||||
|
|
@ -198,9 +205,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
|
||||
extension AppDelegate: MediaKeyTapDelegate {
|
||||
func handle(mediaKey: MediaKey, event _: KeyEvent?, modifiers: NSEvent.ModifierFlags?) {
|
||||
let displays = self.displayManager?.getDisplays() ?? [Display]()
|
||||
guard let currentDisplay = Utils.getCurrentDisplay(from: displays) else { return }
|
||||
|
||||
let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? self.displays : [currentDisplay]
|
||||
let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay]
|
||||
let isSmallIncrement = modifiers?.isSuperset(of: NSEvent.ModifierFlags([.shift, .option])) ?? false
|
||||
|
||||
for display in allDisplays {
|
||||
|
|
@ -241,6 +249,12 @@ extension AppDelegate: MediaKeyTapDelegate {
|
|||
self.updateDisplays()
|
||||
}
|
||||
|
||||
@objc func handlePreferenceReset() {
|
||||
self.setDefaultPrefs()
|
||||
self.updateDisplays()
|
||||
self.startOrRestartMediaKeyTap()
|
||||
}
|
||||
|
||||
private func startOrRestartMediaKeyTap() {
|
||||
var keys: [MediaKey]
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,26 @@ class Display {
|
|||
var contrastSliderHandler: SliderHandler?
|
||||
var ddc: DDC?
|
||||
|
||||
var hideOsd: Bool {
|
||||
get {
|
||||
return self.prefs.bool(forKey: "hideOsd-\(self.identifier)")
|
||||
}
|
||||
set {
|
||||
self.prefs.set(newValue, forKey: "hideOsd-\(self.identifier)")
|
||||
os_log("Set `hideOsd` to: %{public}@", type: .info, String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
var needsLongerDelay: Bool {
|
||||
get {
|
||||
return self.prefs.object(forKey: "longerDelay-\(self.identifier)") as? Bool ?? false
|
||||
}
|
||||
set {
|
||||
self.prefs.set(newValue, forKey: "longerDelay-\(self.identifier)")
|
||||
os_log("Set `needsLongerDisplay` to: %{public}@", type: .info, String(newValue))
|
||||
}
|
||||
}
|
||||
|
||||
private let prefs = UserDefaults.standard
|
||||
private var audioPlayer: AVAudioPlayer?
|
||||
|
||||
|
|
@ -67,7 +87,9 @@ class Display {
|
|||
}
|
||||
|
||||
if let slider = volumeSliderHandler?.slider {
|
||||
slider.intValue = Int32(value)
|
||||
DispatchQueue.main.async {
|
||||
slider.intValue = Int32(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +112,9 @@ class Display {
|
|||
}
|
||||
|
||||
if let slider = volumeSliderHandler?.slider {
|
||||
slider.intValue = Int32(value)
|
||||
DispatchQueue.main.async {
|
||||
slider.intValue = Int32(value)
|
||||
}
|
||||
}
|
||||
|
||||
self.saveValue(value, for: .audioSpeakerVolume)
|
||||
|
|
@ -161,6 +185,46 @@ class Display {
|
|||
return self.prefs.string(forKey: "friendlyName-\(self.identifier)") ?? self.name
|
||||
}
|
||||
|
||||
func setPollingMode(_ value: Int) {
|
||||
self.prefs.set(String(value), forKey: "pollingMode-\(self.identifier)")
|
||||
}
|
||||
|
||||
/*
|
||||
Polling Modes:
|
||||
0 -> .none -> 0 tries
|
||||
1 -> .minimal -> 5 tries
|
||||
2 -> .normal -> 10 tries
|
||||
3 -> .heavy -> 100 tries
|
||||
4 -> .custom -> $pollingCount tries
|
||||
*/
|
||||
func getPollingMode() -> Int {
|
||||
// Reading as string so we don't get "0" as the default value
|
||||
return Int(self.prefs.string(forKey: "pollingMode-\(self.identifier)") ?? "2") ?? 2
|
||||
}
|
||||
|
||||
func getPollingCount() -> Int {
|
||||
let selectedMode = self.getPollingMode()
|
||||
switch selectedMode {
|
||||
case 0:
|
||||
return PollingMode.none.value
|
||||
case 1:
|
||||
return PollingMode.minimal.value
|
||||
case 2:
|
||||
return PollingMode.normal.value
|
||||
case 3:
|
||||
return PollingMode.heavy.value
|
||||
case 4:
|
||||
let val = self.prefs.integer(forKey: "pollingCount-\(self.identifier)")
|
||||
return PollingMode.custom(value: val).value
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func setPollingCount(_ value: Int) {
|
||||
self.prefs.set(value, forKey: "pollingCount-\(self.identifier)")
|
||||
}
|
||||
|
||||
private func showOsd(command: DDC.Command, value: Int, isSmallIncrement: Bool = false) {
|
||||
guard let manager = OSDManager.sharedManager() as? OSDManager else {
|
||||
return
|
||||
|
|
|
|||
7
MonitorControl/Extensions/Display+Extension.swift
Normal file
7
MonitorControl/Extensions/Display+Extension.swift
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
extension Display: Equatable {
|
||||
static func == (lhs: Display, rhs: Display) -> Bool {
|
||||
return lhs.identifier == rhs.identifier
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
extension Display {
|
||||
enum WhitelistReason {
|
||||
case longerDelay
|
||||
case hideOsd
|
||||
}
|
||||
|
||||
static let whitelist: [UInt32: [UInt32: [WhitelistReason]]] = [
|
||||
7789: [
|
||||
30460: [.hideOsd, .longerDelay], // LG 38UC99-W over DisplayPort
|
||||
30459: [.hideOsd, .longerDelay], // LG 38UC99-W over HDMI
|
||||
],
|
||||
]
|
||||
|
||||
var hideOsd: Bool {
|
||||
guard let vendor = self.identifier.vendorNumber, let model = self.identifier.modelNumber else {
|
||||
return false
|
||||
}
|
||||
|
||||
return Display.whitelist[vendor]?[model]?.contains(.hideOsd) ?? false
|
||||
}
|
||||
|
||||
var needsLongerDelay: Bool {
|
||||
guard let vendor = self.identifier.vendorNumber, let model = self.identifier.modelNumber else {
|
||||
return false
|
||||
}
|
||||
|
||||
return Display.whitelist[vendor]?[model]?.contains(.longerDelay) ?? false
|
||||
}
|
||||
}
|
||||
|
|
@ -2,4 +2,9 @@ import Cocoa
|
|||
|
||||
extension NSNotification.Name {
|
||||
static let accessibilityApi = NSNotification.Name(rawValue: "com.apple.accessibility.api")
|
||||
static let listenFor = NSNotification.Name(rawValue: Utils.PrefKeys.listenFor.rawValue)
|
||||
static let showContrast = NSNotification.Name(rawValue: Utils.PrefKeys.showContrast.rawValue)
|
||||
static let friendlyName = NSNotification.Name(rawValue: Utils.PrefKeys.friendlyName.rawValue)
|
||||
static let preferenceReset = NSNotification.Name(rawValue: Utils.PrefKeys.preferenceReset.rawValue)
|
||||
static let displayListUpdate = NSNotification.Name(rawValue: Utils.PrefKeys.displayListUpdate.rawValue)
|
||||
}
|
||||
|
|
|
|||
35
MonitorControl/Manager/DisplayManager.swift
Normal file
35
MonitorControl/Manager/DisplayManager.swift
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import Foundation
|
||||
|
||||
class DisplayManager {
|
||||
private var displays: [Display] {
|
||||
didSet {
|
||||
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
self.displays = []
|
||||
}
|
||||
|
||||
func updateDisplays(displays: [Display]) {
|
||||
self.displays = displays
|
||||
}
|
||||
|
||||
func getDisplays() -> [Display] {
|
||||
return self.displays
|
||||
}
|
||||
|
||||
func addDisplay(display: Display) {
|
||||
self.displays.append(display)
|
||||
}
|
||||
|
||||
func updateDisplay(display updatedDisplay: Display) {
|
||||
if let indexToUpdate = self.displays.firstIndex(of: updatedDisplay) {
|
||||
self.displays[indexToUpdate] = updatedDisplay
|
||||
}
|
||||
}
|
||||
|
||||
func clearDisplays() {
|
||||
self.displays = []
|
||||
}
|
||||
}
|
||||
15
MonitorControl/Support/OnlyIntegerValueFormatter.swift
Normal file
15
MonitorControl/Support/OnlyIntegerValueFormatter.swift
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import Cocoa
|
||||
|
||||
class OnlyIntegerValueFormatter: NumberFormatter {
|
||||
override func isPartialStringValid(_ partialString: String, newEditingString _: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription _: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
|
||||
if partialString.isEmpty {
|
||||
return true
|
||||
}
|
||||
|
||||
if partialString.count > 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
return Int(partialString) != nil
|
||||
}
|
||||
}
|
||||
24
MonitorControl/Support/PollingMode.swift
Normal file
24
MonitorControl/Support/PollingMode.swift
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import Foundation
|
||||
|
||||
enum PollingMode {
|
||||
case none
|
||||
case minimal
|
||||
case normal
|
||||
case heavy
|
||||
case custom(value: Int)
|
||||
|
||||
var value: Int {
|
||||
switch self {
|
||||
case .none:
|
||||
return 0
|
||||
case .minimal:
|
||||
return 5
|
||||
case .normal:
|
||||
return 10
|
||||
case .heavy:
|
||||
return 100
|
||||
case let .custom(val):
|
||||
return val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import Cocoa
|
||||
import DDC
|
||||
import os.log
|
||||
import ServiceManagement
|
||||
|
||||
class Utils: NSObject {
|
||||
// MARK: - Menu
|
||||
|
|
@ -56,7 +57,12 @@ class Utils: NSObject {
|
|||
os_log("Display does not support enabling DDC application report.", type: .debug)
|
||||
}
|
||||
|
||||
values = display.ddc?.read(command: command, tries: 10, minReplyDelay: delay)
|
||||
let tries = UInt(display.getPollingCount())
|
||||
os_log("Polling %{public}@ times", type: .info, String(tries))
|
||||
|
||||
if tries != 0 {
|
||||
values = display.ddc?.read(command: command, tries: tries, minReplyDelay: delay)
|
||||
}
|
||||
|
||||
let (currentValue, maxValue) = values ?? (UInt16(display.getValue(for: command)), UInt16(display.getMaxValue(for: command)))
|
||||
|
||||
|
|
@ -94,6 +100,12 @@ class Utils: NSObject {
|
|||
return
|
||||
}
|
||||
|
||||
static func setStartAtLogin(enabled: Bool) {
|
||||
let identifier = "\(Bundle.main.bundleIdentifier!)Helper" as CFString
|
||||
SMLoginItemSetEnabled(identifier, enabled)
|
||||
os_log("Toggle start at login state: %{public}@", type: .info, enabled ? "on" : "off")
|
||||
}
|
||||
|
||||
static func getSystemPreferences() -> [String: AnyObject]? {
|
||||
var propertyListFormat = PropertyListSerialization.PropertyListFormat.xml
|
||||
let plistPath = NSString(string: "~/Library/Preferences/.GlobalPreferences.plist").expandingTildeInPath
|
||||
|
|
@ -154,6 +166,12 @@ class Utils: NSObject {
|
|||
|
||||
/// Friendly name changed
|
||||
case friendlyName
|
||||
|
||||
/// Prefs Reset
|
||||
case preferenceReset
|
||||
|
||||
/// Used for notification when displays are updated in DisplayManager
|
||||
case displayListUpdate
|
||||
}
|
||||
|
||||
/// Keys for the value of listenFor option
|
||||
|
|
|
|||
|
|
@ -473,5 +473,339 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="162" y="218"/>
|
||||
</scene>
|
||||
<!--Advanced Prefs View Controller-->
|
||||
<scene sceneID="tdo-vT-sVy">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="AdvancedPrefsVC" id="xjG-x0-7HO" customClass="AdvancedPrefsViewController" customModule="MonitorControl" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="MqL-7s-HoR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="628" height="267"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="moz-ZW-I46">
|
||||
<rect key="frame" x="18" y="218" width="118" height="29"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Advanced" id="5wk-Dy-0fG">
|
||||
<font key="font" metaFont="systemBold" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="22" horizontalPageScroll="10" verticalLineScroll="22" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VCP-xz-0jI">
|
||||
<rect key="frame" x="20" y="61" width="588" height="83"/>
|
||||
<clipView key="contentView" drawsBackground="NO" id="EAu-T4-lFV">
|
||||
<rect key="frame" x="1" y="0.0" width="586" height="82"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="20" rowSizeStyle="automatic" headerView="qVc-cy-LaW" viewBased="YES" id="t7B-Q7-Ssj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="586" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="122" minWidth="40" maxWidth="1000" id="dNl-I0-hcg">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Display Name">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" title="Text Cell" id="PZ9-0Z-K6J">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="OH7-e2-Xoh" customClass="FriendlyNameCellView" customModule="MonitorControl" customModuleProvider="target">
|
||||
<rect key="frame" x="1" y="1" width="122" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aqx-sQ-YMe">
|
||||
<rect key="frame" x="0.0" y="3" width="122" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" title="Table View Cell" id="Euj-aT-PWW">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="textField" destination="aqx-sQ-YMe" id="3eJ-Tg-zKo"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="108" minWidth="10" maxWidth="3.4028234663852886e+38" id="JKW-oY-bSb">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="ID">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" alignment="left" title="Text Cell" id="UBV-gO-AZz">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="YSF-wp-a89">
|
||||
<rect key="frame" x="126" y="1" width="108" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4mP-DS-UcD">
|
||||
<rect key="frame" x="0.0" y="3" width="108" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="5xu-ja-W21">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="textField" destination="4mP-DS-UcD" id="Du8-3S-RN7"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="95" minWidth="10" maxWidth="3.4028234663852886e+38" id="gxn-NH-Qhb">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Polling Mode">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableHeaderCell>
|
||||
<popUpButtonCell key="dataCell" type="bevel" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="bezel" imageScaling="proportionallyDown" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" id="1vY-Fh-0Cn">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="fyQ-11-vzK"/>
|
||||
</popUpButtonCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="ZCd-vc-3fw" customClass="PollingModeCellView" customModule="MonitorControl" customModuleProvider="target">
|
||||
<rect key="frame" x="237" y="1" width="95" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7FH-uw-jcn">
|
||||
<rect key="frame" x="6" y="-3" width="85" height="24"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="2Bp-6e-RcJ"/>
|
||||
</constraints>
|
||||
<popUpButtonCell key="cell" type="push" title="Normal" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="2" imageScaling="proportionallyDown" inset="2" selectedItem="Riq-uM-bTs" id="M5p-a2-UEs">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="Nil-kM-Hvj">
|
||||
<items>
|
||||
<menuItem title="None" id="FoA-yh-Yx3"/>
|
||||
<menuItem title="Minimal" tag="1" id="Eq3-z9-yIo"/>
|
||||
<menuItem title="Normal" state="on" tag="2" id="Riq-uM-bTs"/>
|
||||
<menuItem title="Heavy" tag="3" id="vik-vN-bJe"/>
|
||||
<menuItem title="Custom" tag="4" id="Cle-DD-vR7"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="valueChanged:" target="ZCd-vc-3fw" id="7w0-4K-RjT"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="7FH-uw-jcn" firstAttribute="centerY" secondItem="ZCd-vc-3fw" secondAttribute="centerY" id="7vv-CC-KvO"/>
|
||||
<constraint firstItem="7FH-uw-jcn" firstAttribute="centerX" secondItem="ZCd-vc-3fw" secondAttribute="centerX" id="WoT-d3-OhY"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="pollingModeMenu" destination="M5p-a2-UEs" id="qXA-qI-8fN"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="99" minWidth="10" maxWidth="3.4028234663852886e+38" id="ytT-up-Dhs">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Polling Count">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="H4a-c9-LcB">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="dEe-qK-55M" customClass="PollingCountCellView" customModule="MonitorControl" customModuleProvider="target">
|
||||
<rect key="frame" x="335" y="1" width="99" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2ys-EO-duG">
|
||||
<rect key="frame" x="0.0" y="3" width="99" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" enabled="NO" title="Table View Cell" id="LZ8-Tj-mCs">
|
||||
<numberFormatter key="formatter" formatterBehavior="default10_4" usesGroupingSeparator="NO" groupingSize="0" minimumIntegerDigits="0" maximumIntegerDigits="42" id="Sfn-Gs-w6w" customClass="OnlyIntegerValueFormatter" customModule="MonitorControl" customModuleProvider="target"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="valueChanged:" target="dEe-qK-55M" id="YkW-av-OBC"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="textField" destination="2ys-EO-duG" id="elf-GU-vnP"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="79" minWidth="40" maxWidth="1000" id="grO-Kr-l4d">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Longer Delay">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<customCell key="dataCell" alignment="left" id="fNO-9H-lO8"/>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="cOJ-Ph-muT" customClass="LongerDelayCellView" customModule="MonitorControl" customModuleProvider="target">
|
||||
<rect key="frame" x="437" y="1" width="79" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cmY-eY-p4P">
|
||||
<rect key="frame" x="0.0" y="0.0" width="49" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="overlaps" inset="2" id="XFk-DD-r8N">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="buttonToggled:" target="cOJ-Ph-muT" id="zaI-dE-Adg"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="button" destination="cmY-eY-p4P" id="2qv-ZX-ifA"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn width="65" minWidth="40" maxWidth="1000" id="MPF-Mr-zVU">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Hide OSD">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<customCell key="dataCell" alignment="left" id="LXT-s7-Hac"/>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="iWx-Xs-DXV" customClass="HideOsdCellView" customModule="MonitorControl" customModuleProvider="target">
|
||||
<rect key="frame" x="519" y="1" width="65" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rW9-Zy-n6z">
|
||||
<rect key="frame" x="0.0" y="0.0" width="49" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="overlaps" inset="2" id="5mh-qn-QcE">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="buttonToggled:" target="iWx-Xs-DXV" id="liH-GI-qNw"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<connections>
|
||||
<outlet property="button" destination="rW9-Zy-n6z" id="9JR-jX-ogx"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="xjG-x0-7HO" id="yPI-ND-kmF"/>
|
||||
<outlet property="delegate" destination="xjG-x0-7HO" id="o1o-wb-TQA"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="7ew-dx-qzM">
|
||||
<rect key="frame" x="-100" y="-100" width="358" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="9J2-D1-8Yx">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" id="qVc-cy-LaW">
|
||||
<rect key="frame" x="0.0" y="0.0" width="586" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bct-zW-zKf">
|
||||
<rect key="frame" x="14" y="13" width="151" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Reset Preferences" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="4Pj-3t-PJr">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="resetPrefsClicked:" target="xjG-x0-7HO" id="rET-YD-lIt"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView distribution="fillProportionally" orientation="horizontal" alignment="centerY" spacing="0.0" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VYW-sX-LN2">
|
||||
<rect key="frame" x="20" y="164" width="586" height="34"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Z6T-PG-PcF">
|
||||
<rect key="frame" x="-2" y="0.0" width="567" height="34"/>
|
||||
<textFieldCell key="cell" selectable="YES" id="frw-j2-tE1">
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="title">Warning ⚠️
|
||||
Changing some of these setting may cause system freezes or unexpected behaviour. </string>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button toolTip="More Info" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="kqn-gU-mZX">
|
||||
<rect key="frame" x="561" y="3" width="27" height="25"/>
|
||||
<buttonCell key="cell" type="help" bezelStyle="helpButton" imagePosition="overlaps" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="H6v-Sv-5MG">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="helpClicked:" target="xjG-x0-7HO" id="37V-Cf-oZ0"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="VYW-sX-LN2" firstAttribute="leading" secondItem="MqL-7s-HoR" secondAttribute="leading" constant="20" id="CUY-YM-yrE"/>
|
||||
<constraint firstItem="VCP-xz-0jI" firstAttribute="leading" secondItem="MqL-7s-HoR" secondAttribute="leading" constant="20" id="EXX-P9-jE2"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="bct-zW-zKf" secondAttribute="trailing" constant="20" id="FI6-Dj-LYL"/>
|
||||
<constraint firstItem="VYW-sX-LN2" firstAttribute="width" secondItem="t7B-Q7-Ssj" secondAttribute="width" id="HDw-Th-5gb"/>
|
||||
<constraint firstItem="moz-ZW-I46" firstAttribute="leading" secondItem="MqL-7s-HoR" secondAttribute="leading" constant="20" id="Kh2-TM-Ugz"/>
|
||||
<constraint firstAttribute="bottom" secondItem="bct-zW-zKf" secondAttribute="bottom" constant="20" id="Kr9-Xc-ADk"/>
|
||||
<constraint firstItem="moz-ZW-I46" firstAttribute="top" secondItem="MqL-7s-HoR" secondAttribute="top" constant="20" id="MfN-q8-NmM"/>
|
||||
<constraint firstItem="VYW-sX-LN2" firstAttribute="top" secondItem="moz-ZW-I46" secondAttribute="bottom" constant="20" id="P9l-74-III"/>
|
||||
<constraint firstAttribute="trailing" secondItem="VCP-xz-0jI" secondAttribute="trailing" constant="20" id="Vxd-7K-b1F"/>
|
||||
<constraint firstItem="VCP-xz-0jI" firstAttribute="top" secondItem="VYW-sX-LN2" secondAttribute="bottom" constant="20" id="ccu-p4-dcq"/>
|
||||
<constraint firstItem="bct-zW-zKf" firstAttribute="top" secondItem="VCP-xz-0jI" secondAttribute="bottom" constant="20" id="dgi-9A-uCh"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="moz-ZW-I46" secondAttribute="trailing" constant="20" id="nUH-DD-Xsg"/>
|
||||
<constraint firstItem="bct-zW-zKf" firstAttribute="leading" secondItem="MqL-7s-HoR" secondAttribute="leading" constant="20" id="qvo-d9-w65"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="displayList" destination="t7B-Q7-Ssj" id="ZaZ-6Q-b35"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="lVu-28-yuM" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="380" y="544.5"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import os.log
|
|||
|
||||
class FriendlyNameCellView: NSTableCellView {
|
||||
var display: Display?
|
||||
let prefs = UserDefaults.standard
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
25
MonitorControl/UI/Cells/HideOsdCellView.swift
Normal file
25
MonitorControl/UI/Cells/HideOsdCellView.swift
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import Cocoa
|
||||
import os.log
|
||||
|
||||
class HideOsdCellView: NSTableCellView {
|
||||
@IBOutlet var button: NSButton!
|
||||
var display: Display?
|
||||
let prefs = UserDefaults.standard
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
}
|
||||
|
||||
@IBAction func buttonToggled(_ sender: NSButton) {
|
||||
if let display = display {
|
||||
switch sender.state {
|
||||
case .on:
|
||||
display.hideOsd = true
|
||||
case .off:
|
||||
display.hideOsd = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
MonitorControl/UI/Cells/LongerDelayCellView.swift
Normal file
41
MonitorControl/UI/Cells/LongerDelayCellView.swift
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import Cocoa
|
||||
import os.log
|
||||
|
||||
class LongerDelayCellView: NSTableCellView {
|
||||
@IBOutlet var button: NSButton!
|
||||
var display: Display?
|
||||
let prefs = UserDefaults.standard
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
super.draw(dirtyRect)
|
||||
}
|
||||
|
||||
@IBAction func buttonToggled(_ sender: NSButton) {
|
||||
if let display = self.display {
|
||||
switch sender.state {
|
||||
case .on:
|
||||
let alert: NSAlert = NSAlert()
|
||||
alert.messageText = NSLocalizedString("Enable Longer Delay?", comment: "Shown in the alert dialog")
|
||||
alert.informativeText = NSLocalizedString("Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.", comment: "Shown in the alert dialog")
|
||||
alert.addButton(withTitle: NSLocalizedString("Yes", comment: "Shown in the alert dialog"))
|
||||
alert.addButton(withTitle: NSLocalizedString("No", comment: "Shown in the alert dialog"))
|
||||
alert.alertStyle = NSAlert.Style.critical
|
||||
|
||||
if let window = self.window {
|
||||
alert.beginSheetModal(for: window, completionHandler: { modalResponse in
|
||||
if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
|
||||
Utils.setStartAtLogin(enabled: false)
|
||||
display.needsLongerDelay = true
|
||||
} else {
|
||||
sender.state = .off
|
||||
}
|
||||
})
|
||||
}
|
||||
case .off:
|
||||
display.needsLongerDelay = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
MonitorControl/UI/Cells/PollingCountCellView.swift
Normal file
24
MonitorControl/UI/Cells/PollingCountCellView.swift
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import Cocoa
|
||||
import os.log
|
||||
|
||||
class PollingCountCellView: NSTableCellView {
|
||||
var display: Display?
|
||||
|
||||
@IBAction func valueChanged(_ sender: NSTextField) {
|
||||
if let display = display {
|
||||
let newValue = sender.stringValue
|
||||
let originalValue = "\(display.getPollingCount())"
|
||||
|
||||
if newValue.isEmpty {
|
||||
self.textField?.stringValue = originalValue
|
||||
}
|
||||
|
||||
if newValue != originalValue,
|
||||
!newValue.isEmpty,
|
||||
let newValue = Int(newValue) {
|
||||
display.setPollingCount(newValue)
|
||||
os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
MonitorControl/UI/Cells/PollingModeCellView.swift
Normal file
31
MonitorControl/UI/Cells/PollingModeCellView.swift
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import Cocoa
|
||||
import os.log
|
||||
|
||||
/*
|
||||
menu tags:
|
||||
0: none
|
||||
1: minimal
|
||||
2: normal
|
||||
3: heavy
|
||||
4: custom
|
||||
We use these tags as a way to mark selection
|
||||
*/
|
||||
class PollingModeCellView: NSTableCellView {
|
||||
var display: Display?
|
||||
@IBOutlet var pollingModeMenu: NSPopUpButtonCell!
|
||||
|
||||
var didChangePollingMode: ((_ pollingModeInt: Int) -> Void)?
|
||||
|
||||
@IBAction func valueChanged(_ sender: NSPopUpButton) {
|
||||
if let display = display {
|
||||
let newValue = sender.selectedTag()
|
||||
let originalValue = display.getPollingMode()
|
||||
|
||||
if newValue != originalValue {
|
||||
display.setPollingMode(newValue)
|
||||
self.didChangePollingMode?(newValue)
|
||||
os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
import Cocoa
|
||||
import DDC
|
||||
import MASPreferences
|
||||
import os.log
|
||||
|
||||
class AdvancedPrefsViewController: NSViewController, MASPreferencesViewController, NSTableViewDataSource, NSTableViewDelegate {
|
||||
var viewIdentifier: String = "Advanced"
|
||||
var toolbarItemLabel: String? = NSLocalizedString("Advanced", comment: "Shown in the main prefs window")
|
||||
var toolbarItemImage: NSImage? = NSImage(named: NSImage.advancedName)
|
||||
let prefs = UserDefaults.standard
|
||||
|
||||
var displays: [Display] = []
|
||||
var displayManager: DisplayManager?
|
||||
|
||||
enum DisplayColumn: Int {
|
||||
case friendlyName
|
||||
case identifier
|
||||
case pollingMode
|
||||
case pollingCount
|
||||
case longerDelay
|
||||
case hideOsd
|
||||
}
|
||||
|
||||
@IBOutlet var displayList: NSTableView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.loadDisplayList), name: .displayListUpdate, object: nil)
|
||||
self.loadDisplayList()
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@IBAction func resetPrefsClicked(_: NSButton) {
|
||||
let alert: NSAlert = NSAlert()
|
||||
alert.messageText = NSLocalizedString("Reset Preferences?", comment: "Shown in the alert dialog")
|
||||
alert.informativeText = NSLocalizedString("Are you sure you want to reset all preferences?", comment: "Shown in the alert dialog")
|
||||
alert.addButton(withTitle: NSLocalizedString("Yes", comment: "Shown in the alert dialog"))
|
||||
alert.addButton(withTitle: NSLocalizedString("No", comment: "Shown in the alert dialog"))
|
||||
alert.alertStyle = NSAlert.Style.warning
|
||||
|
||||
if let window = self.view.window {
|
||||
alert.beginSheetModal(for: window, completionHandler: { modalResponse in
|
||||
if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
|
||||
if let bundleID = Bundle.main.bundleIdentifier {
|
||||
UserDefaults.standard.removePersistentDomain(forName: bundleID)
|
||||
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.preferenceReset.rawValue), object: nil)
|
||||
os_log("Resetting all preferences.")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func helpClicked(_: NSButton) {
|
||||
if let url = URL(string: "https://github.com/the0neyouseek/MonitorControl/wiki/Advanced-Preferences") {
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func loadDisplayList() {
|
||||
if let displays = displayManager?.getDisplays() {
|
||||
self.displays = displays
|
||||
self.displayList.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
func numberOfRows(in _: NSTableView) -> Int {
|
||||
return self.displays.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
guard let tableColumn = tableColumn,
|
||||
let columnIndex = tableView.tableColumns.firstIndex(of: tableColumn),
|
||||
let column = DisplayColumn(rawValue: columnIndex) else {
|
||||
return nil
|
||||
}
|
||||
let display = self.displays[row]
|
||||
let pollingMode = display.getPollingMode()
|
||||
|
||||
switch column {
|
||||
case .pollingMode:
|
||||
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? PollingModeCellView {
|
||||
cell.display = display
|
||||
cell.pollingModeMenu.selectItem(withTag: pollingMode)
|
||||
cell.didChangePollingMode = { _ in
|
||||
// if the polling mode changed, reload the row so we can enable/disable the PollingCount field
|
||||
tableView.reloadData(forRowIndexes: [row], columnIndexes: [DisplayColumn.pollingCount.rawValue])
|
||||
}
|
||||
return cell
|
||||
}
|
||||
case .pollingCount:
|
||||
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? PollingCountCellView {
|
||||
cell.textField?.stringValue = "\(display.getPollingCount())"
|
||||
cell.display = display
|
||||
cell.textField?.isEnabled = pollingMode == 4
|
||||
return cell
|
||||
}
|
||||
case .longerDelay:
|
||||
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? LongerDelayCellView {
|
||||
cell.button.state = display.needsLongerDelay ? .on : .off
|
||||
cell.display = display
|
||||
return cell
|
||||
}
|
||||
case .hideOsd:
|
||||
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? HideOsdCellView {
|
||||
cell.button.state = display.hideOsd ? .on : .off
|
||||
cell.display = display
|
||||
return cell
|
||||
}
|
||||
default:
|
||||
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? NSTableCellView {
|
||||
cell.textField?.stringValue = self.getText(for: column, with: display)
|
||||
return cell
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func getText(for column: DisplayColumn, with display: Display) -> String {
|
||||
switch column {
|
||||
case .friendlyName:
|
||||
return display.getFriendlyName()
|
||||
case .identifier:
|
||||
return "\(display.identifier)"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@ class DisplayPrefsViewController: NSViewController, MASPreferencesViewController
|
|||
let prefs = UserDefaults.standard
|
||||
|
||||
var displays: [Display] = []
|
||||
var displayManager: DisplayManager?
|
||||
|
||||
enum DisplayColumn: Int {
|
||||
case checkbox
|
||||
case ddc
|
||||
|
|
@ -25,12 +27,19 @@ class DisplayPrefsViewController: NSViewController, MASPreferencesViewController
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.allScreens.state = self.prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? .on : .off
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.loadDisplayList), name: .displayListUpdate, object: nil)
|
||||
self.loadDisplayList()
|
||||
}
|
||||
|
||||
override func viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
self.allScreens.state = self.prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? .on : .off
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
@IBAction func allScreensTouched(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case .on:
|
||||
|
|
@ -47,17 +56,10 @@ class DisplayPrefsViewController: NSViewController, MASPreferencesViewController
|
|||
|
||||
// MARK: - Table datasource
|
||||
|
||||
func loadDisplayList() {
|
||||
for screen in NSScreen.screens {
|
||||
let id = screen.displayID
|
||||
|
||||
let name = screen.displayName ?? NSLocalizedString("Unknown", comment: "Unknown display name")
|
||||
let isEnabled = (prefs.object(forKey: "\(id)-state") as? Bool) ?? true
|
||||
|
||||
let display = Display(id, name: name, isBuiltin: screen.isBuiltin, isEnabled: isEnabled)
|
||||
self.displays.append(display)
|
||||
@objc func loadDisplayList() {
|
||||
if let displays = self.displayManager?.getDisplays() {
|
||||
self.displays = displays
|
||||
}
|
||||
|
||||
self.displayList.reloadData()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ class KeysPrefsViewController: NSViewController, MASPreferencesViewController {
|
|||
|
||||
@IBOutlet var listenFor: NSPopUpButton!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
override func viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
self.listenFor.selectItem(at: self.prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,32 +14,28 @@ class MainPrefsViewController: NSViewController, MASPreferencesViewController {
|
|||
@IBOutlet var showContrastSlider: NSButton!
|
||||
@IBOutlet var lowerContrast: NSButton!
|
||||
|
||||
@available(macOS, deprecated: 10.10)
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
let startAtLogin = (SMCopyAllJobDictionaries(kSMDomainUserLaunchd).takeRetainedValue() as? [[String: AnyObject]])?.first { $0["Label"] as? String == "\(Bundle.main.bundleIdentifier!)Helper" }?["OnDemand"] as? Bool ?? false
|
||||
|
||||
self.startAtLogin.state = startAtLogin ? .on : .off
|
||||
self.showContrastSlider.state = self.prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) ? .on : .off
|
||||
self.lowerContrast.state = self.prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) ? .on : .off
|
||||
self.setVersionNumber()
|
||||
}
|
||||
|
||||
@IBAction func startAtLoginClicked(_ sender: NSButton) {
|
||||
let identifier = "\(Bundle.main.bundleIdentifier!)Helper" as CFString
|
||||
@available(macOS, deprecated: 10.10)
|
||||
override func viewWillAppear() {
|
||||
super.viewWillAppear()
|
||||
let startAtLogin = (SMCopyAllJobDictionaries(kSMDomainUserLaunchd).takeRetainedValue() as? [[String: AnyObject]])?.first { $0["Label"] as? String == "\(Bundle.main.bundleIdentifier!)Helper" }?["OnDemand"] as? Bool ?? false
|
||||
self.startAtLogin.state = startAtLogin ? .on : .off
|
||||
self.showContrastSlider.state = self.prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) ? .on : .off
|
||||
self.lowerContrast.state = self.prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) ? .on : .off
|
||||
}
|
||||
|
||||
@IBAction func startAtLoginClicked(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case .on:
|
||||
SMLoginItemSetEnabled(identifier, true)
|
||||
Utils.setStartAtLogin(enabled: true)
|
||||
case .off:
|
||||
SMLoginItemSetEnabled(identifier, false)
|
||||
Utils.setStartAtLogin(enabled: false)
|
||||
default: break
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
os_log("Toggle start at login state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
|
||||
#endif
|
||||
}
|
||||
|
||||
@IBAction func showContrastSliderClicked(_ sender: NSButton) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue