diff --git a/.bartycrouch.toml b/.bartycrouch.toml index 278293d4..48901f65 100644 --- a/.bartycrouch.toml +++ b/.bartycrouch.toml @@ -1,5 +1,5 @@ [update] -tasks = ["interfaces", "code", "transform", "normalize"] +tasks = ["interfaces", "code", "normalize"] [update.interfaces] paths = ["."] diff --git a/.github/Icon-1024.png b/.github/Icon-1024.png new file mode 100644 index 00000000..f8dcd074 Binary files /dev/null and b/.github/Icon-1024.png differ diff --git a/.github/MonitorControl Icon.fig b/.github/MonitorControl Icon.fig new file mode 100644 index 00000000..6e65225e Binary files /dev/null and b/.github/MonitorControl Icon.fig differ diff --git a/.github/menuadvanced.png b/.github/menuadvanced.png deleted file mode 100644 index 1d0e2777..00000000 Binary files a/.github/menuadvanced.png and /dev/null differ diff --git a/.github/menudisplay.png b/.github/menudisplay.png deleted file mode 100644 index 36152cb3..00000000 Binary files a/.github/menudisplay.png and /dev/null differ diff --git a/.github/menugeneral.png b/.github/menugeneral.png deleted file mode 100644 index 1c5d9f4d..00000000 Binary files a/.github/menugeneral.png and /dev/null differ diff --git a/.github/menukeys.png b/.github/menukeys.png deleted file mode 100644 index 8e4673c9..00000000 Binary files a/.github/menukeys.png and /dev/null differ diff --git a/.github/menulet.png b/.github/menulet.png deleted file mode 100644 index 73e9a4aa..00000000 Binary files a/.github/menulet.png and /dev/null differ diff --git a/.github/osd.jpg b/.github/osd.jpg deleted file mode 100644 index 62bc7517..00000000 Binary files a/.github/osd.jpg and /dev/null differ diff --git a/.github/screenshot.png b/.github/screenshot.png new file mode 100644 index 00000000..cb099847 Binary files /dev/null and b/.github/screenshot.png differ diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj index b2c98bc0..6aa44fdb 100644 --- a/MonitorControl.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -13,35 +13,33 @@ 28D1DDF3227FC8C6004CB494 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB01D9A4016007BCDC5 /* Assets.xcassets */; }; 56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */; }; 56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB01D9A4016007BCDC5 /* Assets.xcassets */; }; - 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 */; }; - 6CB2B64B263EDA6600F0E0EF /* OSD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0A987D61F77B290009B603D /* OSD.framework */; }; 6CBFE27A23DB266000D1BC41 /* Display.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBFE27923DB266000D1BC41 /* Display.swift */; }; 6CBFE27C23DB27A200D1BC41 /* InternalDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBFE27B23DB27A200D1BC41 /* InternalDisplay.swift */; }; 6CC260F6256AD8F900613714 /* Preferences+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC260F5256AD8F900613714 /* Preferences+Extension.swift */; }; - 6CCB278622D5315200619B05 /* HideOsdCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCB278522D5315200619B05 /* HideOsdCellView.swift */; }; 6CD35F53264FFFC6001F1344 /* SimplyCoreAudio in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F52264FFFC6001F1344 /* SimplyCoreAudio */; }; 6CD35F5626500008001F1344 /* MediaKeyTap in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F5526500008001F1344 /* MediaKeyTap */; }; 6CD35F592650002E001F1344 /* DDC in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F582650002E001F1344 /* DDC */; }; 6CD35F5C2650003F001F1344 /* Preferences in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F5B2650003F001F1344 /* Preferences */; }; - 6CD444C322D4FBB8005BFD3D /* LongerDelayCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */; }; 6CDA0FCF26485A8300F52125 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CDA0FCD26485A8300F52125 /* Main.storyboard */; }; + AA062E8A26C9A039007E628C /* DisplaysPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA062E8926C9A039007E628C /* DisplaysPrefsViewController.swift */; }; + AA062E8E26CA7BE5007E628C /* DisplaysPrefsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA062E8D26CA7BE5007E628C /* DisplaysPrefsCellView.swift */; }; + AA16139B26BE772E00DCF027 /* Arm64DDCUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA16139A26BE772E00DCF027 /* Arm64DDCUtils.swift */; }; + AA3B4A2826AE103C00B74CD2 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AA3B4A2726AE103C00B74CD2 /* README.md */; }; + AA665A5D26C5892800FEF2C1 /* AboutPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA665A5C26C5892800FEF2C1 /* AboutPrefsViewController.swift */; }; + AA9AE86F26B5BF3D00B6CA65 /* OSD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA9AE86E26B5BF3D00B6CA65 /* OSD.framework */; }; + AA9AE87126B5BFB700B6CA65 /* CoreDisplay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA9AE87026B5BFB700B6CA65 /* CoreDisplay.framework */; }; + AADB625A26BC196900DFFAA5 /* DisplayServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AADB625926BC196900DFFAA5 /* DisplayServices.framework */; }; 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 */; }; F01B069F228221B7008E64DB /* SliderHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B068F228221B7008E64DB /* SliderHandler.swift */; }; F01B06A1228221B7008E64DB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F01B0692228221B7008E64DB /* MainMenu.xib */; }; F03A8DF21FFBAA6F0034DC27 /* ExternalDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A8DF11FFBAA6F0034DC27 /* ExternalDisplay.swift */; }; - F03FE4C0228DF62B001F59A4 /* FriendlyNameCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */; }; F0445D3820023E710025AE82 /* MainPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3720023E710025AE82 /* MainPrefsViewController.swift */; }; - F0445D3D200254FA0025AE82 /* KeysPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */; }; - F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */; }; F06792EA200A73460066C438 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06792E9200A73460066C438 /* main.swift */; }; F06792F6200A745F0066C438 /* MonitorControlHelper.app in [Login] Copy Helper to start at Login */ = {isa = PBXBuildFile; fileRef = F06792E7200A73460066C438 /* MonitorControlHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; FE4E0896249D584C003A50BB /* OSDUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4E0895249D584C003A50BB /* OSDUtils.swift */; }; @@ -65,16 +63,8 @@ 1E7ECF3F22A4552400E4E701 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = ""; }; 1E7ECF4122A4553000E4E701 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/MainMenu.strings; sourceTree = ""; }; 2894D9B72280B30500DF58DA /* CGDirectDisplayID+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGDirectDisplayID+Extension.swift"; sourceTree = ""; }; - 28D1DDE2227FB7D0004CB494 /* MediaKeyTap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaKeyTap.framework; path = Carthage/Build/Mac/MediaKeyTap.framework; sourceTree = ""; }; - 28D1DDE3227FB7D0004CB494 /* AMCoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AMCoreAudio.framework; path = Carthage/Build/Mac/AMCoreAudio.framework; sourceTree = ""; }; - 28D1DDE4227FB7D0004CB494 /* MASPreferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MASPreferences.framework; path = Carthage/Build/Mac/MASPreferences.framework; sourceTree = ""; }; 28D1DDEC227FB8F2004CB494 /* EDID+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EDID+Extension.swift"; sourceTree = ""; }; - 28D1DDED227FB944004CB494 /* DDC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DDC.framework; path = Carthage/Build/Mac/DDC.framework; sourceTree = ""; }; 28D1DDF1227FBE71004CB494 /* NSScreen+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSScreen+Extension.swift"; sourceTree = ""; }; - 28D1DE0E227FD005004CB494 /* MASPreferences.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = MASPreferences.framework.dSYM; path = Carthage/Build/Mac/MASPreferences.framework.dSYM; sourceTree = ""; }; - 28D1DE0F227FD006004CB494 /* MediaKeyTap.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = MediaKeyTap.framework.dSYM; path = Carthage/Build/Mac/MediaKeyTap.framework.dSYM; sourceTree = ""; }; - 28D1DE10227FD006004CB494 /* AMCoreAudio.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = AMCoreAudio.framework.dSYM; path = Carthage/Build/Mac/AMCoreAudio.framework.dSYM; sourceTree = ""; }; - 28D1DE11227FD006004CB494 /* DDC.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = DDC.framework.dSYM; path = Carthage/Build/Mac/DDC.framework.dSYM; sourceTree = ""; }; 2EAA5B7E24BF9E9A00937821 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/MainMenu.strings; sourceTree = ""; }; 2EAA5B7F24BF9E9A00937821 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; 3CCA5F962442EFF800B4DB84 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/MainMenu.strings; sourceTree = ""; }; @@ -84,23 +74,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 = ""; }; 56754EB01D9A4016007BCDC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsViewController.swift; sourceTree = ""; tabWidth = 4; }; 6C20466B23153E4F00859767 /* Display+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Display+Extension.swift"; sourceTree = ""; }; 6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlyIntegerValueFormatter.swift; sourceTree = ""; }; 6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollingMode.swift; sourceTree = ""; }; 6C85EFD922C941B000227EA1 /* DisplayManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayManager.swift; sourceTree = ""; }; - 6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollingModeCellView.swift; sourceTree = ""; }; - 6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = PollingCountCellView.swift; sourceTree = ""; tabWidth = 4; }; 6C85EFE022CC00AD00227EA1 /* NSNotification+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSNotification+Extension.swift"; sourceTree = ""; }; 6CAD134F23624CC1009BD53F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/MainMenu.strings; sourceTree = ""; }; 6CAD135023624CC1009BD53F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 6CBFE27923DB266000D1BC41 /* Display.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Display.swift; sourceTree = ""; }; 6CBFE27B23DB27A200D1BC41 /* InternalDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalDisplay.swift; sourceTree = ""; }; 6CC260F5256AD8F900613714 /* Preferences+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Extension.swift"; sourceTree = ""; }; - 6CC260F9256ADA7400613714 /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Carthage/Build/Mac/Preferences.framework; sourceTree = ""; }; - 6CCB278522D5315200619B05 /* HideOsdCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideOsdCellView.swift; sourceTree = ""; }; - 6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongerDelayCellView.swift; sourceTree = ""; }; - 6CDA0FCB26485A7600F52125 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = MonitorControl/UI/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; }; 6CDA0FCE26485A8300F52125 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 6CDA0FD026485AA100F52125 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = ""; }; 6CDA0FD126485AA300F52125 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = ""; }; @@ -111,6 +94,17 @@ 6CDA0FD626485AAC00F52125 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Main.strings; sourceTree = ""; }; 6CDA0FD726485AAC00F52125 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Main.strings; sourceTree = ""; }; 6CDA0FD826485AAE00F52125 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Main.strings; sourceTree = ""; }; + AA062E8926C9A039007E628C /* DisplaysPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaysPrefsViewController.swift; sourceTree = ""; }; + AA062E8D26CA7BE5007E628C /* DisplaysPrefsCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaysPrefsCellView.swift; sourceTree = ""; }; + AA16139A26BE772E00DCF027 /* Arm64DDCUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arm64DDCUtils.swift; sourceTree = ""; }; + AA3B4A2726AE103C00B74CD2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + AA665A5C26C5892800FEF2C1 /* AboutPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutPrefsViewController.swift; sourceTree = ""; }; + AA6686F026B8172E00AF74A2 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Main.strings; sourceTree = ""; }; + AA6686F126B8172E00AF74A2 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/MainMenu.strings; sourceTree = ""; }; + AA6686F226B8172E00AF74A2 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; + AA9AE86E26B5BF3D00B6CA65 /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OSD.framework; path = ../../../../../System/Library/PrivateFrameworks/OSD.framework; sourceTree = ""; }; + AA9AE87026B5BFB700B6CA65 /* CoreDisplay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreDisplay.framework; path = ../../../../../System/Library/Frameworks/CoreDisplay.framework; sourceTree = ""; }; + AADB625926BC196900DFFAA5 /* DisplayServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DisplayServices.framework; path = ../../../../../System/Library/PrivateFrameworks/DisplayServices.framework; sourceTree = ""; }; B0C4810623357CE500053F91 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; B0C4810823357CE500053F91 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/MainMenu.strings; sourceTree = ""; }; F01B0681228221B6008E64DB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; @@ -119,22 +113,17 @@ F01B0684228221B6008E64DB /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; F01B0685228221B6008E64DB /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; F01B0686228221B6008E64DB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - F01B068E228221B6008E64DB /* ButtonCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonCellView.swift; sourceTree = ""; }; F01B068F228221B7008E64DB /* SliderHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderHandler.swift; sourceTree = ""; }; F01B0693228221B7008E64DB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; F01B06A222822208008E64DB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = ""; }; F01B06A32282220A008E64DB /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/MainMenu.strings; sourceTree = ""; }; F01B06A42282220D008E64DB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/MainMenu.strings; sourceTree = ""; }; F03A8DF11FFBAA6F0034DC27 /* ExternalDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalDisplay.swift; sourceTree = ""; }; - F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendlyNameCellView.swift; sourceTree = ""; }; F0445D3720023E710025AE82 /* MainPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPrefsViewController.swift; sourceTree = ""; }; - F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeysPrefsViewController.swift; sourceTree = ""; }; - F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayPrefsViewController.swift; sourceTree = ""; }; F06792E7200A73460066C438 /* MonitorControlHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControlHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; F06792E9200A73460066C438 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; F06792F0200A73470066C438 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F06792F1200A73470066C438 /* MonitorControlHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MonitorControlHelper.entitlements; sourceTree = ""; }; - F0A987D61F77B290009B603D /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OSD.framework; sourceTree = ""; }; FE4E0895249D584C003A50BB /* OSDUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSDUtils.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -143,11 +132,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + AA9AE87126B5BFB700B6CA65 /* CoreDisplay.framework in Frameworks */, 6CD35F53264FFFC6001F1344 /* SimplyCoreAudio in Frameworks */, 6CD35F5626500008001F1344 /* MediaKeyTap in Frameworks */, - 6CB2B64B263EDA6600F0E0EF /* OSD.framework in Frameworks */, 6CD35F592650002E001F1344 /* DDC in Frameworks */, + AA9AE86F26B5BF3D00B6CA65 /* OSD.framework in Frameworks */, 6CD35F5C2650003F001F1344 /* Preferences in Frameworks */, + AADB625A26BC196900DFFAA5 /* DisplayServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -164,16 +155,9 @@ 28D1DDD1227FB759004CB494 /* Frameworks */ = { isa = PBXGroup; children = ( - 6CC260F9256ADA7400613714 /* Preferences.framework */, - 28D1DDE3227FB7D0004CB494 /* AMCoreAudio.framework */, - 28D1DE10227FD006004CB494 /* AMCoreAudio.framework.dSYM */, - 28D1DDED227FB944004CB494 /* DDC.framework */, - 28D1DE11227FD006004CB494 /* DDC.framework.dSYM */, - 28D1DDE4227FB7D0004CB494 /* MASPreferences.framework */, - 28D1DE0E227FD005004CB494 /* MASPreferences.framework.dSYM */, - 28D1DDE2227FB7D0004CB494 /* MediaKeyTap.framework */, - 28D1DE0F227FD006004CB494 /* MediaKeyTap.framework.dSYM */, - F0A987D61F77B290009B603D /* OSD.framework */, + AA9AE86E26B5BF3D00B6CA65 /* OSD.framework */, + AA9AE87026B5BFB700B6CA65 /* CoreDisplay.framework */, + AADB625926BC196900DFFAA5 /* DisplayServices.framework */, ); name = Frameworks; sourceTree = ""; @@ -194,6 +178,7 @@ 56754EA21D9A4016007BCDC5 = { isa = PBXGroup; children = ( + AA3B4A2726AE103C00B74CD2 /* README.md */, 28D1DDD1227FB759004CB494 /* Frameworks */, 56754EAD1D9A4016007BCDC5 /* MonitorControl */, F06792E8200A73460066C438 /* MonitorControlHelper */, @@ -245,20 +230,6 @@ path = Manager; sourceTree = ""; }; - 6C85EFDB22CBA77600227EA1 /* Cells */ = { - isa = PBXGroup; - children = ( - 6CDA0FCA26485A7600F52125 /* Main.storyboard */, - F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */, - F01B068E228221B6008E64DB /* ButtonCellView.swift */, - 6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */, - 6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */, - 6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */, - 6CCB278522D5315200619B05 /* HideOsdCellView.swift */, - ); - path = Cells; - sourceTree = ""; - }; F01B067F228221B6008E64DB /* Support */ = { isa = PBXGroup; children = ( @@ -268,6 +239,7 @@ 6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */, 6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */, FE4E0895249D584C003A50BB /* OSDUtils.swift */, + AA16139A26BE772E00DCF027 /* Arm64DDCUtils.swift */, ); path = Support; sourceTree = ""; @@ -275,7 +247,6 @@ F01B0687228221B6008E64DB /* UI */ = { isa = PBXGroup; children = ( - 6C85EFDB22CBA77600227EA1 /* Cells */, 6CDA0FCD26485A8300F52125 /* Main.storyboard */, F01B0692228221B7008E64DB /* MainMenu.xib */, F01B068F228221B7008E64DB /* SliderHandler.swift */, @@ -286,10 +257,10 @@ F0445D3620023D5B0025AE82 /* View Controllers */ = { isa = PBXGroup; children = ( - F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */, - F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */, F0445D3720023E710025AE82 /* MainPrefsViewController.swift */, - 6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */, + AA665A5C26C5892800FEF2C1 /* AboutPrefsViewController.swift */, + AA062E8926C9A039007E628C /* DisplaysPrefsViewController.swift */, + AA062E8D26CA7BE5007E628C /* DisplaysPrefsCellView.swift */, ); path = "View Controllers"; sourceTree = ""; @@ -390,6 +361,7 @@ it, ja, pl, + hu, ); mainGroup = 56754EA21D9A4016007BCDC5; packageReferences = ( @@ -415,6 +387,7 @@ files = ( 56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */, 6CDA0FCF26485A8300F52125 /* Main.storyboard in Resources */, + AA3B4A2826AE103C00B74CD2 /* README.md in Resources */, F01B0699228221B7008E64DB /* Localizable.strings in Resources */, F01B06A1228221B7008E64DB /* MainMenu.xib in Resources */, ); @@ -526,25 +499,20 @@ 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 */, + AA062E8A26C9A039007E628C /* DisplaysPrefsViewController.swift in Sources */, 6C2EA1CD228F644B00060E3F /* OnlyIntegerValueFormatter.swift in Sources */, 2894D9B82280B30500DF58DA /* CGDirectDisplayID+Extension.swift in Sources */, - 6CCB278622D5315200619B05 /* HideOsdCellView.swift in Sources */, 6CC260F6256AD8F900613714 /* Preferences+Extension.swift in Sources */, - 6CD444C322D4FBB8005BFD3D /* LongerDelayCellView.swift in Sources */, - F03FE4C0228DF62B001F59A4 /* FriendlyNameCellView.swift in Sources */, + AA665A5D26C5892800FEF2C1 /* AboutPrefsViewController.swift in Sources */, 6C2EA1CF228F7DFB00060E3F /* PollingMode.swift in Sources */, 6CBFE27C23DB27A200D1BC41 /* InternalDisplay.swift in Sources */, + AA062E8E26CA7BE5007E628C /* DisplaysPrefsCellView.swift in Sources */, FE4E0896249D584C003A50BB /* OSDUtils.swift in Sources */, 6CBFE27A23DB266000D1BC41 /* Display.swift in Sources */, F03A8DF21FFBAA6F0034DC27 /* ExternalDisplay.swift in Sources */, - F0445D40200259C10025AE82 /* DisplayPrefsViewController.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 */, + AA16139B26BE772E00DCF027 /* Arm64DDCUtils.swift in Sources */, F0445D3820023E710025AE82 /* MainPrefsViewController.swift in Sources */, 28D1DDF2227FBE71004CB494 /* NSScreen+Extension.swift in Sources */, F01B069F228221B7008E64DB /* SliderHandler.swift in Sources */, @@ -564,14 +532,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 6CDA0FCA26485A7600F52125 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 6CDA0FCB26485A7600F52125 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; 6CDA0FCD26485A8300F52125 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -585,6 +545,7 @@ 6CDA0FD626485AAC00F52125 /* pl */, 6CDA0FD726485AAC00F52125 /* ru */, 6CDA0FD826485AAE00F52125 /* uk */, + AA6686F026B8172E00AF74A2 /* hu */, ); name = Main.storyboard; sourceTree = ""; @@ -601,6 +562,7 @@ 6CAD135023624CC1009BD53F /* it */, 3CCA5F972442EFF800B4DB84 /* ja */, 2EAA5B7F24BF9E9A00937821 /* pl */, + AA6686F226B8172E00AF74A2 /* hu */, ); name = Localizable.strings; sourceTree = ""; @@ -618,6 +580,7 @@ 6CAD134F23624CC1009BD53F /* it */, 3CCA5F962442EFF800B4DB84 /* ja */, 2EAA5B7E24BF9E9A00937821 /* pl */, + AA6686F126B8172E00AF74A2 /* hu */, ); name = MainMenu.xib; sourceTree = ""; @@ -747,20 +710,29 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 631; + CURRENT_PROJECT_VERSION = 1179; DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(PROJECT_DIR)/**", + "/System/Library/PrivateFrameworks/**", + ); INFOPLIST_FILE = MonitorControl/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 3.0.0; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl/Support/Bridging-Header.h"; SWIFT_VERSION = 5.0; + SYSTEM_FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); }; name = Debug; }; @@ -769,23 +741,32 @@ buildSettings = { ARCHS = x86_64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 631; - DEVELOPMENT_TEAM = CYC8C8R4K9; + CURRENT_PROJECT_VERSION = 1179; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(PROJECT_DIR)/**", + "/System/Library/PrivateFrameworks/**", + ); INFOPLIST_FILE = MonitorControl/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.2.0; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 3.0.0; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl/Support/Bridging-Header.h"; SWIFT_VERSION = 5.0; + SYSTEM_FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); }; name = Release; }; @@ -809,7 +790,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.1.0; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 3.0.0; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -825,11 +807,11 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements; - CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 631; - DEVELOPMENT_TEAM = CYC8C8R4K9; + DEVELOPMENT_TEAM = ""; ENABLE_HARDENED_RUNTIME = YES; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = MonitorControlHelper/Info.plist; @@ -837,7 +819,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 2.1.0; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 3.0.0; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/MonitorControl/AppDelegate.swift b/MonitorControl/AppDelegate.swift index fcee1db1..690c6b1f 100644 --- a/MonitorControl/AppDelegate.swift +++ b/MonitorControl/AppDelegate.swift @@ -1,5 +1,4 @@ import Cocoa -import DDC import Foundation import MediaKeyTap import os.log @@ -12,30 +11,27 @@ let prefs = UserDefaults.standard @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @IBOutlet var statusMenu: NSMenu! - let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) - var monitorItems: [NSMenuItem] = [] var mediaKeyTap: MediaKeyTap? var keyRepeatTimers: [MediaKey: Timer] = [:] - let coreAudio = SimplyCoreAudio() var accessibilityObserver: NSObjectProtocol! - + var reconfigureID: Int = 0 // dispatched reconfigure command ID + var sleepID: Int = 0 // Don't reconfigure display as the system or display is sleeping or wake just recently. + let debugSw: Bool = false lazy var preferencesWindowController: PreferencesWindowController = { let storyboard = NSStoryboard(name: "Main", bundle: Bundle.main) let mainPrefsVc = storyboard.instantiateController(withIdentifier: "MainPrefsVC") as? MainPrefsViewController - let keyPrefsVc = storyboard.instantiateController(withIdentifier: "KeysPrefsVC") as? KeysPrefsViewController - let displayPrefsVc = storyboard.instantiateController(withIdentifier: "DisplayPrefsVC") as? DisplayPrefsViewController - let advancedPrefsVc = storyboard.instantiateController(withIdentifier: "AdvancedPrefsVC") as? AdvancedPrefsViewController + let displaysPrefsVc = storyboard.instantiateController(withIdentifier: "DisplaysPrefsVC") as? DisplaysPrefsViewController + let aboutPrefsVc = storyboard.instantiateController(withIdentifier: "AboutPrefsVC") as? AboutPrefsViewController return PreferencesWindowController( preferencePanes: [ mainPrefsVc!, - keyPrefsVc!, - displayPrefsVc!, - advancedPrefsVc!, + displaysPrefsVc!, + aboutPrefsVc!, ], - animated: false // causes glitchy animations + animated: true ) }() @@ -43,12 +39,27 @@ class AppDelegate: NSObject, NSApplicationDelegate { app = self self.subscribeEventListeners() self.setDefaultPrefs() - self.updateMediaKeyTap() - self.statusItem.image = NSImage(named: "status") + if #available(macOS 11.0, *) { + self.statusItem.button?.image = NSImage(systemSymbolName: "sun.max", accessibilityDescription: "MonitorControl") + } else { + self.statusItem.button?.image = NSImage(named: "status") + } + self.statusItem.isVisible = prefs.bool(forKey: Utils.PrefKeys.hideMenuIcon.rawValue) ? false : true self.statusItem.menu = self.statusMenu self.checkPermissions() - CGDisplayRegisterReconfigurationCallback({ _, _, _ in app.updateDisplays() }, nil) - self.updateDisplays() + CGDisplayRegisterReconfigurationCallback({ _, _, _ in app.displayReconfigured() }, nil) + self.updateDisplays(firstrun: true) + } + + func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool { + self.prefsClicked(self) + return true + } + + func applicationWillTerminate(_: Notification) { + os_log("Goodbye!", type: .info) + DisplayManager.shared.resetSwBrightnessForAllDisplays() + self.statusItem.isVisible = true } @IBAction func quitClicked(_: AnyObject) { @@ -59,19 +70,19 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.preferencesWindowController.show() } - /// Set the default prefs of the app func setDefaultPrefs() { if !prefs.bool(forKey: Utils.PrefKeys.appAlreadyLaunched.rawValue) { prefs.set(true, forKey: Utils.PrefKeys.appAlreadyLaunched.rawValue) - prefs.set(false, forKey: Utils.PrefKeys.showContrast.rawValue) - prefs.set(false, forKey: Utils.PrefKeys.lowerContrast.rawValue) + prefs.set(true, forKey: Utils.PrefKeys.showVolume.rawValue) + prefs.set(false, forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) + prefs.set(true, forKey: Utils.PrefKeys.fallbackSw.rawValue) + prefs.set(false, forKey: Utils.PrefKeys.hideMenuIcon.rawValue) + prefs.set(false, forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) } } - // MARK: - Menu - - func clearDisplays() { + func clearMenu() { if self.statusMenu.items.count > 2 { var items: [NSMenuItem] = [] for i in 0 ..< self.statusMenu.items.count - 2 { @@ -82,35 +93,50 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.statusMenu.removeItem(item) } } - self.monitorItems = [] - DisplayManager.shared.clearDisplays() } - func updateDisplays() { - self.clearDisplays() - - for screen in NSScreen.screens { - let name: String - if #available(OSX 10.15, *) { - name = screen.localizedName - } else { - name = screen.displayName ?? NSLocalizedString("Unknown", comment: "Unknown display name") + func updateArm64AVServices() { + if Arm64DDCUtils.isArm64 { + os_log("arm64 AVService update requested", type: .info) + var displayIDs: [CGDirectDisplayID] = [] + for externalDisplay in DisplayManager.shared.getExternalDisplays() { + displayIDs.append(externalDisplay.identifier) } - let id = screen.displayID - let vendorNumber = screen.vendorNumber - let modelNumber = screen.modelNumber - let display: Display - if screen.isBuiltin { - display = InternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber) - } else { - display = ExternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber) + for serviceMatch in Arm64DDCUtils.getServiceMatches(displayIDs: displayIDs) { + for externalDisplay in DisplayManager.shared.getExternalDisplays() where externalDisplay.identifier == serviceMatch.displayID && serviceMatch.service != nil { + externalDisplay.arm64avService = serviceMatch.service + os_log("Display service match successful for display %{public}@", type: .info, String(serviceMatch.displayID)) + if !serviceMatch.isDiscouraged { + externalDisplay.arm64ddc = !debugSw ? true : false // MARK: (point of interest when testing) + } + } + } + os_log("AVService update done", type: .info) + } + } + + func displayReconfigured() { + self.reconfigureID += 1 + os_log("Bumping reconfigureID to %{public}@", type: .info, String(self.reconfigureID)) + if self.sleepID == 0 { + let dispatchedReconfigureID = self.reconfigureID + os_log("Display to be reconfigured with reconfigureID %{public}@", type: .info, String(dispatchedReconfigureID)) + DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { + self.updateDisplays(dispatchedReconfigureID: dispatchedReconfigureID) } - DisplayManager.shared.addDisplay(display: display) } + } - let ddcDisplays = DisplayManager.shared.getDdcCapableDisplays() - if ddcDisplays.count == 0 { + func updateMenus() { + self.clearMenu() + var controllableExternalDisplays: [ExternalDisplay] = [] + if prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) { + controllableExternalDisplays = DisplayManager.shared.getNonVirtualExternalDisplays() + } else { + controllableExternalDisplays = DisplayManager.shared.getDdcCapableDisplays() + } + if controllableExternalDisplays.count == 0 { let item = NSMenuItem() item.title = NSLocalizedString("No supported display found", comment: "Shown in menu") item.isEnabled = false @@ -118,41 +144,97 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.statusMenu.insertItem(item, at: 0) self.statusMenu.insertItem(NSMenuItem.separator(), at: 1) } else { - for display in ddcDisplays { + for display in controllableExternalDisplays { os_log("Supported display found: %{public}@", type: .info, "\(display.name) (Vendor: \(display.vendorNumber ?? 0), Model: \(display.modelNumber ?? 0))") - self.addDisplayToMenu(display: display, asSubMenu: ddcDisplays.count > 1) + let asSubmenu: Bool = controllableExternalDisplays.count > 2 ? true : false + if asSubmenu { + self.statusMenu.insertItem(NSMenuItem.separator(), at: 0) + } + self.addDisplayToMenu(display: display, asSubMenu: asSubmenu) + } + } + } + + func updateDisplays(dispatchedReconfigureID: Int = 0, firstrun: Bool = false) { + guard self.sleepID == 0, dispatchedReconfigureID == self.reconfigureID else { + return + } + os_log("Request for updateDisplay with reconfigreID %{public}@", type: .info, String(dispatchedReconfigureID)) + self.reconfigureID = 0 + DisplayManager.shared.clearDisplays() + var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 16) + var displayCount: UInt32 = 0 + guard CGGetOnlineDisplayList(10, &onlineDisplayIDs, &displayCount) == .success else { + os_log("Unable to get display list.", type: .info) + return + } + for onlineDisplayID in onlineDisplayIDs where onlineDisplayID != 0 { + let name = DisplayManager.shared.getDisplayNameByID(displayID: onlineDisplayID) + let id = onlineDisplayID + let vendorNumber = CGDisplayVendorNumber(onlineDisplayID) + let modelNumber = CGDisplayVendorNumber(onlineDisplayID) + let display: Display + var isVirtual: Bool = false + if #available(macOS 11.0, *) { + if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(onlineDisplayID))?.takeRetainedValue() as NSDictionary?) { + let isVirtualDevice = dictionary["kCGDisplayIsVirtualDevice"] as? Bool + let displayIsAirplay = dictionary["kCGDisplayIsAirPlay"] as? Bool + if isVirtualDevice ?? displayIsAirplay ?? false { + isVirtual = true + } + } } + if !debugSw, CGDisplayIsBuiltin(onlineDisplayID) != 0 { // MARK: (point of interest for testing) + display = InternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual) + } else { + display = ExternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual) + } + DisplayManager.shared.addDisplay(display: display) } + self.updateArm64AVServices() + if firstrun { + DisplayManager.shared.resetSwBrightnessForAllDisplays(settingsOnly: true) + } + NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil) + self.updateMenus() + if !firstrun { + if prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) || prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + DisplayManager.shared.restoreSwBrightnessForAllDisplays(async: true) + } + } + updateMediaKeyTap() } private func addDisplayToMenu(display: ExternalDisplay, asSubMenu: Bool) { + if !asSubMenu { + self.statusMenu.insertItem(NSMenuItem.separator(), at: 0) + } let monitorSubMenu: NSMenu = asSubMenu ? NSMenu() : self.statusMenu - self.statusMenu.insertItem(NSMenuItem.separator(), at: 0) - - let volumeSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, - forDisplay: display, - command: .audioSpeakerVolume, - title: NSLocalizedString("Volume", comment: "Shown in menu")) - let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, - forDisplay: display, - command: .brightness, - title: NSLocalizedString("Brightness", comment: "Shown in menu")) - if prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) { - let contrastSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, - forDisplay: display, - command: .contrast, - title: NSLocalizedString("Contrast", comment: "Shown in menu")) - display.contrastSliderHandler = contrastSliderHandler - } - - display.volumeSliderHandler = volumeSliderHandler + if !display.isSw() { + if prefs.bool(forKey: Utils.PrefKeys.showVolume.rawValue) { + let volumeSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, forDisplay: display, command: .audioSpeakerVolume, title: NSLocalizedString("Volume", comment: "Shown in menu")) + display.volumeSliderHandler = volumeSliderHandler + } + if prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) { + let contrastSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, forDisplay: display, command: .contrast, title: NSLocalizedString("Contrast", comment: "Shown in menu")) + display.contrastSliderHandler = contrastSliderHandler + } + } + var numOfTickMarks = 0 + if !display.isSw(), prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + numOfTickMarks = 0 // 1 - I disabled this because tickmarks are buggy in dark mode on Monterey (probably Big Sur as well). + } + let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, forDisplay: display, command: .brightness, title: NSLocalizedString("Brightness", comment: "Shown in menu"), numOfTickMarks: numOfTickMarks) display.brightnessSliderHandler = brightnessSliderHandler let monitorMenuItem = NSMenuItem() - monitorMenuItem.title = "\(display.getFriendlyName())" if asSubMenu { + monitorMenuItem.title = "\(display.getFriendlyName())" monitorMenuItem.submenu = monitorSubMenu + } else { + let attrs: [NSAttributedString.Key: Any] = [.foregroundColor: NSColor.systemGray, .font: NSFont.boldSystemFont(ofSize: 12)] + monitorMenuItem.attributedTitle = NSAttributedString(string: "\(display.getFriendlyName())", attributes: attrs) } self.monitorItems.append(monitorMenuItem) @@ -167,19 +249,44 @@ class AppDelegate: NSObject, NSApplicationDelegate { } private func subscribeEventListeners() { - // subscribe KeyTap event listener - 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(handleListenForChanged), name: .listenFor, object: nil) // subscribe KeyTap event listeners NotificationCenter.default.addObserver(self, selector: #selector(handleFriendlyNameChanged), name: .friendlyName, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handlePreferenceReset), name: .preferenceReset, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil) // subscribe Audio output detector (SimplyCoreAudio) + DistributedNotificationCenter.default.addObserver(self, selector: #selector(colorSyncSettingsChanged), 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) + NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotofication), name: NSWorkspace.didWakeNotification, object: nil) + _ = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.updateMediaKeyTap() // listen for accessibility status changes + } + } + } - // subscribe Audio output detector (SimplyCoreAudio) - NotificationCenter.default.addObserver(self, selector: #selector(audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil) + @objc private func sleepNotification() { + self.sleepID += 1 + os_log("Sleeping with sleep %{public}@", type: .info, String(self.sleepID)) + } - // listen for accessibility status changes - _ = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - self.updateMediaKeyTap() + @objc private func wakeNotofication() { + if self.sleepID != 0 { + os_log("Waking up from sleep %{public}@", type: .info, String(self.sleepID)) + let dispatchedSleepID = self.sleepID + DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) { // Some displays take time to recover... + self.soberNow(dispatchedSleepID: dispatchedSleepID) + } + } + } + + private func soberNow(dispatchedSleepID: Int) { + if self.sleepID == dispatchedSleepID { + os_log("Sober from sleep %{public}@", type: .info, String(self.sleepID)) + 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)) + self.updateDisplays(dispatchedReconfigureID: dispatchedReconfigureID) } } } @@ -217,16 +324,21 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } -// MARK: - Media Key Tap delegate - extension AppDelegate: MediaKeyTapDelegate { func handle(mediaKey: MediaKey, event: KeyEvent?, modifiers: NSEvent.ModifierFlags?) { + guard self.sleepID == 0, self.reconfigureID == 0 else { + if [.brightnessUp, .brightnessDown].contains(mediaKey) { + OSDUtils.showOSDLockOnAllDisplays(osdImage: 1) + } + if [.volumeUp, .volumeDown, .mute].contains(mediaKey) { + OSDUtils.showOSDLockOnAllDisplays(osdImage: 3) + } + return + } if self.handleOpenPrefPane(mediaKey: mediaKey, event: event, modifiers: modifiers) { return } - let isSmallIncrement = modifiers?.isSuperset(of: NSEvent.ModifierFlags([.shift, .option])) ?? false - // control internal display when holding ctrl modifier let isControlModifier = modifiers?.isSuperset(of: NSEvent.ModifierFlags([.control])) ?? false if isControlModifier, mediaKey == .brightnessUp || mediaKey == .brightnessDown { @@ -235,10 +347,8 @@ extension AppDelegate: MediaKeyTapDelegate { return } } - let oppositeKey: MediaKey? = self.oppositeMediaKey(mediaKey: mediaKey) let isRepeat = event?.keyRepeat ?? false - // If the opposite key to the one being held has an active timer, cancel it - we'll be going in the opposite direction if let oppositeKey = oppositeKey, let oppositeKeyTimer = self.keyRepeatTimers[oppositeKey], oppositeKeyTimer.isValid { oppositeKeyTimer.invalidate() @@ -252,65 +362,90 @@ extension AppDelegate: MediaKeyTapDelegate { self.sendDisplayCommand(mediaKey: mediaKey, isRepeat: isRepeat, isSmallIncrement: isSmallIncrement) } - private func sendDisplayCommand(mediaKey: MediaKey, isRepeat: Bool, isSmallIncrement: Bool) { - let displays = DisplayManager.shared.getAllDisplays() - guard let currentDisplay = DisplayManager.shared.getCurrentDisplay() else { return } - - let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay] - - // Introduce a small delay to handle the media key being held down - let delay = isRepeat ? 0.05 : 0 + private func getAffectedDisplays() -> [Display]? { + var affectedDisplays: [Display] + let allDisplays = DisplayManager.shared.getAllNonVirtualDisplays() + guard let currentDisplay = DisplayManager.shared.getCurrentDisplay() else { + return nil + } + // let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay] + if prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) { + affectedDisplays = allDisplays + } else { + affectedDisplays = [currentDisplay] + if CGDisplayIsInHWMirrorSet(currentDisplay.identifier) != 0 || CGDisplayIsInMirrorSet(currentDisplay.identifier) != 0, CGDisplayMirrorsDisplay(currentDisplay.identifier) == 0 { + for display in allDisplays where CGDisplayMirrorsDisplay(display.identifier) == currentDisplay.identifier { + affectedDisplays.append(display) + } + } + } + return affectedDisplays + } - self.keyRepeatTimers[mediaKey] = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { _ in - for display in allDisplays where display.isEnabled { - switch mediaKey { - case .brightnessUp, .brightnessDown: + private func sendDisplayCommand(mediaKey: MediaKey, isRepeat: Bool, isSmallIncrement: Bool) { + guard self.sleepID == 0, self.reconfigureID == 0, let affectedDisplays = self.getAffectedDisplays() else { + return + } + var isAnyDisplayInSwAfterBrightnessMode: Bool = false + for display in affectedDisplays where ((display as? ExternalDisplay)?.isSwBrightnessNotDefault() ?? false) && !((display as? ExternalDisplay)?.isSw() ?? false) { + isAnyDisplayInSwAfterBrightnessMode = true + } + // let delay = isRepeat ? 0.05 : 0 // Introduce a small delay to handle the media key being held down - Update: it is not clear why this is needed but it blocks the media keys working when the menu is open and also it doesn't seem to affect external bluetooth keyboards but slows down internal keyboards for some reason. Things seem to work better this being disabled. + // self.keyRepeatTimers[mediaKey] = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { _ in + for display in affectedDisplays where display.isEnabled && !display.isVirtual { + switch mediaKey { + case .brightnessUp: + if !(isAnyDisplayInSwAfterBrightnessMode && !(((display as? ExternalDisplay)?.isSwBrightnessNotDefault() ?? false) && !((display as? ExternalDisplay)?.isSw() ?? false))) { display.stepBrightness(isUp: mediaKey == .brightnessUp, isSmallIncrement: isSmallIncrement) - case .mute: - // The mute key should not respond to press + hold - if !isRepeat { - // mute only matters for external displays - if let display = display as? ExternalDisplay { - display.toggleMute() - } - } - case .volumeUp, .volumeDown: - // volume only matters for external displays + } + case .brightnessDown: + display.stepBrightness(isUp: mediaKey == .brightnessUp, isSmallIncrement: isSmallIncrement) + case .mute: + // The mute key should not respond to press + hold + if !isRepeat { + // mute only matters for external displays if let display = display as? ExternalDisplay { - display.stepVolume(isUp: mediaKey == .volumeUp, isSmallIncrement: isSmallIncrement) + display.toggleMute() } - default: - return } + case .volumeUp, .volumeDown: + // volume only matters for external displays + if let display = display as? ExternalDisplay { + display.stepVolume(isUp: mediaKey == .volumeUp, isSmallIncrement: isSmallIncrement) + } + default: + return } - }) + } + // }) } - // MARK: - Prefs notification - @objc func handleListenForChanged() { self.checkPermissions() self.updateMediaKeyTap() } - @objc func handleShowContrastChanged() { - self.updateDisplays() - } - @objc func handleFriendlyNameChanged() { - self.updateDisplays() + self.updateMenus() } @objc func handlePreferenceReset() { + os_log("Resetting all preferences.") + if prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) || prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + DisplayManager.shared.resetSwBrightnessForAllDisplays() + } + if let bundleID = Bundle.main.bundleIdentifier { + UserDefaults.standard.removePersistentDomain(forName: bundleID) + } + app.statusItem.isVisible = true self.setDefaultPrefs() - self.updateDisplays() self.checkPermissions() self.updateMediaKeyTap() + self.updateDisplays(firstrun: true) } private func updateMediaKeyTap() { var keys: [MediaKey] - switch prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue) { case Utils.ListenForKeys.brightnessOnlyKeys.rawValue: keys = [.brightnessUp, .brightnessDown] @@ -321,13 +456,20 @@ extension AppDelegate: MediaKeyTapDelegate { default: keys = [.brightnessUp, .brightnessDown, .mute, .volumeUp, .volumeDown] } - + // Remove keys if no external displays are connected + var isInternalDisplayOnly = true + for display in DisplayManager.shared.getAllDisplays() where display is ExternalDisplay { + isInternalDisplayOnly = false + } + if isInternalDisplayOnly { + let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute, .brightnessUp, .brightnessDown] + keys.removeAll { keysToDelete.contains($0) } + } + // Remove volume related keys if audio device is controllable if self.coreAudio.defaultOutputDevice?.canSetVirtualMasterVolume(scope: .output) == true { - // Remove volume related keys. let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute] keys.removeAll { keysToDelete.contains($0) } } - self.mediaKeyTap?.stop() // returning an empty array listens for all mediakeys in MediaKeyTap if keys.count > 0 { @@ -345,4 +487,9 @@ extension AppDelegate: MediaKeyTapDelegate { #endif self.updateMediaKeyTap() } + + @objc private func colorSyncSettingsChanged() { + CGDisplayRestoreColorSyncSettings() + self.displayReconfigured() + } } diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Contents.json b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Contents.json index d296f15f..959fa98b 100644 --- a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,68 +1,68 @@ { "images" : [ { - "size" : "16x16", - "idiom" : "mac", "filename" : "Icon-16.png", - "scale" : "1x" + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" }, { - "size" : "16x16", - "idiom" : "mac", "filename" : "Icon-33.png", - "scale" : "2x" + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" }, { - "size" : "32x32", - "idiom" : "mac", "filename" : "Icon-32.png", - "scale" : "1x" + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" }, { - "size" : "32x32", - "idiom" : "mac", "filename" : "Icon-64.png", - "scale" : "2x" + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" }, { - "size" : "128x128", - "idiom" : "mac", "filename" : "Icon-128.png", - "scale" : "1x" + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" }, { - "size" : "128x128", - "idiom" : "mac", "filename" : "Icon-257.png", - "scale" : "2x" + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" }, { - "size" : "256x256", - "idiom" : "mac", "filename" : "Icon-256.png", - "scale" : "1x" + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" }, { - "size" : "256x256", - "idiom" : "mac", "filename" : "Icon-513.png", - "scale" : "2x" + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" }, { - "size" : "512x512", - "idiom" : "mac", "filename" : "Icon-512.png", - "scale" : "1x" + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" }, { - "size" : "512x512", - "idiom" : "mac", "filename" : "Icon-1024.png", - "scale" : "2x" + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-1024.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-1024.png index 9bb9765b..f8dcd074 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-1024.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-1024.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-128.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-128.png index 7dffaf77..a62a61fa 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-128.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-128.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-16.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-16.png index 038f8483..42b9fa83 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-16.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-16.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-256.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-256.png index f517ca43..cfa72741 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-256.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-256.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-257.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-257.png index f517ca43..cfa72741 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-257.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-257.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-32.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-32.png index ff6ce192..309c15f7 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-32.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-32.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-33.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-33.png index ff6ce192..309c15f7 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-33.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-33.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-512.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-512.png index 5b658f63..c2e466a7 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-512.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-512.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-513.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-513.png index 5b658f63..c2e466a7 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-513.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-513.png differ diff --git a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-64.png b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-64.png index 81f7ffa8..72cd79b0 100644 Binary files a/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-64.png and b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Icon-64.png differ diff --git a/MonitorControl/Assets.xcassets/Contents.json b/MonitorControl/Assets.xcassets/Contents.json index da4a164c..73c00596 100644 --- a/MonitorControl/Assets.xcassets/Contents.json +++ b/MonitorControl/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Contents.json b/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Contents.json deleted file mode 100644 index 5c0a83df..00000000 --- a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "Keyboard-32.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "Keyboard-64.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "Keyboard-96.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-32.png b/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-32.png deleted file mode 100644 index f1ce9708..00000000 Binary files a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-32.png and /dev/null differ diff --git a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-64.png b/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-64.png deleted file mode 100644 index 7133271e..00000000 Binary files a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-64.png and /dev/null differ diff --git a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-96.png b/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-96.png deleted file mode 100644 index 139ab274..00000000 Binary files a/MonitorControl/Assets.xcassets/KeyboardPref.imageset/Keyboard-96.png and /dev/null differ diff --git a/MonitorControl/Extensions/NSNotification+Extension.swift b/MonitorControl/Extensions/NSNotification+Extension.swift index 19c65799..94353efa 100644 --- a/MonitorControl/Extensions/NSNotification+Extension.swift +++ b/MonitorControl/Extensions/NSNotification+Extension.swift @@ -3,7 +3,6 @@ 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) diff --git a/MonitorControl/Extensions/NSScreen+Extension.swift b/MonitorControl/Extensions/NSScreen+Extension.swift index 9f478a58..d744db1d 100644 --- a/MonitorControl/Extensions/NSScreen+Extension.swift +++ b/MonitorControl/Extensions/NSScreen+Extension.swift @@ -47,13 +47,8 @@ public extension NSScreen { while case let object = IOIteratorNext(servicePortIterator), object != 0 { let dict = (IODisplayCreateInfoDictionary(object, UInt32(kIODisplayOnlyPreferredName)).takeRetainedValue() as NSDictionary as? [String: AnyObject])! - if dict[kDisplayVendorID] as? UInt32 == self.vendorNumber, - dict[kDisplayProductID] as? UInt32 == self.modelNumber, - dict[kDisplaySerialNumber] as? UInt32 == self.serialNumber - { - if let productName = dict["DisplayProductName"] as? [String: String], - let firstKey = Array(productName.keys).first - { + if dict[kDisplayVendorID] as? UInt32 == self.vendorNumber, dict[kDisplayProductID] as? UInt32 == self.modelNumber, dict[kDisplaySerialNumber] as? UInt32 == self.serialNumber { + if let productName = dict["DisplayProductName"] as? [String: String], let firstKey = Array(productName.keys).first { return productName[firstKey]! } } diff --git a/MonitorControl/Extensions/Preferences+Extension.swift b/MonitorControl/Extensions/Preferences+Extension.swift index bf3f4a61..541409b3 100644 --- a/MonitorControl/Extensions/Preferences+Extension.swift +++ b/MonitorControl/Extensions/Preferences+Extension.swift @@ -10,7 +10,6 @@ import Preferences extension Preferences.PaneIdentifier { static let main = Self("Main") - static let keys = Self("Keys") - static let advanced = Self("Advanced") - static let display = Self("Display") + static let displays = Self("Displays") + static let about = Self("About") } diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 5ce5b448..b72c6dbc 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 947 + 2866 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Manager/DisplayManager.swift b/MonitorControl/Manager/DisplayManager.swift index c6fc41f9..0eccce11 100644 --- a/MonitorControl/Manager/DisplayManager.swift +++ b/MonitorControl/Manager/DisplayManager.swift @@ -1,13 +1,10 @@ import Cocoa +import DDC class DisplayManager { public static let shared = DisplayManager() - private var displays: [Display] { - didSet { - NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil) - } - } + private var displays: [Display] init() { self.displays = [] @@ -17,13 +14,33 @@ class DisplayManager { self.displays = displays } + func getExternalDisplays() -> [ExternalDisplay] { + return self.displays.compactMap { $0 as? ExternalDisplay } + } + func getAllDisplays() -> [Display] { return self.displays } + func getAllNonVirtualDisplays() -> [Display] { + return self.displays.compactMap { display -> Display? in + if !display.isVirtual { + return display + } else { return nil } + } + } + func getDdcCapableDisplays() -> [ExternalDisplay] { return self.displays.compactMap { display -> ExternalDisplay? in - if let externalDisplay = display as? ExternalDisplay, externalDisplay.ddc != nil { + if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isSw(), !externalDisplay.isVirtual { + return externalDisplay + } else { return nil } + } + } + + func getNonVirtualExternalDisplays() -> [ExternalDisplay] { + return self.displays.compactMap { display -> ExternalDisplay? in + if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isVirtual { return externalDisplay } else { return nil } } @@ -34,10 +51,12 @@ class DisplayManager { } func getCurrentDisplay() -> Display? { - guard let mainDisplayID = NSScreen.main?.displayID else { - return nil + let mouseLocation = NSEvent.mouseLocation + let screens = NSScreen.screens + if let screenWithMouse = (screens.first { NSMouseInRect(mouseLocation, $0.frame, false) }) { + return self.displays.first { $0.identifier == screenWithMouse.displayID } } - return self.displays.first { $0.identifier == mainDisplayID } + return nil } func addDisplay(display: Display) { @@ -53,4 +72,83 @@ class DisplayManager { func clearDisplays() { self.displays = [] } + + func resetSwBrightnessForAllDisplays(settingsOnly: Bool = false, async: Bool = false) { + for externalDisplay in self.getNonVirtualExternalDisplays() { + if !settingsOnly { + _ = externalDisplay.setSwBrightness(value: externalDisplay.getSwMaxBrightness(), smooth: async) + } else { + externalDisplay.saveSwBirghtnessPrefValue(Int(externalDisplay.getSwMaxBrightness())) + } + if externalDisplay.isSw() { + externalDisplay.saveValue(Int(externalDisplay.getSwMaxBrightness()), for: .brightness) + } + } + } + + func setBrightnessSliderValue(externalDisplay: ExternalDisplay, value: Int32) { + if let slider = externalDisplay.brightnessSliderHandler?.slider { + slider.intValue = value + } + } + + func getBrightnessSliderMaxValue(externalDisplay: ExternalDisplay) -> Double { + if let slider = externalDisplay.brightnessSliderHandler?.slider { + return slider.maxValue + } + return 0 + } + + func restoreSwBrightnessForAllDisplays(async: Bool = false) { + for externalDisplay in self.getExternalDisplays() { + let sliderMax = self.getBrightnessSliderMaxValue(externalDisplay: externalDisplay) + if externalDisplay.getValue(for: .brightness) == 0 || externalDisplay.isSw() { + let savedPrefValue = externalDisplay.getSwBrightnessPrefValue() + if externalDisplay.getSwBrightness() != savedPrefValue { + if let manager = OSDManager.sharedManager() as? OSDManager { // 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 + manager.showImage(OSDImage.brightness.rawValue, onDisplayID: externalDisplay.identifier, priority: 0x1F4, msecUntilFade: 0) + } + } + externalDisplay.saveSwBirghtnessPrefValue(Int(externalDisplay.getSwBrightness())) + _ = externalDisplay.setSwBrightness(value: UInt8(savedPrefValue), smooth: async) + if !externalDisplay.isSw(), prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + if savedPrefValue < externalDisplay.getSwMaxBrightness() { + self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(Float(sliderMax / 2) * (Float(savedPrefValue) / Float(externalDisplay.getSwMaxBrightness())))) + } else { + self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(sliderMax / 2) + Int32(externalDisplay.getValue(for: DDC.Command.brightness))) + } + } else if externalDisplay.isSw() { + self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(Float(sliderMax) * (Float(savedPrefValue) / Float(externalDisplay.getSwMaxBrightness())))) + } + } else { + _ = externalDisplay.setSwBrightness(value: externalDisplay.getSwMaxBrightness()) + if externalDisplay.isSw() { + self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(sliderMax)) + } + } + } + } + + func getDisplayNameByID(displayID: CGDirectDisplayID) -> String { + let defaultName: String = NSLocalizedString("Unknown", comment: "Unknown display name") + if #available(macOS 11.0, *) { + if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], var name = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value { + if CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0 { + let mirroredDisplayID = CGDisplayMirrorsDisplay(displayID) + if mirroredDisplayID != 0, let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(mirroredDisplayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], let mirroredName = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value { + name.append("~" + mirroredName) + } + } + return name + } + } + if let screen = NSScreen.getByDisplayID(displayID: displayID) { + if #available(OSX 10.15, *) { + return screen.localizedName + } else { + return screen.displayName ?? defaultName + } + } + return defaultName + } } diff --git a/MonitorControl/Model/Display.swift b/MonitorControl/Model/Display.swift index 10da136a..c1939800 100644 --- a/MonitorControl/Model/Display.swift +++ b/MonitorControl/Model/Display.swift @@ -10,7 +10,7 @@ import DDC import Foundation import os.log -private enum OSDImage: Int64 { +enum OSDImage: Int64 { case brightness = 1 case audioSpeaker = 3 case audioSpeakerMuted = 4 @@ -23,20 +23,40 @@ class Display { internal var modelNumber: UInt32? internal var isEnabled: Bool { get { - return self.prefs.object(forKey: "\(self.identifier)-state") as? Bool ?? true + self.prefs.object(forKey: "\(self.identifier)-state") as? Bool ?? true } set { self.prefs.set(newValue, forKey: "\(self.identifier)-state") } } + var forceSw: Bool { + get { + return self.prefs.bool(forKey: "forceSw-\(self.identifier)") + } + set { + self.prefs.set(newValue, forKey: "forceSw-\(self.identifier)") + os_log("Set `forceSw` to: %{public}@", type: .info, String(newValue)) + } + } + + var isVirtual: Bool = false + + var defaultGammaTableRed = [CGGammaValue](repeating: 0, count: 256) + var defaultGammaTableGreen = [CGGammaValue](repeating: 0, count: 256) + var defaultGammaTableBlue = [CGGammaValue](repeating: 0, count: 256) + var defaultGammaTableSampleCount: UInt32 = 0 + var defaultGammaTablePeak: Float = 1 + private let prefs = UserDefaults.standard - internal init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) { + internal init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) { self.identifier = identifier self.name = name self.vendorNumber = vendorNumber self.modelNumber = modelNumber + self.isVirtual = isVirtual + self.swUpdateDefaultGammaTable() } func stepBrightness(isUp _: Bool, isSmallIncrement _: Bool) {} @@ -49,7 +69,118 @@ class Display { return self.prefs.string(forKey: "friendlyName-\(self.identifier)") ?? self.name } - func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100, roundChiclet: Bool = false) { + func getShowOsdDisplayId() -> CGDirectDisplayID { + if CGDisplayIsInHWMirrorSet(self.identifier) != 0 || CGDisplayIsInMirrorSet(self.identifier) != 0, CGDisplayMirrorsDisplay(self.identifier) != 0 { + for mirrorMaestro in DisplayManager.shared.getAllNonVirtualDisplays() where CGDisplayMirrorsDisplay(self.identifier) == mirrorMaestro.identifier { + if let externalMirrorMaestro = mirrorMaestro as? ExternalDisplay, externalMirrorMaestro.isSw() { + var thereAreOthers = false + for mirrorMember in DisplayManager.shared.getAllNonVirtualDisplays() where CGDisplayMirrorsDisplay(mirrorMember.identifier) == CGDisplayMirrorsDisplay(self.identifier) && mirrorMember.identifier != self.identifier { + thereAreOthers = true + } + if !thereAreOthers { + return externalMirrorMaestro.identifier + } + } + } + } + return self.identifier + } + + func swUpdateDefaultGammaTable() { + CGGetDisplayTransferByTable(self.identifier, 256, &self.defaultGammaTableRed, &self.defaultGammaTableGreen, &self.defaultGammaTableBlue, &self.defaultGammaTableSampleCount) + let redPeak = self.defaultGammaTableRed.max() ?? 0 + let greenPeak = self.defaultGammaTableGreen.max() ?? 0 + let bluePeak = self.defaultGammaTableBlue.max() ?? 0 + self.defaultGammaTablePeak = max(redPeak, greenPeak, bluePeak) + } + + func swBrightnessTransform(value: Float, reverse: Bool = false) -> Float { + let lowTreshold: Float = 0.1 // We don't allow decrease lower than 5% for safety reasons and because some displays blank off after a while on full black screen due to energy saving settings + if !reverse { + return value * (1 - lowTreshold) + lowTreshold + } else { + return (value - lowTreshold) / (1 - lowTreshold) + } + } + + let swBrightnessSemaphore = DispatchSemaphore(value: 1) + func setSwBrightness(value: UInt8, smooth: Bool = false) -> Bool { + let brightnessValue: UInt8 = min(getSwMaxBrightness(), value) + var currentValue = Float(self.getSwBrightnessPrefValue()) / Float(self.getSwMaxBrightness()) + self.saveSwBirghtnessPrefValue(Int(brightnessValue)) + var newValue = Float(Float(brightnessValue)) / Float(self.getSwMaxBrightness()) + currentValue = self.swBrightnessTransform(value: currentValue) + newValue = self.swBrightnessTransform(value: newValue) + os_log("setting software brightness to: %{public}@", type: .debug, String(newValue)) + if smooth { + DispatchQueue.global(qos: .userInteractive).async { + self.swBrightnessSemaphore.wait() + for transientValue in stride(from: currentValue, to: newValue, by: 0.005 * (currentValue > newValue ? -1 : 1)) { + let gammaTableRed = self.defaultGammaTableRed.map { $0 * transientValue } + let gammaTableGreen = self.defaultGammaTableGreen.map { $0 * transientValue } + let gammaTableBlue = self.defaultGammaTableBlue.map { $0 * transientValue } + guard app.reconfigureID == 0 else { + return + } + CGSetDisplayTransferByTable(self.identifier, self.defaultGammaTableSampleCount, gammaTableRed, gammaTableGreen, gammaTableBlue) + Thread.sleep(forTimeInterval: 0.001) // Let's make things quick if not performed in the background + } + self.swBrightnessSemaphore.signal() + } + } else { + let gammaTableRed = self.defaultGammaTableRed.map { $0 * /* transientValue */ newValue } + let gammaTableGreen = self.defaultGammaTableGreen.map { $0 * /* transientValue */ newValue } + let gammaTableBlue = self.defaultGammaTableBlue.map { $0 * /* transientValue */ newValue } + CGSetDisplayTransferByTable(self.identifier, self.defaultGammaTableSampleCount, gammaTableRed, gammaTableGreen, gammaTableBlue) + } + return true + } + + func getSwBrightness() -> UInt8 { + var gammaTableRed = [CGGammaValue](repeating: 0, count: 256) + var gammaTableGreen = [CGGammaValue](repeating: 0, count: 256) + var gammaTableBlue = [CGGammaValue](repeating: 0, count: 256) + var gammaTableSampleCount: UInt32 = 0 + if CGGetDisplayTransferByTable(self.identifier, 256, &gammaTableRed, &gammaTableGreen, &gammaTableBlue, &gammaTableSampleCount) == CGError.success { + let redPeak = gammaTableRed.max() ?? 0 + let greenPeak = gammaTableGreen.max() ?? 0 + let bluePeak = gammaTableBlue.max() ?? 0 + let gammaTablePeak = max(redPeak, greenPeak, bluePeak) + let peakRatio = gammaTablePeak / self.defaultGammaTablePeak + let brightnessValue = UInt8(round(self.swBrightnessTransform(value: peakRatio, reverse: true) * Float(self.getSwMaxBrightness()))) + os_log("Current software gammatable brightness is: %{public}@", type: .debug, String(brightnessValue)) + return brightnessValue + } + return self.getSwMaxBrightness() + } + + func resetSwBrightness() -> Bool { + return self.setSwBrightness(value: self.getSwMaxBrightness()) + } + + func saveSwBirghtnessPrefValue(_ value: Int) { + self.prefs.set(value, forKey: "SwBrightness-\(self.identifier)") + } + + func getSwBrightnessPrefValue() -> Int { + return self.prefs.integer(forKey: "SwBrightness-\(self.identifier)") + } + + func getSwMaxBrightness() -> UInt8 { + return 100 + } + + func isSwBrightnessNotDefault() -> Bool { + guard !self.isVirtual else { + return false + } + if self.getSwBrightness() < self.getSwMaxBrightness() { + return true + } + return false + } + + func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100, roundChiclet: Bool = false, lock: Bool = false) { guard let manager = OSDManager.sharedManager() as? OSDManager else { return } @@ -78,11 +209,11 @@ class Display { } manager.showImage(osdImage.rawValue, - onDisplayID: self.identifier, + onDisplayID: self.getShowOsdDisplayId(), priority: 0x1F4, msecUntilFade: 1000, filledChiclets: UInt32(filledChiclets), totalChiclets: UInt32(totalChiclets), - locked: false) + locked: lock) } } diff --git a/MonitorControl/Model/ExternalDisplay.swift b/MonitorControl/Model/ExternalDisplay.swift index d9f6c9b2..78e24c85 100644 --- a/MonitorControl/Model/ExternalDisplay.swift +++ b/MonitorControl/Model/ExternalDisplay.swift @@ -1,6 +1,7 @@ import AVFoundation import Cocoa import DDC +import IOKit import os.log class ExternalDisplay: Display { @@ -8,9 +9,23 @@ class ExternalDisplay: Display { var volumeSliderHandler: SliderHandler? var contrastSliderHandler: SliderHandler? var ddc: DDC? + var arm64ddc: Bool = false + var arm64avService: IOAVService? + + let DDC_HARD_MAX_LIMIT: Int = 100 private let prefs = UserDefaults.standard + var enableMuteUnmute: Bool { + get { + return self.prefs.bool(forKey: "enableMuteUnmute-\(self.identifier)") + } + set { + self.prefs.set(newValue, forKey: "enableMuteUnmute-\(self.identifier)") + os_log("Set `enableMuteUnmute` for %{private}@ to: %{public}@", type: .info, String(self.identifier), String(newValue)) + } + } + var hideOsd: Bool { get { return self.prefs.bool(forKey: "hideOsd-\(self.identifier)") @@ -33,20 +48,11 @@ class ExternalDisplay: Display { private var audioPlayer: AVAudioPlayer? - override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) { - super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber) - self.ddc = DDC(for: identifier) - } - - // On some displays, the display's OSD overlaps the macOS OSD, - // calling the OSD command with 1 seems to hide it. - func hideDisplayOsd() { - guard self.hideOsd else { - return - } + override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) { + super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual) - for _ in 0 ..< 20 { - _ = self.ddc?.write(command: .osd, value: UInt16(1), errorRecoveryWaitTime: 2000) + if !isVirtual, !Arm64DDCUtils.isArm64 { + self.ddc = DDC(for: identifier) } } @@ -75,12 +81,12 @@ class ExternalDisplay: Display { let volumeDDCValue = UInt16(volumeOSDValue) - guard self.ddc?.write(command: .audioSpeakerVolume, value: volumeDDCValue) == true else { + guard self.writeDDCValues(command: .audioSpeakerVolume, value: volumeDDCValue) == true else { return } - if self.supportsMuteCommand() { - guard self.ddc?.write(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else { + if self.enableMuteUnmute { + guard self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else { return } } @@ -88,8 +94,9 @@ class ExternalDisplay: Display { self.saveValue(muteValue, for: .audioMuteScreenBlank) if !fromVolumeSlider { - self.hideDisplayOsd() - self.showOsd(command: volumeOSDValue > 0 ? .audioSpeakerVolume : .audioMuteScreenBlank, value: volumeOSDValue, roundChiclet: true) + if !self.hideOsd { + self.showOsd(command: volumeOSDValue > 0 ? .audioSpeakerVolume : .audioMuteScreenBlank, value: volumeOSDValue, roundChiclet: true) + } if volumeOSDValue > 0 { self.playVolumeChangedSound() @@ -103,7 +110,9 @@ class ExternalDisplay: Display { func stepVolume(isUp: Bool, isSmallIncrement: Bool) { var muteValue: Int? - let volumeOSDValue = self.calcNewValue(for: .audioSpeakerVolume, isUp: isUp, isSmallIncrement: isSmallIncrement) + let currentValue = self.getValue(for: .audioSpeakerVolume) + let maxValue = self.getMaxValue(for: .audioSpeakerVolume) + let volumeOSDValue = self.calcNewValue(currentValue: currentValue, maxValue: maxValue, isUp: isUp, isSmallIncrement: isSmallIncrement) let volumeDDCValue = UInt16(volumeOSDValue) if self.isMuted(), volumeOSDValue > 0 { muteValue = 2 @@ -113,24 +122,22 @@ class ExternalDisplay: Display { let isAlreadySet = volumeOSDValue == self.getValue(for: .audioSpeakerVolume) - if !isAlreadySet { - guard self.ddc?.write(command: .audioSpeakerVolume, value: volumeDDCValue) == true else { - return - } + guard self.writeDDCValues(command: .audioSpeakerVolume, value: volumeDDCValue) == true else { + return } if let muteValue = muteValue { - // If the mute command is supported, set its value accordingly - if self.supportsMuteCommand() { - guard self.ddc?.write(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else { + if self.enableMuteUnmute { + guard self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else { return } } self.saveValue(muteValue, for: .audioMuteScreenBlank) } - self.hideDisplayOsd() - self.showOsd(command: .audioSpeakerVolume, value: volumeOSDValue, roundChiclet: !isSmallIncrement) + if !self.hideOsd { + self.showOsd(command: .audioSpeakerVolume, value: volumeOSDValue, roundChiclet: !isSmallIncrement) + } if !isAlreadySet { self.saveValue(volumeOSDValue, for: .audioSpeakerVolume) @@ -145,86 +152,168 @@ class ExternalDisplay: Display { } } - override func stepBrightness(isUp: Bool, isSmallIncrement: Bool) { - let osdValue = Int(self.calcNewValue(for: .brightness, isUp: isUp, isSmallIncrement: isSmallIncrement)) - let isAlreadySet = osdValue == self.getValue(for: .brightness) - let ddcValue = UInt16(osdValue) + func isSwOnly() -> Bool { + return (!self.arm64ddc && self.ddc == nil && !self.isVirtual) + } - // Set the contrast value according to the brightness, if necessary - if !isAlreadySet { - self.setContrastValueForBrightness(osdValue) + func isSw() -> Bool { + if self.prefs.bool(forKey: "forceSw-\(self.identifier)") || self.isSwOnly() { + return true + } else { + return false } + } - if !isAlreadySet { - guard self.ddc?.write(command: .brightness, value: ddcValue) == true else { + let swAfterOsdAnimationSemaphore = DispatchSemaphore(value: 1) + var lastAnimationStartedTime: CFTimeInterval = CACurrentMediaTime() + func doSwAfterOsdAnimation() { + self.lastAnimationStartedTime = CACurrentMediaTime() + DispatchQueue.global(qos: .userInteractive).async { + self.swAfterOsdAnimationSemaphore.wait() + guard CACurrentMediaTime() < self.lastAnimationStartedTime + 0.05 else { + self.swAfterOsdAnimationSemaphore.signal() return } + for value: Int in stride(from: 1, to: 6, by: 1) { + guard self.getValue(for: .brightness) == 0 else { + self.swAfterOsdAnimationSemaphore.signal() + return + } + self.showOsd(command: .brightness, value: value, roundChiclet: false) + Thread.sleep(forTimeInterval: Double(value * 2) / 300) + } + for value: Int in stride(from: 5, to: 0, by: -1) { + guard self.getValue(for: .brightness) == 0 else { + self.swAfterOsdAnimationSemaphore.signal() + return + } + self.showOsd(command: .brightness, value: value, roundChiclet: false) + Thread.sleep(forTimeInterval: Double(value * 2) / 300) + } + self.showOsd(command: .brightness, value: 0, roundChiclet: true) + self.swAfterOsdAnimationSemaphore.signal() } + } - self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement) - - if !isAlreadySet { - if let slider = self.brightnessSliderHandler?.slider { - slider.intValue = Int32(ddcValue) + func stepBrightnessPart(osdValue: Int, isSmallIncrement: Bool) -> Bool { + if self.isSw(), self.prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) { + if self.setSwBrightness(value: UInt8(osdValue), smooth: true) { + self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement) + self.saveValue(osdValue, for: .brightness) + if let slider = brightnessSliderHandler?.slider { + slider.intValue = Int32(osdValue) + } } + return true + } + return false + } - self.saveValue(osdValue, for: .brightness) + func stepBrightnessswAfterBirghtnessMode(osdValue: Int, isUp: Bool, isSmallIncrement: Bool) -> Bool { + let isAlreadySet = osdValue == self.getValue(for: .brightness) + var swAfterBirghtnessMode: Bool = isSwBrightnessNotDefault() + if isAlreadySet, !isUp, !swAfterBirghtnessMode, self.prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + swAfterBirghtnessMode = true + } + + if swAfterBirghtnessMode { + let currentSwBrightness = UInt8(self.getSwBrightnessPrefValue()) + var swBirghtnessValue = self.calcNewValue(currentValue: Int(currentSwBrightness), maxValue: Int(getSwMaxBrightness()), isUp: isUp, isSmallIncrement: isSmallIncrement) + if swBirghtnessValue >= Int(getSwMaxBrightness()) { + swBirghtnessValue = Int(getSwMaxBrightness()) + swAfterBirghtnessMode = false + } + if self.setSwBrightness(value: UInt8(swBirghtnessValue)) { + if let slider = brightnessSliderHandler?.slider { + slider.intValue = Int32(Float(slider.maxValue / 2) * (Float(swBirghtnessValue) / Float(getSwMaxBrightness()))) + } + self.doSwAfterOsdAnimation() + } } + return swAfterBirghtnessMode } - func setContrastValueForBrightness(_ brightness: Int) { - var contrastValue: Int? + override func stepBrightness(isUp: Bool, isSmallIncrement: Bool) { + let currentValue = self.getValue(for: .brightness) + let maxValue = self.isSw() ? Int(self.getSwMaxBrightness()) : self.getMaxValue(for: .brightness) + let osdValue = self.calcNewValue(currentValue: currentValue, maxValue: maxValue, isUp: isUp, isSmallIncrement: isSmallIncrement) - if brightness == 0 { - contrastValue = 0 + if self.stepBrightnessPart(osdValue: osdValue, isSmallIncrement: isSmallIncrement) { + return + } - // Save the current DDC value for contrast so it can be restored, even across app restarts - if self.getRestoreValue(for: .contrast) == 0 { - self.setRestoreValue(self.getValue(for: .contrast), for: .contrast) - } - } else if self.getValue(for: .brightness) == 0, brightness > 0 { - contrastValue = self.getRestoreValue(for: .contrast) + if self.stepBrightnessswAfterBirghtnessMode(osdValue: osdValue, isUp: isUp, isSmallIncrement: isSmallIncrement) { + return } - // Only write the new contrast value if lowering contrast after brightness is enabled - if let contrastValue = contrastValue, self.prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) { - _ = self.ddc?.write(command: .contrast, value: UInt16(contrastValue)) - self.saveValue(contrastValue, for: .contrast) + let ddcValue = UInt16(osdValue) + guard self.writeDDCValues(command: .brightness, value: ddcValue) == true else { + return + } + if let slider = brightnessSliderHandler?.slider { + if !self.isSw(), self.prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + slider.intValue = Int32(slider.maxValue / 2) + Int32(ddcValue) + } else { + slider.intValue = Int32(ddcValue) + } + } + self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement) + self.saveValue(osdValue, for: .brightness) + } - if let slider = contrastSliderHandler?.slider { - slider.intValue = Int32(contrastValue) + public func writeDDCValues(command: DDC.Command, value: UInt16, errorRecoveryWaitTime _: UInt32? = nil) -> Bool? { + guard app.sleepID == 0, app.reconfigureID == 0, !self.forceSw else { + return false + } + if Arm64DDCUtils.isArm64 { + guard self.arm64ddc else { + return false } + return Arm64DDCUtils.write(service: self.arm64avService, command: command.rawValue, value: value) + } else { + return self.ddc?.write(command: command, value: value, errorRecoveryWaitTime: 2000) ?? false } } func readDDCValues(for command: DDC.Command, tries: UInt, minReplyDelay delay: UInt64?) -> (current: UInt16, max: UInt16)? { var values: (UInt16, UInt16)? - - if self.ddc?.supported(minReplyDelay: delay) == true { - os_log("Display supports DDC.", type: .debug) - } else { - os_log("Display does not support DDC.", type: .debug) + guard app.sleepID == 0, app.reconfigureID == 0, !self.forceSw else { + return values } - - if self.ddc?.enableAppReport() == true { - os_log("Display supports enabling DDC application report.", type: .debug) + if Arm64DDCUtils.isArm64 { + guard self.arm64ddc else { + return nil + } + if let unwrappedDelay = delay { + values = Arm64DDCUtils.read(service: self.arm64avService, command: command.rawValue, tries: UInt8(min(tries, 255)), minReplyDelay: UInt32(unwrappedDelay / 1000)) + } else { + values = Arm64DDCUtils.read(service: self.arm64avService, command: command.rawValue, tries: UInt8(min(tries, 255))) + } } else { - os_log("Display does not support enabling DDC application report.", type: .debug) - } + if self.ddc?.supported(minReplyDelay: delay) == true { + os_log("Display supports DDC.", type: .debug) + } else { + os_log("Display does not support DDC.", type: .debug) + } - values = self.ddc?.read(command: command, tries: tries, minReplyDelay: delay) + if self.ddc?.enableAppReport() == true { + os_log("Display supports enabling DDC application report.", type: .debug) + } else { + os_log("Display does not support enabling DDC application report.", type: .debug) + } + + values = self.ddc?.read(command: command, tries: tries, minReplyDelay: delay) + } return values } - func calcNewValue(for command: DDC.Command, isUp: Bool, isSmallIncrement: Bool) -> Int { - let currentValue = self.getValue(for: command) + func calcNewValue(currentValue: Int, maxValue: Int, isUp: Bool, isSmallIncrement: Bool) -> Int { let nextValue: Int - let maxValue = Float(self.getMaxValue(for: command)) if isSmallIncrement { nextValue = currentValue + (isUp ? 1 : -1) } else { - let osdChicletFromValue = OSDUtils.chiclet(fromValue: Float(currentValue), maxValue: maxValue) + let osdChicletFromValue = OSDUtils.chiclet(fromValue: Float(currentValue), maxValue: Float(maxValue)) let distance = OSDUtils.getDistance(fromNearestChiclet: osdChicletFromValue) // get the next rounded chiclet @@ -240,11 +329,11 @@ class ExternalDisplay: Display { nextFilledChiclet += 1 } - nextValue = Int(round(OSDUtils.value(fromChiclet: nextFilledChiclet, maxValue: maxValue))) + nextValue = Int(round(OSDUtils.value(fromChiclet: nextFilledChiclet, maxValue: Float(maxValue)))) os_log("next: .value %{public}@/%{public}@, .osd %{public}@/%{public}@", type: .debug, String(nextValue), String(maxValue), String(nextFilledChiclet), String(OSDUtils.chicletCount)) } - return max(0, min(self.getMaxValue(for: command), nextValue)) + return max(0, min(maxValue, nextValue)) } func getValue(for command: DDC.Command) -> Int { @@ -261,7 +350,7 @@ class ExternalDisplay: Display { func getMaxValue(for command: DDC.Command) -> Int { let max = self.prefs.integer(forKey: "max-\(command.rawValue)-\(self.identifier)") - return max == 0 ? 100 : max + return min(self.DDC_HARD_MAX_LIMIT, max == 0 ? self.DDC_HARD_MAX_LIMIT : max) } func getRestoreValue(for command: DDC.Command) -> Int { @@ -316,13 +405,8 @@ class ExternalDisplay: Display { return isSmallIncrement ? 1 : Int(floor(Float(self.getMaxValue(for: command)) / OSDUtils.chicletCount)) } - override func showOsd(command: DDC.Command, value: Int, maxValue _: Int = 100, roundChiclet: Bool = false) { - super.showOsd(command: command, value: value, maxValue: self.getMaxValue(for: command), roundChiclet: roundChiclet) - } - - private func supportsMuteCommand() -> Bool { - // Monitors which don't support the mute command - e.g. Dell U3419W - will have a maximum value of 100 for the DDC mute command - return self.getMaxValue(for: .audioMuteScreenBlank) == 2 + override func showOsd(command: DDC.Command, value: Int, maxValue _: Int = 100, roundChiclet: Bool = false, lock: Bool = false) { + super.showOsd(command: command, value: value, maxValue: self.getMaxValue(for: command), roundChiclet: roundChiclet, lock: lock) } private func playVolumeChangedSound() { diff --git a/MonitorControl/Model/InternalDisplay.swift b/MonitorControl/Model/InternalDisplay.swift index 4c6178df..ea3dd697 100644 --- a/MonitorControl/Model/InternalDisplay.swift +++ b/MonitorControl/Model/InternalDisplay.swift @@ -5,7 +5,7 @@ // Created by Joni Van Roost on 24/01/2020. // Copyright © 2020 MonitorControl. All rights reserved. // -// Most of the code in this file was sourced from: +// Some of the code in this file was sourced from: // https://github.com/fnesveda/ExternalDisplayBrightness // all credit goes to @fnesveda @@ -15,9 +15,9 @@ class InternalDisplay: Display { // the queue for dispatching display operations, so they're not performed directly and concurrently private var displayQueue: DispatchQueue - override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) { + override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) { self.displayQueue = DispatchQueue(label: String("displayQueue-\(identifier)")) - super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber) + super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual) } func calcNewBrightness(isUp: Bool, isSmallIncrement: Bool) -> Float { @@ -30,56 +30,17 @@ class InternalDisplay: Display { } public func getBrightness() -> Float { - self.displayQueue.sync { - Float(type(of: self).CoreDisplayGetUserBrightness?(self.identifier) ?? 0.5) - } + var brightness: Float = 0 + DisplayServicesGetBrightness(self.identifier, &brightness) + return brightness } override func stepBrightness(isUp: Bool, isSmallIncrement: Bool) { let value = self.calcNewBrightness(isUp: isUp, isSmallIncrement: isSmallIncrement) self.displayQueue.sync { - type(of: self).CoreDisplaySetUserBrightness?(self.identifier, Double(value)) - type(of: self).DisplayServicesBrightnessChanged?(self.identifier, Double(value)) + DisplayServicesSetBrightness(self.identifier, Float(value)) + DisplayServicesBrightnessChanged(self.identifier, Double(value)) self.showOsd(command: .brightness, value: Int(value * 64), maxValue: 64) } } - - // notifies the system that the brightness of a specified display has changed (to update System Preferences etc.) - // unfortunately Apple doesn't provide a public API for this, so we have to manually extract the function from the DisplayServices framework - private static var DisplayServicesBrightnessChanged: ((CGDirectDisplayID, Double) -> Void)? { - let displayServicesPath = CFURLCreateWithString(kCFAllocatorDefault, "/System/Library/PrivateFrameworks/DisplayServices.framework" as CFString, nil) - if let displayServicesBundle = CFBundleCreate(kCFAllocatorDefault, displayServicesPath) { - if let funcPointer = CFBundleGetFunctionPointerForName(displayServicesBundle, "DisplayServicesBrightnessChanged" as CFString) { - typealias DSBCFunctionType = @convention(c) (UInt32, Double) -> Void - return unsafeBitCast(funcPointer, to: DSBCFunctionType.self) - } - } - return nil - } - - // reads the brightness of a display through the CoreDisplay framework - // unfortunately Apple doesn't provide a public API for this, so we have to manually extract the function from the CoreDisplay framework - private static var CoreDisplayGetUserBrightness: ((CGDirectDisplayID) -> Double)? { - let coreDisplayPath = CFURLCreateWithString(kCFAllocatorDefault, "/System/Library/Frameworks/CoreDisplay.framework" as CFString, nil) - if let coreDisplayBundle = CFBundleCreate(kCFAllocatorDefault, coreDisplayPath) { - if let funcPointer = CFBundleGetFunctionPointerForName(coreDisplayBundle, "CoreDisplay_Display_GetUserBrightness" as CFString) { - typealias CDGUBFunctionType = @convention(c) (UInt32) -> Double - return unsafeBitCast(funcPointer, to: CDGUBFunctionType.self) - } - } - return nil - } - - // sets the brightness of a display through the CoreDisplay framework - // unfortunately Apple doesn't provide a public API for this, so we have to manually extract the function from the CoreDisplay framework - private static var CoreDisplaySetUserBrightness: ((CGDirectDisplayID, Double) -> Void)? { - let coreDisplayPath = CFURLCreateWithString(kCFAllocatorDefault, "/System/Library/Frameworks/CoreDisplay.framework" as CFString, nil) - if let coreDisplayBundle = CFBundleCreate(kCFAllocatorDefault, coreDisplayPath) { - if let funcPointer = CFBundleGetFunctionPointerForName(coreDisplayBundle, "CoreDisplay_Display_SetUserBrightness" as CFString) { - typealias CDSUBFunctionType = @convention(c) (UInt32, Double) -> Void - return unsafeBitCast(funcPointer, to: CDSUBFunctionType.self) - } - } - return nil - } } diff --git a/MonitorControl/Support/Arm64DDCUtils.swift b/MonitorControl/Support/Arm64DDCUtils.swift new file mode 100644 index 00000000..69452422 --- /dev/null +++ b/MonitorControl/Support/Arm64DDCUtils.swift @@ -0,0 +1,277 @@ +// +// Arm64DDCUitls.swift +// MonitorControl +// +// Created by @waydabber, 2021 +// Copyright © 2021. MonitorControl. All rights reserved. +// + +import Foundation +import IOKit + +class Arm64DDCUtils: NSObject { + public struct DisplayService { + var displayID: CGDirectDisplayID = 0 + var service: IOAVService? + var serviceLocation: Int = 0 + var isDiscouraged: Bool = false + } + + #if arch(arm64) + public static let isArm64: Bool = true + #else + public static let isArm64: Bool = false + #endif + + // This matches Displays to the right IOAVService + public static func getServiceMatches(displayIDs: [CGDirectDisplayID]) -> [DisplayService] { + let ioregServicesForMatching = self.getIoregServicesForMatching() + var matchedDisplayServices: [DisplayService] = [] + var scoredCandidateDisplayServices: [Int: [DisplayService]] = [:] + for displayID in displayIDs { + for ioregServiceForMatching in ioregServicesForMatching { + let score = self.ioregMatchScore(displayID: displayID, ioregEdidUUID: ioregServiceForMatching.edidUUID, ioregProductName: ioregServiceForMatching.productName, ioregSerialNumber: ioregServiceForMatching.serialNumber, serviceLocation: ioregServiceForMatching.serviceLocation) + let isDiscouraged = self.checkIfDiscouraged(ioregService: ioregServiceForMatching) + let displayService = DisplayService(displayID: displayID, service: ioregServiceForMatching.service, serviceLocation: ioregServiceForMatching.serviceLocation, isDiscouraged: isDiscouraged) + if scoredCandidateDisplayServices[score] == nil { + scoredCandidateDisplayServices[score] = [] + } + scoredCandidateDisplayServices[score]?.append(displayService) + } + } + var takenServiceLocations: [Int] = [] + var takenDisplayIDs: [CGDirectDisplayID] = [] + for score in stride(from: self.MAX_MATCH_SCORE, to: 0, by: -1) { + if let scoredCandidateDisplayService = scoredCandidateDisplayServices[score] { + for candidateDisplayService in scoredCandidateDisplayService { + if !(takenDisplayIDs.contains(candidateDisplayService.displayID) || takenServiceLocations.contains(candidateDisplayService.serviceLocation)) { + takenDisplayIDs.append(candidateDisplayService.displayID) + takenServiceLocations.append(candidateDisplayService.serviceLocation) + matchedDisplayServices.append(candidateDisplayService) + } + } + } + } + return matchedDisplayServices + } + + // Perform DDC read + public static func read(service: IOAVService?, command: UInt8, tries: UInt8 = 3, minReplyDelay: UInt32 = 10000) -> (current: UInt16, max: UInt16)? { + var values: (UInt16, UInt16)? + var send: [UInt8] = [command] + var reply = [UInt8](repeating: 0, count: 11) + if Arm64DDCUtils.performDDCCommunication(service: service, send: &send, reply: &reply, readSleepTime: minReplyDelay, numOfRetryAttemps: tries) { + let max = UInt16(reply[6]) * 256 + UInt16(reply[7]) + let current = UInt16(reply[8]) * 256 + UInt16(reply[9]) + values = (current, max) + } else { + values = nil + } + return values + } + + // Perform DDC write + public static func write(service: IOAVService?, command: UInt8, value: UInt16) -> Bool { + var send: [UInt8] = [command, UInt8(value >> 8), UInt8(value & 255)] + var reply: [UInt8] = [] + return Arm64DDCUtils.performDDCCommunication(service: service, send: &send, reply: &reply) + } + + // Performs DDC read or write + public static func performDDCCommunication(service: IOAVService?, send: inout [UInt8], reply: inout [UInt8], writeSleepTime: UInt32 = 10000, numofWriteCycles: UInt8 = 2, readSleepTime: UInt32 = 10000, numOfRetryAttemps: UInt8 = 3, retrySleepTime: UInt32 = 20000) -> Bool { + var success: Bool = false + guard service != nil else { + return success + } + var checkedsend: [UInt8] = [UInt8(0x80 | (send.count + 1)), UInt8(send.count)] + send + [0] + checkedsend[checkedsend.count - 1] = Utils.checksum(chk: send.count == 1 ? 0x6E : 0x6E ^ 0x51, data: &checkedsend, start: 0, end: checkedsend.count - 2) + for _ in 1 ... numOfRetryAttemps { + for _ in 1 ... numofWriteCycles { + usleep(writeSleepTime) + if IOAVServiceWriteI2C(service, 0x37, 0x51, &checkedsend, UInt32(checkedsend.count)) == 0 { + success = true + } + } + if reply.count > 0 { + usleep(readSleepTime) + if IOAVServiceReadI2C(service, 0x37, 0x51, &reply, UInt32(reply.count)) == 0 { + if Utils.checksum(chk: 0x50, data: &reply, start: 0, end: reply.count - 2) == reply[reply.count - 1] { + success = true + } else { + success = false + } + } + } + if success { + return success + } + usleep(retrySleepTime) + } + return success + } + + // ------- + + private struct IOregService { + var edidUUID: String = "" + var manufacturerID: String = "" + var productName: String = "" + var serialNumber: Int64 = 0 + var location: String = "" + var transportUpstream: String = "" + var transportDownstream: String = "" + var service: IOAVService? + var serviceLocation: Int = 0 + } + + private static let MAX_MATCH_SCORE: Int = 13 + + // Scores the likelihood of a display match based on EDID UUID, ProductName and SerialNumber from in ioreg, compared to DisplayCreateInfoDictionary. + private static func ioregMatchScore(displayID: CGDirectDisplayID, ioregEdidUUID: String, ioregProductName: String = "", ioregSerialNumber: Int64 = 0, serviceLocation: Int = 0) -> Int { + var matchScore: Int = 0 + if let dictionary = (CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary? { + if let kDisplayYearOfManufacture = dictionary[kDisplayYearOfManufacture] as? Int64, let kDisplayWeekOfManufacture = dictionary[kDisplayWeekOfManufacture] as? Int64, let kDisplayVendorID = dictionary[kDisplayVendorID] as? Int64, let kDisplayProductID = dictionary[kDisplayProductID] as? Int64, let kDisplayVerticalImageSize = dictionary[kDisplayVerticalImageSize] as? Int64, let kDisplayHorizontalImageSize = dictionary[kDisplayHorizontalImageSize] as? Int64 { + struct KeyLoc { + var key: String + var loc: Int + } + let edidUUIDSearchKeys: [KeyLoc] = [ + // Vendor ID + KeyLoc(key: String(format: "%04x", UInt16(max(0, min(kDisplayVendorID, 256 * 256 - 1)))).uppercased(), loc: 0), + // Product ID + KeyLoc(key: String(format: "%02x", UInt8((UInt16(max(0, min(kDisplayProductID, 256 * 256 - 1))) >> (0 * 8)) & 0xFF)).uppercased() + + String(format: "%02x", UInt8((UInt16(max(0, min(kDisplayProductID, 256 * 256 - 1))) >> (1 * 8)) & 0xFF)).uppercased(), loc: 4), + // Manufacture date + KeyLoc(key: String(format: "%02x", UInt8(max(0, min(kDisplayWeekOfManufacture, 256 - 1)))).uppercased() + + String(format: "%02x", UInt8(max(0, min(kDisplayYearOfManufacture - 1990, 256 - 1)))).uppercased(), loc: 19), + // Image size + KeyLoc(key: String(format: "%02x", UInt8(max(0, min(kDisplayHorizontalImageSize / 10, 256 - 1)))).uppercased() + + String(format: "%02x", UInt8(max(0, min(kDisplayVerticalImageSize / 10, 256 - 1)))).uppercased(), loc: 30), + ] + for searchKey in edidUUIDSearchKeys where searchKey.key != "0000" && searchKey.key == ioregEdidUUID.prefix(searchKey.loc + 4).suffix(4) { + matchScore += 2 + } + } + if ioregProductName != "", let nameList = dictionary["DisplayProductName"] as? [String: String], let name = nameList["en_US"] ?? nameList.first?.value, name.lowercased() == ioregProductName.lowercased() { + matchScore += 2 + } + if ioregSerialNumber != 0, let serial = dictionary[kDisplaySerialNumber] as? Int64, serial == ioregSerialNumber { + matchScore += 2 + } + if serviceLocation == displayID { + matchScore += 1 + } + } + return matchScore + } + + // Iterate to the next AppleCLCD2 or DCPAVServiceProxy item in the ioreg tree and return the name and corresponding service + private static func ioregIterateToNextObjectOfInterest(interests _: [String], iterator: inout io_iterator_t) -> (name: String, service: io_service_t)? { + var objectName: String = "" + var service: io_service_t = IO_OBJECT_NULL + let name = UnsafeMutablePointer.allocate(capacity: MemoryLayout.size) + defer { + name.deallocate() + } + while true { + service = IOIteratorNext(iterator) + guard service != MACH_PORT_NULL else { + service = IO_OBJECT_NULL + break + } + guard IORegistryEntryGetName(service, name) == KERN_SUCCESS else { + service = IO_OBJECT_NULL + break + } + if String(cString: name) == "AppleCLCD2" || String(cString: name) == "DCPAVServiceProxy" { + objectName = String(cString: name) + return (objectName, service) + } + } + return nil + } + + // Returns EDID UUDI, Product Name and Serial Number in an IOregService if it is found using the provided io_service_t pointing to a AppleCDC2 item in the ioreg tree + private static func getIORegServiceAppleCDC2Properties(service: io_service_t) -> IOregService { + var ioregService = IOregService() + if let unmanagedEdidUUID = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "EDID UUID", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let edidUUID = unmanagedEdidUUID.takeRetainedValue() as? String { + ioregService.edidUUID = edidUUID + } + if let unmanagedDisplayAttrs = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "DisplayAttributes", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let displayAttrs = unmanagedDisplayAttrs.takeRetainedValue() as? NSDictionary, let productAttrs = displayAttrs.value(forKey: "ProductAttributes") as? NSDictionary { + if let manufacturerID = productAttrs.value(forKey: "ManufacturerID") as? String { + ioregService.manufacturerID = manufacturerID + } + if let productName = productAttrs.value(forKey: "ProductName") as? String { + ioregService.productName = productName + } + if let serialNumber = productAttrs.value(forKey: "SerialNumber") as? Int64 { + ioregService.serialNumber = serialNumber + } + } + if let unmanagedTransport = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "Transport", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let transport = unmanagedTransport.takeRetainedValue() as? NSDictionary { + if let upstream = transport.value(forKey: "Upstream") as? String { + ioregService.transportUpstream = upstream + } + if let downstream = transport.value(forKey: "Downstream") as? String { + ioregService.transportDownstream = downstream + } + } + return ioregService + } + + // Sets up the service in an IOregService if it is found using the provided io_service_t pointing to a DCPAVServiceProxy item in the ioreg tree + private static func setIORegServiceDCPAVServiceProxy(service: io_service_t, ioregService: inout IOregService) { + if let unmanagedLocation = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "Location", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let location = unmanagedLocation.takeRetainedValue() as? String { + ioregService.location = location + if location == "External" { + ioregService.service = IOAVServiceCreateWithService(kCFAllocatorDefault, service)?.takeRetainedValue() as IOAVService + } + } + } + + // Returns IOAVSerivces with associated display properties for matching logic + private static func getIoregServicesForMatching() -> [IOregService] { + var serviceLocation: Int = 0 + var ioregServicesForMatching: [IOregService] = [] + let ioregRoot: io_registry_entry_t = IORegistryGetRootEntry(kIOMasterPortDefault) + var iterator = io_iterator_t() + var ioregService = IOregService() + guard IORegistryEntryCreateIterator(ioregRoot, "IOService", IOOptionBits(kIORegistryIterateRecursively), &iterator) == KERN_SUCCESS else { + return ioregServicesForMatching + } + while true { + if let objectOfInterest = ioregIterateToNextObjectOfInterest(interests: ["AppleCLCD2", "DCPAVServiceProxy"], iterator: &iterator) { + if objectOfInterest.name == "AppleCLCD2", objectOfInterest.service != IO_OBJECT_NULL { + ioregService = self.getIORegServiceAppleCDC2Properties(service: objectOfInterest.service) + serviceLocation += 1 + ioregService.serviceLocation = serviceLocation + } + if objectOfInterest.name == "DCPAVServiceProxy", objectOfInterest.service != IO_OBJECT_NULL { + self.setIORegServiceDCPAVServiceProxy(service: objectOfInterest.service, ioregService: &ioregService) + ioregServicesForMatching.append(ioregService) + } + } else { + break + } + } + return ioregServicesForMatching + } + + // Check if it is problematic to enable DDC on the display + private static func checkIfDiscouraged(ioregService: IOregService) -> Bool { + var modelIdentifier: String = "" + let platformExpertDevice = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")) + if let modelData = IORegistryEntryCreateCFProperty(platformExpertDevice, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data, let modelIdentifierCString = String(data: modelData, encoding: .utf8)?.cString(using: .utf8) { + modelIdentifier = String(cString: modelIdentifierCString) + } + // This is a well known dummy plug (not a real display) but it breaks DDC communication on M1 + if ioregService.manufacturerID == "AOC", ioregService.productName == "28E850" { + return true + } + // First service location of Mac Mini HDMI is broken for DDC communication + if ioregService.transportDownstream == "HDMI", ioregService.serviceLocation == 1, modelIdentifier == "Macmini9,1" { + return true + } + return false + } +} diff --git a/MonitorControl/Support/Bridging-Header.h b/MonitorControl/Support/Bridging-Header.h index f529e5ba..2b704058 100644 --- a/MonitorControl/Support/Bridging-Header.h +++ b/MonitorControl/Support/Bridging-Header.h @@ -1,4 +1,48 @@ #pragma once #import -#import +#import +#import + +typedef CFTypeRef IOAVService; +extern IOAVService IOAVServiceCreate(CFAllocatorRef allocator); +extern IOAVService IOAVServiceCreateWithService(CFAllocatorRef allocator, io_service_t service); +extern IOReturn IOAVServiceReadI2C(IOAVService service, uint32_t chipAddress, uint32_t offset, void* outputBuffer, uint32_t outputBufferSize); +extern IOReturn IOAVServiceWriteI2C(IOAVService service, uint32_t chipAddress, uint32_t dataAddress, void* inputBuffer, uint32_t inputBufferSize); +extern CFDictionaryRef CoreDisplay_DisplayCreateInfoDictionary(CGDirectDisplayID); + +extern void DisplayServicesBrightnessChanged(CGDirectDisplayID display, double brightness); +extern int DisplayServicesGetBrightness(CGDirectDisplayID display, float *brightness); +extern int DisplayServicesSetBrightness(CGDirectDisplayID display, float brightness); + +@class NSString; + +@protocol OSDUIHelperProtocol +- (void)showFullScreenImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecToAnimate:(unsigned int)arg4; +- (void)fadeClassicImageOnDisplay:(unsigned int)arg1; +- (void)showImageAtPath:(NSString *)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(NSString *)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 filledChiclets:(unsigned int)arg5 totalChiclets:(unsigned int)arg6 locked:(BOOL)arg7; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(NSString *)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4; +@end + +@class NSXPCConnection; + +@interface OSDManager : NSObject +{ + id _proxyObject; + NSXPCConnection *connection; +} + ++ (id)sharedManager; +@property(retain) NSXPCConnection *connection; // @synthesize connection; +- (void)showFullScreenImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecToAnimate:(unsigned int)arg4; +- (void)fadeClassicImageOnDisplay:(unsigned int)arg1; +- (void)showImageAtPath:(id)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(id)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 filledChiclets:(unsigned int)arg5 totalChiclets:(unsigned int)arg6 locked:(BOOL)arg7; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(id)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4; +@property(readonly) id remoteObjectProxy; // @dynamic remoteObjectProxy; + +@end + diff --git a/MonitorControl/Support/OSDUtils.swift b/MonitorControl/Support/OSDUtils.swift index 9b8da0ad..9aa4adf0 100644 --- a/MonitorControl/Support/OSDUtils.swift +++ b/MonitorControl/Support/OSDUtils.swift @@ -22,4 +22,17 @@ class OSDUtils: NSObject { static func getDistance(fromNearestChiclet chiclet: Float) -> Float { return abs(chiclet.rounded(.towardZero) - chiclet) } + + static func showOSDLockOnAllDisplays(osdImage: Int64) { + var displayCount: UInt32 = 0 + var onlineDisplays = [CGDirectDisplayID](repeating: 0, count: Int(16)) + if CGGetOnlineDisplayList(16, &onlineDisplays, &displayCount) == CGError.success { + let displayIDs = onlineDisplays.prefix(Int(displayCount)) + for id in displayIDs { + if let manager = OSDManager.sharedManager() as? OSDManager { + manager.showImage(osdImage, onDisplayID: id, priority: 0x1F4, msecUntilFade: 1000, filledChiclets: 0, totalChiclets: 100, locked: true) + } + } + } + } } diff --git a/MonitorControl/Support/Utils.swift b/MonitorControl/Support/Utils.swift index 7db7f9e3..d6987fbe 100644 --- a/MonitorControl/Support/Utils.swift +++ b/MonitorControl/Support/Utils.swift @@ -14,25 +14,48 @@ class Utils: NSObject { /// - command: Command (Brightness/Volume/...) /// - title: Title of the slider /// - Returns: An `NSSlider` slider - static func addSliderMenuItem(toMenu menu: NSMenu, forDisplay display: ExternalDisplay, command: DDC.Command, title: String) -> SliderHandler { + static func addSliderMenuItem(toMenu menu: NSMenu, forDisplay display: ExternalDisplay, command: DDC.Command, title: String, numOfTickMarks: Int = 0) -> SliderHandler { let item = NSMenuItem() let handler = SliderHandler(display: display, command: command) let slider = NSSlider(value: 0, minValue: 0, maxValue: 100, target: handler, action: #selector(SliderHandler.valueChanged)) slider.isEnabled = false - slider.frame.size.width = 180 - slider.frame.origin = NSPoint(x: 20, y: 5) - handler.slider = slider - let view = NSView(frame: NSRect(x: 0, y: 0, width: slider.frame.width + 30, height: slider.frame.height + 10)) - view.addSubview(slider) - - item.view = view - - menu.insertItem(item, at: 0) - menu.insertItem(withTitle: title, action: nil, keyEquivalent: "", at: 0) + if #available(macOS 11.0, *) { + slider.frame.size.width = 160 + slider.frame.origin = NSPoint(x: 35, y: 5) + let view = NSView(frame: NSRect(x: 0, y: 0, width: slider.frame.width + 47, height: slider.frame.height + 14)) + view.frame.origin = NSPoint(x: 12, y: 0) + var iconName: String = "circle.dashed" + switch command { + case .audioSpeakerVolume: iconName = "speaker.wave.2" + case .brightness: iconName = "sun.max" + case .contrast: iconName = "circle.lefthalf.fill" + default: break + } + let icon = NSImageView(image: NSImage(systemSymbolName: iconName, accessibilityDescription: title)!) + icon.frame = view.frame + icon.wantsLayer = true + icon.alphaValue = 0.7 + icon.imageAlignment = NSImageAlignment.alignLeft + view.addSubview(icon) + view.addSubview(slider) + item.view = view + menu.insertItem(item, at: 0) + } else { + slider.frame.size.width = 180 + slider.frame.origin = NSPoint(x: 15, y: 5) + let view = NSView(frame: NSRect(x: 0, y: 0, width: slider.frame.width + 30, height: slider.frame.height + 10)) + let sliderHeaderItem = NSMenuItem() + let attrs: [NSAttributedString.Key: Any] = [.foregroundColor: NSColor.systemGray, .font: NSFont.systemFont(ofSize: 12)] + sliderHeaderItem.attributedTitle = NSAttributedString(string: title, attributes: attrs) + view.addSubview(slider) + item.view = view + menu.insertItem(item, at: 0) + menu.insertItem(sliderHeaderItem, at: 0) + } var values: (UInt16, UInt16)? let delay = display.needsLongerDelay ? UInt64(40 * kMillisecondScale) : nil @@ -40,23 +63,31 @@ class Utils: NSObject { let tries = UInt(display.getPollingCount()) os_log("Polling %{public}@ times", type: .info, String(tries)) - if tries != 0 { - values = display.readDDCValues(for: command, tries: tries, minReplyDelay: delay) - } + var (currentValue, maxValue) = (UInt16(0), UInt16(0)) - let (currentDDCValue, maxValue) = values ?? (UInt16(display.getValue(for: command)), UInt16(display.getMaxValue(for: command))) - - display.saveValue(Int(currentDDCValue), for: command) + if display.isSw(), command == DDC.Command.brightness { + (currentValue, maxValue) = (UInt16(display.getSwBrightnessPrefValue()), UInt16(display.getSwMaxBrightness())) + } else { + if tries != 0 { + values = display.readDDCValues(for: command, tries: tries, minReplyDelay: delay) + } + (currentValue, maxValue) = values ?? (UInt16(display.getValue(for: command)), 0) // We set 0 for max. value to indicate that there is no real DDC reported max. value - ExternalDisplay.getMaxValue() will return 100 in case of 0 max. values. + } display.saveMaxValue(Int(maxValue), for: command) - + display.saveValue(min(Int(currentValue), display.getMaxValue(for: command)), for: command) // We won't allow currrent value to be higher than the max. value os_log("%{public}@ (%{public}@):", type: .info, display.name, String(reflecting: command)) - os_log(" - current ddc value: %{public}@ - from display? %{public}@", type: .info, String(currentDDCValue), String(values != nil)) - os_log(" - maximum ddc value: %{public}@ - from display? %{public}@", type: .info, String(maxValue), String(values != nil)) + os_log(" - current value: %{public}@ - from display? %{public}@", type: .info, String(currentValue), String(values != nil)) + os_log(" - maximum value: %{public}@ - from display? %{public}@", type: .info, String(display.getMaxValue(for: command)), String(values != nil)) - if command != .audioSpeakerVolume { - slider.integerValue = Int(currentDDCValue) - slider.maxValue = Double(maxValue) - } else { + if command == .brightness { + if !display.isSw(), prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + slider.maxValue = Double(display.getMaxValue(for: command) * 2) + slider.integerValue = Int(slider.maxValue) / 2 + Int(currentValue) + } else { + slider.integerValue = Int(currentValue) + slider.maxValue = Double(display.getMaxValue(for: command)) + } + } else if command == .audioSpeakerVolume { // If we're looking at the audio speaker volume, also retrieve the values for the mute command var muteValues: (current: UInt16, max: UInt16)? @@ -80,14 +111,18 @@ class Utils: NSObject { // If the system is not currently muted, or doesn't support the mute command, display the current volume as the slider value if muteValues == nil || muteValues!.current == 2 { - slider.integerValue = Int(currentDDCValue) + slider.integerValue = Int(currentValue) } else { slider.integerValue = 0 } - slider.maxValue = Double(maxValue) + slider.maxValue = Double(display.getMaxValue(for: command)) + } else { + slider.integerValue = Int(currentValue) + slider.maxValue = Double(display.getMaxValue(for: command)) } + slider.numberOfTickMarks = numOfTickMarks slider.isEnabled = true return handler } @@ -133,6 +168,22 @@ class Utils: NSObject { } } + static func checksum(chk: UInt8, data: inout [UInt8], start: Int, end: Int) -> UInt8 { + var chkd: UInt8 = chk + for i in start ... end { + chkd ^= data[i] + } + return chkd + } + + static func alert(text: String) { + let alert = NSAlert() + alert.messageText = text + alert.alertStyle = NSAlert.Style.informational + alert.addButton(withTitle: "OK") + alert.runModal() + } + // MARK: - Enums /// UserDefault Keys for the app prefs @@ -143,14 +194,23 @@ class Utils: NSObject { /// Does the app start when plugged to an external monitor case startWhenExternal + /// Hide menu icon + case hideMenuIcon + /// Keys listened for (Brightness/Volume) case listenFor /// Show contrast sliders case showContrast - /// Lower contrast after brightness - case lowerContrast + /// Show volume sliders + case showVolume + + /// Lower via software after brightness + case lowerSwAfterBrightness + + /// Fallback to software control for external displays with no DDC + case fallbackSw /// Change Brightness/Volume for all screens case allScreens @@ -163,6 +223,9 @@ class Utils: NSObject { /// Used for notification when displays are updated in DisplayManager case displayListUpdate + + /// Show advanced options under Displays tab in Preferences + case showAdvancedDisplays } /// Keys for the value of listenFor option diff --git a/MonitorControl/Support/de.lproj/Localizable.strings b/MonitorControl/Support/de.lproj/Localizable.strings index 42a62edf..c193ada0 100644 --- a/MonitorControl/Support/de.lproj/Localizable.strings +++ b/MonitorControl/Support/de.lproj/Localizable.strings @@ -1,5 +1,8 @@ -/* Shown in the main prefs window */ -"Advanced" = "Erweitert"; +/* Shown in the main prefs window */ +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Build"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Kontrast"; -/* Shown in menu */ -"Default" = "Standard"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; /* Shown in the main prefs window */ -"Display" = "Monitor"; +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "Allgemein"; -/* Shown in the main prefs window */ -"Keys" = "Tasten"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "Kein unterstützter Monitor angeschlossen"; /* Shown in the alert dialog */ "Ok" = "OK"; -/* Shown in Preferences window */ -"Preferences" = "Einstellungen"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Als Standard festlegen"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Kurzbefehle nicht verfügbar"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* unknown display name unknown model unknown vendor */ "Unknown" = "Unbekannt"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Version"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Lautstärke"; diff --git a/MonitorControl/Support/en.lproj/Localizable.strings b/MonitorControl/Support/en.lproj/Localizable.strings index d16cd647..ccbb2d81 100644 --- a/MonitorControl/Support/en.lproj/Localizable.strings +++ b/MonitorControl/Support/en.lproj/Localizable.strings @@ -1,5 +1,8 @@ /* Shown in the main prefs window */ -"Advanced" = "Advanced"; +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -7,59 +10,81 @@ /* Shown in the alert dialog */ "Are you sure you want to reset all preferences?" = "Are you sure you want to reset all preferences?"; -/* Sown in menu */ +/* Shown in menu */ "Brightness" = "Brightness"; /* Build */ "Build" = "Build"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Contrast"; -/* Shown in menu */ -"Default" = "Default"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "Display"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "General"; -/* Shown in the main prefs window */ -"Keys" = "Keys"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "No supported display found"; /* Shown in the alert dialog */ "Ok" = "Ok"; -/* Shown in Preferences window */ -"Preferences" = "Preferences"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Set as default"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Shortcuts not available"; -/* Unknown display name - Unknown model - Unknown vendor */ +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + +/* Unknown display name */ "Unknown" = "Unknown"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Version"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Volume"; diff --git a/MonitorControl/Support/fr.lproj/Localizable.strings b/MonitorControl/Support/fr.lproj/Localizable.strings index dbb1a22e..3e66af28 100644 --- a/MonitorControl/Support/fr.lproj/Localizable.strings +++ b/MonitorControl/Support/fr.lproj/Localizable.strings @@ -1,5 +1,8 @@ /* Shown in the main prefs window */ -"Advanced" = "Advanced"; +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Build"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Contraste"; -/* Shown in menu */ -"Default" = "Écran par défaut"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "Écrans"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "Général"; -/* Shown in the main prefs window */ -"Keys" = "Touches"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "Aucun écran supporté trouvé"; /* Shown in the alert dialog */ "Ok" = "Ok"; -/* Shown in Preferences window */ -"Preferences" = "Préférences"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Enregistrer comme écran par défaut"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Raccourcis non disponible"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "Inconnu"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Version"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Volume"; diff --git a/MonitorControl/Support/hu.lproj/Localizable.strings b/MonitorControl/Support/hu.lproj/Localizable.strings new file mode 100644 index 00000000..5b758d11 --- /dev/null +++ b/MonitorControl/Support/hu.lproj/Localizable.strings @@ -0,0 +1,97 @@ +/* Shown in the main prefs window */ +"About" = "Névjegy"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; + +/* Shown in the alert dialog */ +"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." = "Biztos benne, hogy engedélyezni kívánja a hosszabb várakozást? Ez bizonyos esetekben a rendszer lefagyását eredményezheti, akár újraindítás is szükségessé válhat. A bejelentkezéskori automatikus indítást letiltjuk a biztonság kedvéért."; + +/* Shown in the alert dialog */ +"Are you sure you want to reset all preferences?" = "Biztos benne, hogy vissza kívánja állítani az alapértelmezett beállításokat?"; + +/* Sown in menu */ +"Brightness" = "Fényerő"; + +/* Build */ +"Build" = "Build"; + +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + +/* Shown in menu */ +"Contrast" = "Kontraszt"; + +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; + +/* Shown in the main prefs window */ +"Displays" = "Kijelzők"; + +/* Shown in the alert dialog */ +"Enable Longer Delay?" = "Hosszabb várakozás engedélyezése?"; + +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + +/* Shown in the main prefs window */ +"General" = "Általános"; + +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardver (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardver (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; + +/* Shown in the alert dialog */ +"No" = "Nem"; + +/* Shown in the Display Preferences */ +"No Control Available" = "Nincs vezérlés"; + +/* Shown in menu */ +"No supported display found" = "Nincs támogatott kijelző"; + +/* Shown in the alert dialog */ +"Ok" = "Ok"; + +/* Shown in the Display Preferences */ +"Other Display" = "Egyéb kijelző"; + +/* Shown in the alert dialog */ +"Reset Preferences?" = "Alapértelmezett beállítások"; + +/* Shown in the alert dialog */ +"Shortcuts not available" = "Gyorsbillentyűk nem elérhetők"; + +/* Shown in the Display Preferences */ +"Software (Forced)" = "Szoftveres"; + +/* Shown in the Display Preferences */ +"Software Only" = "Csak szoftveres"; + +/* Unknown display name + Unknown model + Unknown vendor */ +"Unknown" = "Ismeretlen"; + +/* Shown in the Display Preferences */ +"Unspecified" = "Meghatározatlan"; + +/* Version */ +"Version" = "Verzió"; + +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtuális kijelző"; + +/* Shown in menu */ +"Volume" = "Hangerő"; + +/* Shown in the alert dialog */ +"Yes" = "Igen"; + +/* Shown in the alert dialog */ +"You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work" = "Engedélyeznie kell a MonitorControlt a Rendszerbeállítások > Biztonság és adatvédelem > Kisegítő lehetőségek alatt a gyorsbillentyűk használatához!"; diff --git a/MonitorControl/Support/it.lproj/Localizable.strings b/MonitorControl/Support/it.lproj/Localizable.strings index 50d4a61f..b4902f2a 100644 --- a/MonitorControl/Support/it.lproj/Localizable.strings +++ b/MonitorControl/Support/it.lproj/Localizable.strings @@ -1,5 +1,8 @@ /* Shown in the main prefs window */ -"Advanced" = "Advanced"; +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Build"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Contrasto"; -/* Shown in menu */ -"Default" = "Predefinito"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "Monitor"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "Generale"; -/* Shown in the main prefs window */ -"Keys" = "Tasti"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "Nessuno schermo supportato è stato trovato"; /* Shown in the alert dialog */ "Ok" = "Ok"; -/* Shown in Preferences window */ -"Preferences" = "Preferenze"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Imposta come default"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Comandi rapidi non disponibili"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "Sconosciuto"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Versione"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Volume"; diff --git a/MonitorControl/Support/ja.lproj/Localizable.strings b/MonitorControl/Support/ja.lproj/Localizable.strings index 8776ebd4..10acd33b 100644 --- a/MonitorControl/Support/ja.lproj/Localizable.strings +++ b/MonitorControl/Support/ja.lproj/Localizable.strings @@ -1,5 +1,8 @@ -/* Shown in the main prefs window */ -"Advanced" = "詳細設定"; +/* Shown in the main prefs window */ +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "ビルド"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "コントラスト"; -/* Shown in menu */ -"Default" = "デフォルト"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "ディスプレイ"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "一般"; -/* Shown in the main prefs window */ -"Keys" = "キー"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "サポートされていないディスプレイが検知されました"; /* Shown in the alert dialog */ "Ok" = "OK"; -/* Shown in Preferences window */ -"Preferences" = "環境設定"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "デフォルトとして設定"; - /* Shown in the alert dialog */ "Shortcuts not available" = "ショートカットキーを使用できません"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "不明"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "バージョン"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "音量"; diff --git a/MonitorControl/Support/pl.lproj/Localizable.strings b/MonitorControl/Support/pl.lproj/Localizable.strings index 62e15387..e9ef647c 100644 --- a/MonitorControl/Support/pl.lproj/Localizable.strings +++ b/MonitorControl/Support/pl.lproj/Localizable.strings @@ -1,5 +1,8 @@ /* Shown in the main prefs window */ -"Advanced" = "Zaawansowane"; +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "Czy na pewno chcesz ustawić większe opóźnienie? Może to skutkować zawieszeniem systemu i koniecznością restartu. Uruchamianie programu podczas logowania zostanie wyłączone."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Kompilacja"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Kontrast"; -/* Shown in menu */ -"Default" = "Domyślnie"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "Wyświetlacz"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "Ogólne"; -/* Shown in the main prefs window */ -"Keys" = "Klawisze"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "Nie"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "Nie znaleziono obsługiwanego wyświetlacza"; /* Shown in the alert dialog */ "Ok" = "Ok"; -/* Shown in Preferences window */ -"Preferences" = "Preferencje"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Ustaw jako domyślne"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Skróty klawiszowe niedostępne"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "Nieznany"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Wersja"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Głośność"; diff --git a/MonitorControl/Support/ru.lproj/Localizable.strings b/MonitorControl/Support/ru.lproj/Localizable.strings index b5f3081a..831d1f0a 100644 --- a/MonitorControl/Support/ru.lproj/Localizable.strings +++ b/MonitorControl/Support/ru.lproj/Localizable.strings @@ -1,5 +1,8 @@ -/* Shown in the main prefs window */ -"Advanced" = "Дополнительные"; +/* Shown in the main prefs window */ +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Сборка"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Контрастность"; -/* Shown in menu */ -"Default" = "По умолчанию"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "Мониторы"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "Основные"; -/* Shown in the main prefs window */ -"Keys" = "Сочетания клавиш"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "Поддерживаемых мониторов не найдено"; /* Shown in the alert dialog */ "Ok" = "ОК"; -/* Shown in Preferences window */ -"Preferences" = "Настройки"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Сделать основным"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Сочетания клавиш недоступны"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "Неизвестный"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Версия"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Громкость"; diff --git a/MonitorControl/Support/uk.lproj/Localizable.strings b/MonitorControl/Support/uk.lproj/Localizable.strings index c150714b..52f9ee27 100644 --- a/MonitorControl/Support/uk.lproj/Localizable.strings +++ b/MonitorControl/Support/uk.lproj/Localizable.strings @@ -1,5 +1,8 @@ -/* Shown in the main prefs window */ -"Advanced" = "Розширені"; +/* Shown in the main prefs window */ +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Білд"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "Контраст"; -/* Shown in menu */ -"Default" = "Стандартне"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "Дісплей"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "Загальні"; -/* Shown in the main prefs window */ -"Keys" = "Клавіші"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "Не знайдено жодного дісплею"; /* Shown in the alert dialog */ "Ok" = "ОК"; -/* Shown in Preferences window */ -"Preferences" = "Налаштування"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "Вибрати за-умовчанням"; - /* Shown in the alert dialog */ "Shortcuts not available" = "Скорочення недоступні"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "Невідомо"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Версія"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "Гучність"; diff --git a/MonitorControl/Support/zh-Hans.lproj/Localizable.strings b/MonitorControl/Support/zh-Hans.lproj/Localizable.strings index d35f1bca..4ff183dd 100644 --- a/MonitorControl/Support/zh-Hans.lproj/Localizable.strings +++ b/MonitorControl/Support/zh-Hans.lproj/Localizable.strings @@ -1,5 +1,8 @@ -/* Shown in the main prefs window */ -"Advanced" = "进阶设置"; +/* Shown in the main prefs window */ +"About" = "About"; + +/* Apple Silicon designation (shown after the version number in Preferences) */ +"Apple Silicon" = "Apple Silicon"; /* Shown in the alert dialog */ "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." = "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."; @@ -13,53 +16,77 @@ /* Build */ "Build" = "Build"; +/* Shown in the Display Preferences */ +"Built-in Display" = "Built-in Display"; + /* Shown in menu */ "Contrast" = "对比度"; -/* Shown in menu */ -"Default" = "默认"; +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; -/* No comment provided by engineer. */ -"Display" = "显示器"; +/* Shown in the main prefs window */ +"Displays" = "Displays"; /* Shown in the alert dialog */ "Enable Longer Delay?" = "Enable Longer Delay?"; +/* Shown in the Display Preferences */ +"External Display" = "External Display"; + /* Shown in the main prefs window */ "General" = "通用"; -/* Shown in the main prefs window */ -"Keys" = "快捷键"; +/* Shown in the Display Preferences */ +"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Hardware (DDC)"; + +/* Intel designation (shown after the version number in Preferences) */ +"Intel" = "Intel"; /* Shown in the alert dialog */ "No" = "No"; +/* Shown in the Display Preferences */ +"No Control Available" = "No Control Available"; + /* Shown in menu */ "No supported display found" = "未发现支持的显示器"; /* Shown in the alert dialog */ "Ok" = "Ok"; -/* Shown in Preferences window */ -"Preferences" = "偏好设置"; +/* Shown in the Display Preferences */ +"Other Display" = "Other Display"; /* Shown in the alert dialog */ "Reset Preferences?" = "Reset Preferences?"; -/* Shown in menu */ -"Set as default" = "设为默认"; - /* Shown in the alert dialog */ "Shortcuts not available" = "快捷键不可用"; +/* Shown in the Display Preferences */ +"Software (Forced)" = "Software (Forced)"; + +/* Shown in the Display Preferences */ +"Software Only" = "Software Only"; + /* Unknown display name Unknown model Unknown vendor */ "Unknown" = "Unknown"; +/* Shown in the Display Preferences */ +"Unspecified" = "Unspecified"; + /* Version */ "Version" = "Version"; +/* Shown in the Display Preferences */ +"Virtual Display" = "Virtual Display"; + /* Shown in menu */ "Volume" = "音量"; diff --git a/MonitorControl/UI/Base.lproj/Main.storyboard b/MonitorControl/UI/Base.lproj/Main.storyboard index 9a946b23..e1544f05 100644 --- a/MonitorControl/UI/Base.lproj/Main.storyboard +++ b/MonitorControl/UI/Base.lproj/Main.storyboard @@ -1,43 +1,227 @@ - + - + + - - + + - - - + + + - - - - - + + - + + + + + + + + + + + + + + + + + + + - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only. + + + + + + + + + + + + + + + + + + + + + + + + @@ -59,410 +243,72 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - @@ -473,355 +319,479 @@ - - + + - + + + + + + + - - + - - + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - Warning ⚠️ -Changing some of these setting may cause system freezes or unexpected behaviour. - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - + + + + + + - + - + + + + diff --git a/MonitorControl/UI/Base.lproj/MainMenu.xib b/MonitorControl/UI/Base.lproj/MainMenu.xib index c158ef84..f4c931f6 100644 --- a/MonitorControl/UI/Base.lproj/MainMenu.xib +++ b/MonitorControl/UI/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + diff --git a/MonitorControl/UI/Cells/ButtonCellView.swift b/MonitorControl/UI/Cells/ButtonCellView.swift deleted file mode 100644 index a0d59fff..00000000 --- a/MonitorControl/UI/Cells/ButtonCellView.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Cocoa -import os.log - -class ButtonCellView: NSTableCellView { - @IBOutlet var button: NSButton! - var display: Display? - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - } - - @IBAction func buttonToggled(_ sender: NSButton) { - if let display = display { - let isEnabled = sender.state == .on - display.isEnabled = isEnabled - #if DEBUG - os_log("Toggle enabled display state: %{public}@", type: .info, isEnabled ? "on" : "off") - #endif - } - } -} diff --git a/MonitorControl/UI/Cells/FriendlyNameCellView.swift b/MonitorControl/UI/Cells/FriendlyNameCellView.swift deleted file mode 100644 index 6ecf643f..00000000 --- a/MonitorControl/UI/Cells/FriendlyNameCellView.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Cocoa -import os.log - -class FriendlyNameCellView: NSTableCellView { - var display: Display? - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - } - - @IBAction func valueChanged(_ sender: NSTextFieldCell) { - if let display = display { - let newValue = sender.stringValue - let originalValue = display.getFriendlyName() - - if newValue.isEmpty { - self.textField?.stringValue = originalValue - return - } - - if newValue != originalValue, - !newValue.isEmpty - { - display.setFriendlyName(newValue) - NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.friendlyName.rawValue), object: nil) - #if DEBUG - os_log("Value changed for friendly name: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`") - #endif - } - } - } -} diff --git a/MonitorControl/UI/Cells/HideOsdCellView.swift b/MonitorControl/UI/Cells/HideOsdCellView.swift deleted file mode 100644 index 704eed87..00000000 --- a/MonitorControl/UI/Cells/HideOsdCellView.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Cocoa -import os.log - -class HideOsdCellView: NSTableCellView { - @IBOutlet var button: NSButton! - var display: ExternalDisplay? - 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 - } - } - } -} diff --git a/MonitorControl/UI/Cells/LongerDelayCellView.swift b/MonitorControl/UI/Cells/LongerDelayCellView.swift deleted file mode 100644 index 7f7b73c3..00000000 --- a/MonitorControl/UI/Cells/LongerDelayCellView.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Cocoa -import os.log - -class LongerDelayCellView: NSTableCellView { - @IBOutlet var button: NSButton! - var display: ExternalDisplay? - 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() - 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 - } - } - } -} diff --git a/MonitorControl/UI/Cells/PollingCountCellView.swift b/MonitorControl/UI/Cells/PollingCountCellView.swift deleted file mode 100644 index 932886e7..00000000 --- a/MonitorControl/UI/Cells/PollingCountCellView.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Cocoa -import os.log - -class PollingCountCellView: NSTableCellView { - var display: ExternalDisplay? - - @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)`") - } - } - } -} diff --git a/MonitorControl/UI/Cells/PollingModeCellView.swift b/MonitorControl/UI/Cells/PollingModeCellView.swift deleted file mode 100644 index cfc79767..00000000 --- a/MonitorControl/UI/Cells/PollingModeCellView.swift +++ /dev/null @@ -1,31 +0,0 @@ -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: ExternalDisplay? - @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)`") - } - } - } -} diff --git a/MonitorControl/UI/SliderHandler.swift b/MonitorControl/UI/SliderHandler.swift index 362c06f7..91d96818 100644 --- a/MonitorControl/UI/SliderHandler.swift +++ b/MonitorControl/UI/SliderHandler.swift @@ -12,6 +12,9 @@ class SliderHandler { } @objc func valueChanged(slider: NSSlider) { + guard app.sleepID == 0, app.reconfigureID == 0 else { + return + } let snapInterval = 25 let snapThreshold = 3 @@ -28,17 +31,27 @@ class SliderHandler { self.display.toggleMute(fromVolumeSlider: true) } - // If the command is to adjust brightness, also instruct the display to set the contrast value, if necessary - if self.cmd == .brightness { - self.display.setContrastValueForBrightness(value) - } - - // If the command is to adjust contrast, erase the previous value for the contrast to restore after brightness is increased - if self.cmd == .contrast { - self.display.setRestoreValue(nil, for: .contrast) + if !self.display.isSw() { + if self.cmd == DDC.Command.brightness, prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) { + var brightnessDDCValue: Int = 0 + var brightnessSwValue: Int = 100 + if value >= Int(slider.maxValue / 2) { + brightnessDDCValue = slider.integerValue - Int(slider.maxValue / 2) + brightnessSwValue = Int(self.display.getSwMaxBrightness()) + } else { + brightnessDDCValue = 0 + brightnessSwValue = Int((Float(value) / Float(slider.maxValue / 2)) * Float(self.display.getSwMaxBrightness())) + } + _ = self.display.writeDDCValues(command: self.cmd, value: UInt16(brightnessDDCValue)) + _ = self.display.setSwBrightness(value: UInt8(brightnessSwValue)) + self.display.saveValue(brightnessDDCValue, for: self.cmd) + } else { + _ = self.display.writeDDCValues(command: self.cmd, value: UInt16(value)) + self.display.saveValue(value, for: self.cmd) + } + } else if self.cmd == DDC.Command.brightness { + _ = self.display.setSwBrightness(value: UInt8(value)) + self.display.saveValue(value, for: self.cmd) } - - _ = self.display.ddc?.write(command: self.cmd, value: UInt16(value)) - self.display.saveValue(value, for: self.cmd) } } diff --git a/MonitorControl/UI/de.lproj/Main.strings b/MonitorControl/UI/de.lproj/Main.strings index 9351f179..09f5e254 100644 --- a/MonitorControl/UI/de.lproj/Main.strings +++ b/MonitorControl/UI/de.lproj/Main.strings @@ -1,83 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Helligkeit/Lautstärke für alle Monitore ändern"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Einstellungen zurücksetzen"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Aktiv"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Name"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Eigene"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Anzeigename"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Minimal"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "Kontrast nach Helligkeit verringern"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "Aus"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Warnung ⚠️\nDas Ändern dieser Einstellungen kann zum Einfrieren des Systems oder unerwartetem Verhalten führen."; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Verzögerung"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Abfragemodus"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "Helligkeit"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "MonitorControl beim login starten"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "Mehr Informationen"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Hersteller"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; + +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "ohne OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "Lautstärke"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Modell"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Normal"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Anzeigename"; - -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Hören auf"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Stark"; @@ -85,32 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Helligkeit & Lautstärke"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "Slider für Kontrast anzeigen"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Anzahl Abfragen"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/en.lproj/Main.strings b/MonitorControl/UI/en.lproj/Main.strings index 2fa20f31..3bd0d234 100644 --- a/MonitorControl/UI/en.lproj/Main.strings +++ b/MonitorControl/UI/en.lproj/Main.strings @@ -1,83 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Change Brightness/Volume for all screens"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Reset Preferences"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Enabled"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Name"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Custom"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; + +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Display Name"; +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Minimal"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ -"fhy-Er-0aI.title" = "Lower contrast after brightness"; +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ +"fhy-Er-0aI.title" = "Further lower brightness via software dimming"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "None"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Longer Delay"; +/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ +"hjz-0c-rvK.title" = "Brightness only"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Polling Mode"; +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = "Text Cell"; +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ +"j72-NF-zsW.title" = "Start at Login"; -/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ -"hjz-0c-rvK.title" = "Brightness only"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ -"j72-NF-zsW.title" = "Start MonitorControl at login"; +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "More Info"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Vendor"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "Hide OSD"; +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; + +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "Volume only"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Model"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; + +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Normal"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = "Text Cell"; - -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Display Name"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@JoniVR\n@waydabber"; -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Listen for"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Heavy"; @@ -85,32 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Both Brightness & Volume"; -/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ -"X96-ny-lAP.title" = "None"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ -"xSI-8W-Xd0.title" = "Show a slider for contrast"; +/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ +"X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Polling Count"; +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ +"xSI-8W-Xd0.title" = "Show contrast slider in menu"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/fr.lproj/Main.strings b/MonitorControl/UI/fr.lproj/Main.strings index 08cedf4d..6efe3161 100644 --- a/MonitorControl/UI/fr.lproj/Main.strings +++ b/MonitorControl/UI/fr.lproj/Main.strings @@ -1,83 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Modifier Luminosité/Volume pour tous les écrans"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Reset Preferences"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Activé"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Nom de l'écran"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Custom"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "Identifiant"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Display Name"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Minimal"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "Diminuer le contraste après la luminosité"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "None"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Longer Delay"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Polling Mode"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "Luminosité uniquement"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "Lancer MonitorControl au démarrage"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "More Info"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Vendeur"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; + +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "Hide OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "Volume uniquement"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Model"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Normal"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Nom d'affichage"; - -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Écouter pour"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Heavy"; @@ -85,32 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Luminosité & Volume"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "Afficher un slide pour le contraste"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Polling Count"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/hu.lproj/Main.strings b/MonitorControl/UI/hu.lproj/Main.strings new file mode 100644 index 00000000..c3ba51a9 --- /dev/null +++ b/MonitorControl/UI/hu.lproj/Main.strings @@ -0,0 +1,143 @@ +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; + +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Köszönjük mindenkinek, aki hozzájárult!"; + +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Menü ikon elrejtése"; + +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "MacOS hangerő OSD tiltása"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Visszaállítás"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "DDC némítás parancs engedélyezése"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Billentyűzet:"; + +/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ +"Cle-DD-vR7.title" = "Egyedi"; + +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Weboldal"; + +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Figyelem! Ezen beállítások változtatása veszélyeztetheti a rendszer stabilitását!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Hangerő csúszka megjelenítése a menüben"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Fényerő/hangerő módosítása az összes képernyőn"; + +/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ +"Eq3-z9-yIo.title" = "Minimális"; + +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Alaphelyzet"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ +"fhy-Er-0aI.title" = "Fényerő tovább csökkentése szoftveres sötétítéssel"; + +/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ +"FoA-yh-Yx3.title" = "Nincs"; + +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Fényerő billentyűk:"; + +/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ +"hjz-0c-rvK.title" = "Csak a fényerő billentyűk"; + +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "Ezek a lehetőségek hardveresen (DDC) vezérelhető kijelzőkkel működnek."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ +"j72-NF-zsW.title" = "Automatikus indítás bejelentkezéskor"; + +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Olvasási próbálkozások:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "A képernyő fényerejét és hangerejét az Apple Billentyűzet fényerő és hangerő gombjaival lehet szabályozni."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Átállás szoftveres sötétítésre, ha szükséges"; + +/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ +"kqn-gU-mZX.ibShadowedToolTip" = "További információ"; + +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Kijelző típusa:"; + +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menü tartalom:"; + +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "Szoftveres sötétítés használata, ha egy külső kijelzőt nem lehet vezérelni. Csak a fényerő szabályozás elérhető ilyen kijelzőknél."; + +/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ +"NLP-dU-Dam.title" = "Csak a hangerő billentyűk"; + +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Alkalmazás:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Vezérlés:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Hosszabb várakozás DDC olvasáskor"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "Ha rejtett, indítsa el újra az alkalmazást a beállítások megnyitásához!"; + +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Haladó:"; + +/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ +"Riq-uM-bTs.title" = "Normál"; + +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@JoniVR\n@waydabber"; + +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Vezérlés billentyűzetről"; + +/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ +"vik-vN-bJe.title" = "Magas"; + +/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ +"Vr4-xb-B4o.title" = "Fényerő és hangerő billentyűk"; + +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC olvasás mód:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Haladó beállítások a Kijelzők alatt"; + +/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ +"X96-ny-lAP.title" = "Nincs"; + +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ +"xSI-8W-Xd0.title" = "Kontraszt csúszka megjelenítése a menüben"; + +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Alaphelyzetbe állítás"; + +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; + +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "A fényerő szoftveres csökkentése, ha a kijelző elérte a nulla fényerőt. A menü csúszkát is befolyásolja, 50% a váltóhatár. Csak hardveresen (DDC) vezérelhető kijelzőkkel működik."; + +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Azonosító:"; + +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Hardveres DDC vezérlés"; + +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Adakozás"; diff --git a/MonitorControl/UI/hu.lproj/MainMenu.strings b/MonitorControl/UI/hu.lproj/MainMenu.strings new file mode 100644 index 00000000..2689fbcd --- /dev/null +++ b/MonitorControl/UI/hu.lproj/MainMenu.strings @@ -0,0 +1,5 @@ +/* Class = "NSMenuItem"; title = "Quit"; ObjectID = "JTa-2I-AsI"; */ +"JTa-2I-AsI.title" = "Kilépés"; + +/* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "SOS-eZ-uU5"; */ +"SOS-eZ-uU5.title" = "Beállítások..."; diff --git a/MonitorControl/UI/it.lproj/Main.strings b/MonitorControl/UI/it.lproj/Main.strings index 941a03be..80725f12 100644 --- a/MonitorControl/UI/it.lproj/Main.strings +++ b/MonitorControl/UI/it.lproj/Main.strings @@ -1,83 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Modifica Luminosità/Volume per tutti i monitor"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Reset Preferences"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Abilitato"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Nome"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Custom"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Display Name"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Minimal"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "Abbassa il contrasto dopo la luminosità"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "None"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Longer Delay"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Polling Mode"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "Solo Luminosità"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "Avvia MonitorControl al login"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "More Info"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Produttore"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; + +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "Hide OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "Solo Volume"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Modello"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Normal"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Nome assegnato"; - -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Gestisci"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Heavy"; @@ -85,32 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Luminosità e Volume"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "Mostra un selettore per il Contrasto"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Polling Count"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/ja.lproj/Main.strings b/MonitorControl/UI/ja.lproj/Main.strings index 24cab95b..d8584229 100644 --- a/MonitorControl/UI/ja.lproj/Main.strings +++ b/MonitorControl/UI/ja.lproj/Main.strings @@ -1,116 +1,143 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "すべての画面の画面輝度と音量を変更する"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = "Text Cell"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "初期設定に戻す"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "有効"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = "Text Cell"; +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = "Text Cell"; +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "名称"; +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "カスタム"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "ディスプレイの名称"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "低頻度"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "画面輝度変更後、コントラストを下げる"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "設定しない"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "⚠️ 注意 ⚠️\n下の設定を変更するとMacがフリーズしたり予期せぬ挙動になる場合があります。"; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "遅延を長くする"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "ポーリングモード"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "画面輝度のみ"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "ログイン時にMonitorCoontrolを起動する"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "More Info"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "ベンダー"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = "バージョン 0.0.0 (ビルド 0)"; +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "OSDを隠す"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "音量のみ"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "モデル"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "普通"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "表示名 (クリックして変更)"; - -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "操作対象:"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "高頻度"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = "Text Cell"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = "Text Cell"; - /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "画面輝度と音量"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "コントラスト変更用のスライダーをメニューに表示する"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "ポーリングカウント"; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; + +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; + +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; + +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; + +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; + +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/pl.lproj/Main.strings b/MonitorControl/UI/pl.lproj/Main.strings index 2a895e1d..0ddfbd8a 100644 --- a/MonitorControl/UI/pl.lproj/Main.strings +++ b/MonitorControl/UI/pl.lproj/Main.strings @@ -1,80 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Zmiana jasności/głośności dla wszystkich ekranów"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Resetowanie ustawień"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Aktywne"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = "Text Cell"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Nazwa"; +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Niestandardowy"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; + +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Nazwa wyświetlacza"; +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Minimalny"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "Obniż kontrast po jasności."; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "Nikt"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Uwaga ⚠️\nZmiana niektórych z tych ustawień może spowodować zawieszenia systemu lub nieoczekiwane zachowanie."; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Dłuższe opóźnienie"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Tryb odpytywania"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "Tylko jasność"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "Uruchamiaj MonitorContol podczas logowania"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "Więcej informacji"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Producent"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = "Wersja 0.0.0 (Kompilacja 0)"; +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "Schowaj OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "Tylko głośność"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Model"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; + +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Normalny"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Przyjazna nazwa"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Reaguj na"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Ciężki"; @@ -82,35 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Jasność i Głośność"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "Nic"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "Pokaż suwak dla kontrastu"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Licznik odpytań"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/ru.lproj/Main.strings b/MonitorControl/UI/ru.lproj/Main.strings index a6cd5b3d..4e3b82ac 100644 --- a/MonitorControl/UI/ru.lproj/Main.strings +++ b/MonitorControl/UI/ru.lproj/Main.strings @@ -1,77 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Изменять Яркость/Громкость на всех мониторах"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Сброс настроек"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Включено"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Имя"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Другое"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Название монитора"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Редко"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "Уменьшать контрастность после яркости"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "Нет"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Внимание ⚠️\nИзменение некоторых из этих настроек может привести к зависанию системы или неожиданному поведению."; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Длительный опрос"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Режим опроса"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "Только яркость"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "Запускать MonitorControl при входе в систему"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "Больше информации"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Производитель"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = "Версия 0.0.0 (Сборка 0)"; +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "Скрыть OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "Только громкость"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Модель"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; + +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Нормально"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Название монтора"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Изменять клавишами"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Часто"; @@ -79,38 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Яркость и громкость вместе"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "Показать ползунок для контрастности"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Количество опросов"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/uk.lproj/Main.strings b/MonitorControl/UI/uk.lproj/Main.strings index 4dacae72..4c71b072 100644 --- a/MonitorControl/UI/uk.lproj/Main.strings +++ b/MonitorControl/UI/uk.lproj/Main.strings @@ -1,77 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "Змінювати Яскравість та Гучність для усіх дісплеїв"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "Відновлення налаштувань"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "Актив."; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "Назва"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "Власне"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "Назва дісплею"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "Мінім."; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "Зменшувати Контраст після Яскравості"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "Немає"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "Увага! ⚠️\nЗміна деяких із цих налаштувань може привести до зависання системи або неочікуванних наслідків."; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "Затримка"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "Режим полінгу"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "лише Яскравість"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "Запускати MonitorControl разом із системою"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "Детальніше"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "Виробник"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = "Версія 0.0.0 (Білд 0)"; +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "Без OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "лише Гучність"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "Модель"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; + +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Звич."; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "Назва дісплею"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "Реагувати на"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "Част."; @@ -79,38 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "Яскравість та Гучність "; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "Показувати слайдер для контрасту"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "Опитувань/с"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/UI/zh-Hans.lproj/Main.strings b/MonitorControl/UI/zh-Hans.lproj/Main.strings index cd35f25b..2f359678 100644 --- a/MonitorControl/UI/zh-Hans.lproj/Main.strings +++ b/MonitorControl/UI/zh-Hans.lproj/Main.strings @@ -1,83 +1,110 @@ -/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */ -"0Z7-PQ-Bl8.title" = "将亮度/音量调节应用于所有显示器"; +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; -/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */ -"4Pj-3t-PJr.title" = "重置偏好设置"; +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Special thanks to our contributors!"; -/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */ -"8U8-ec-Zbv.headerCell.title" = "启用"; +/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */ +"aXL-i8-S6R.title" = "Hide Menu Icon"; -/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */ -"CHc-s5-4MN.headerCell.title" = "名字"; +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Disable macOS volume OSD"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Reset settings"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Enable Mute DDC command"; + +/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */ +"c7N-cO-759.title" = "Keyboard:"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "自定义"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */ -"dgp-q7-cBK.headerCell.title" = "ID"; +/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */ +"Cln-uW-2dd.title" = "Website"; -/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */ -"dNl-I0-hcg.headerCell.title" = "显示器名字"; +/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */ +"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */ +"dhP-eB-1L6.title" = "Show volume slider in menu"; + +/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */ +"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens"; /* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ "Eq3-z9-yIo.title" = "少量"; -/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */ +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Reset Name"; + +/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */ "fhy-Er-0aI.title" = "对比度与亮度同时降低"; /* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ "FoA-yh-Yx3.title" = "不请求"; -/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */ -"frw-j2-tE1.title" = "警告 ⚠️\n更改这些设置可能会导致系统冻结或者其它的意外情况。"; - -/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */ -"grO-Kr-l4d.headerCell.title" = "增加延时"; - -/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */ -"gxn-NH-Qhb.headerCell.title" = "请求模式"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */ -"H4a-c9-LcB.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */ +"hdd-Zz-buN.title" = "Brightness control:"; /* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */ "hjz-0c-rvK.title" = "仅亮度"; -/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */ +/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */ +"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only."; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ "j72-NF-zsW.title" = "登录时启动 MonitorControl"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */ -"JKW-oY-bSb.headerCell.title" = "ID"; +/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */ +"J77-r0-djA.title" = "Custom read polling count:"; + +/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */ +"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume."; + +/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */ +"kMa-3q-udl.title" = "Enable software dimming if required"; /* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */ "kqn-gU-mZX.ibShadowedToolTip" = "了解更多"; -/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */ -"LRJ-fb-Z9E.headerCell.title" = "制造商"; +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Display type:"; + +/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */ +"MJx-MK-e7D.title" = "Menu contents:"; -/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */ -"MPF-Mr-zVU.headerCell.title" = "隐藏 OSD"; +/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */ +"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead."; /* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */ "NLP-dU-Dam.title" = "仅音量"; -/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */ -"Nvp-hI-w4x.headerCell.title" = "型号"; +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Application:"; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Control method:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Longer delay during DDC read operations"; + +/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */ +"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */ -"PZ9-0Z-K6J.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */ +"r7i-oG-Ab6.title" = "Advanced:"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "正常"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */ -"UBV-gO-AZz.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber"; -/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */ -"uoI-1J-RdD.headerCell.title" = "自定义名"; - -/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */ -"Vh8-06-U3K.title" = "通过快捷键调整"; +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Enable keyboard control for display"; /* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ "vik-vN-bJe.title" = "多次"; @@ -85,32 +112,32 @@ /* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */ "Vr4-xb-B4o.title" = "亮度和音量"; +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "DDC read polling mode:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */ +"Wnd-hx-Meb.title" = "Show advanced settings under Displays"; + /* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */ "X96-ny-lAP.title" = "None"; -/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */ -"xFw-if-3FU.headerCell.title" = "DDC"; - -/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */ +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */ "xSI-8W-Xd0.title" = "显示对比度滑动条"; -/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */ -"ytT-up-Dhs.headerCell.title" = "查询次数"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */ -"2gr-xG-Byx.title" = ""; +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */ +"xY6-aw-o9u.title" = "Reset Preferences"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */ -"afl-95-ZJl.title" = ""; +/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */ +"Xz0-X0-rB4.title" = "Additional settings:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */ -"as0-t3-Aub.title" = ""; +/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */ +"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; -/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */ -"mBs-6m-13Q.title" = ""; +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Identifier:"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */ -"vkG-RF-Yne.title" = ""; +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Use hardware DDC control"; -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */ -"VPD-MR-IXg.title" = ""; +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Donate"; diff --git a/MonitorControl/View Controllers/AboutPrefsViewController.swift b/MonitorControl/View Controllers/AboutPrefsViewController.swift new file mode 100644 index 00000000..3efc985c --- /dev/null +++ b/MonitorControl/View Controllers/AboutPrefsViewController.swift @@ -0,0 +1,71 @@ +import Cocoa +import Preferences +import ServiceManagement + +class AboutPrefsViewController: NSViewController, PreferencePane { + let preferencePaneIdentifier = Preferences.PaneIdentifier.about + let preferencePaneTitle: String = NSLocalizedString("About", comment: "Shown in the main prefs window") + + var toolbarItemIcon: NSImage { + if #available(macOS 11.0, *) { + return NSImage(systemSymbolName: "info.circle", accessibilityDescription: "About")! + } else { + // Fallback on earlier versions + return NSImage(named: NSImage.infoName)! + } + } + + @IBOutlet var versionLabel: NSTextField! + @IBOutlet var copyrightLabel: NSTextField! + @IBOutlet var openContributorsButton: NSButton! + + override func viewDidLoad() { + super.viewDidLoad() + self.setAppInfo() + self.setCopyrightInfo() + } + + @available(macOS, deprecated: 10.10) + override func viewWillAppear() { + super.viewWillAppear() + } + + @IBAction func openDonate(_: NSButton) { + if let url = URL(string: "https://opencollective.com/monitorcontrol/donate") { + NSWorkspace.shared.open(url) + } + } + + @IBAction func openWebPage(_: NSButton) { + if let url = URL(string: "https://monitorcontrol.app") { + NSWorkspace.shared.open(url) + } + } + + @IBAction func openContributorsPage(_: NSButton) { + if let url = URL(string: "https://github.com/MonitorControl/MonitorControl/graphs/contributors") { + NSWorkspace.shared.open(url) + } + } + + func setAppInfo() { + let versionName = NSLocalizedString("Version", comment: "Version") + let buildName = NSLocalizedString("Build", comment: "Build") + let versionNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "error" + let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "error" + + #if arch(arm64) + let arch: String = NSLocalizedString("Apple Silicon", comment: "Apple Silicon designation (shown after the version number in Preferences)") + #else + let arch: String = NSLocalizedString("Intel", comment: "Intel designation (shown after the version number in Preferences)") + #endif + + self.versionLabel.stringValue = "\(versionName) \(versionNumber) \(buildName) \(buildNumber) - \(arch)" + } + + func setCopyrightInfo() { + let copyright = NSLocalizedString("Copyright Ⓒ MonitorControl, ", comment: "Version") + let year = Calendar.current.component(.year, from: Date()) + self.copyrightLabel.stringValue = "\(copyright) \(year)" + } +} diff --git a/MonitorControl/View Controllers/AdvancedPrefsViewController.swift b/MonitorControl/View Controllers/AdvancedPrefsViewController.swift deleted file mode 100644 index d7f07e51..00000000 --- a/MonitorControl/View Controllers/AdvancedPrefsViewController.swift +++ /dev/null @@ -1,139 +0,0 @@ -import Cocoa -import DDC -import os.log -import Preferences - -class AdvancedPrefsViewController: NSViewController, PreferencePane, NSTableViewDataSource, NSTableViewDelegate { - var preferencePaneIdentifier = Preferences.PaneIdentifier.advanced - var preferencePaneTitle: String = NSLocalizedString("Advanced", comment: "Shown in the main prefs window") - - var toolbarItemIcon: NSImage { - if #available(macOS 11.0, *) { - return NSImage(systemSymbolName: "gearshape", accessibilityDescription: "Advanced")! - } else { - // Fallback on earlier versions - return NSImage(named: NSImage.advancedName)! - } - } - - let prefs = UserDefaults.standard - - var displays: [ExternalDisplay] = [] - - 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() - 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() { - self.displays = DisplayManager.shared.getDdcCapableDisplays() - 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: ExternalDisplay) -> String { - switch column { - case .friendlyName: - return display.getFriendlyName() - case .identifier: - return "\(display.identifier)" - default: - return "" - } - } -} diff --git a/MonitorControl/View Controllers/DisplayPrefsViewController.swift b/MonitorControl/View Controllers/DisplayPrefsViewController.swift deleted file mode 100644 index 4088cd7c..00000000 --- a/MonitorControl/View Controllers/DisplayPrefsViewController.swift +++ /dev/null @@ -1,132 +0,0 @@ -import Cocoa -import DDC -import os.log -import Preferences - -class DisplayPrefsViewController: NSViewController, PreferencePane, NSTableViewDataSource, NSTableViewDelegate { - var preferencePaneIdentifier = Preferences.PaneIdentifier.display - var preferencePaneTitle: String = NSLocalizedString("Display", comment: "Shown in the main prefs window") - - var toolbarItemIcon: NSImage { - if #available(macOS 11.0, *) { - return NSImage(systemSymbolName: "display", accessibilityDescription: "Display")! - } else { - // Fallback on earlier versions - return NSImage(named: NSImage.computerName)! - } - } - - let prefs = UserDefaults.standard - - var displays: [Display] = [] - - enum DisplayColumn: Int { - case checkbox - case ddc - case name - case friendlyName - case identifier - case vendor - case model - } - - @IBOutlet var allScreens: NSButton! - @IBOutlet var displayList: NSTableView! - - override func viewDidLoad() { - super.viewDidLoad() - 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: - self.prefs.set(true, forKey: Utils.PrefKeys.allScreens.rawValue) - case .off: - self.prefs.set(false, forKey: Utils.PrefKeys.allScreens.rawValue) - default: break - } - - #if DEBUG - os_log("Toggle allScreens state: %{public}@", type: .info, sender.state == .on ? "on" : "off") - #endif - } - - // MARK: - Table datasource - - @objc func loadDisplayList() { - self.displays = DisplayManager.shared.getAllDisplays() - self.displayList.reloadData() - } - - func numberOfRows(in _: NSTableView) -> Int { - return self.displays.count - } - - // MARK: - Table delegate - - 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] - - switch column { - case .checkbox: - if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? ButtonCellView { - cell.display = display - cell.button.state = display.isEnabled ? .on : .off - return cell - } - case .ddc: - if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? ButtonCellView { - cell.display = display - cell.button.state = DDC(for: display.identifier) != nil ? .on : .off - cell.button.isEnabled = false - return cell - } - case .friendlyName: - if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? FriendlyNameCellView { - cell.display = display - cell.textField?.stringValue = display.getFriendlyName() - cell.textField?.isEditable = true - 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 .name: - return display.name - case .identifier: - return "\(display.identifier)" - case .vendor: - return display.identifier.vendorNumber.map { String(format: "0x%02X", $0) } ?? NSLocalizedString("Unknown", comment: "Unknown vendor") - case .model: - return display.identifier.modelNumber.map { String(format: "0x%02X", $0) } ?? NSLocalizedString("Unknown", comment: "Unknown model") - default: - return "" - } - } -} diff --git a/MonitorControl/View Controllers/DisplaysPrefsCellView.swift b/MonitorControl/View Controllers/DisplaysPrefsCellView.swift new file mode 100644 index 00000000..af8c10c1 --- /dev/null +++ b/MonitorControl/View Controllers/DisplaysPrefsCellView.swift @@ -0,0 +1,208 @@ +import Cocoa +import os.log + +class DisplaysPrefsCellView: NSTableCellView { + var display: Display? + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + } + + @IBOutlet var displayImage: NSImageCell! + @IBOutlet var friendlyName: NSTextFieldCell! + @IBOutlet var displayId: NSTextFieldCell! + @IBOutlet var enabledButton: NSButton! + @IBOutlet var ddcButton: NSButton! + @IBOutlet var controlMethod: NSTextFieldCell! + @IBOutlet var displayType: NSTextFieldCell! + @IBOutlet var disableVolumeOSDButton: NSButton! + + @IBOutlet var advancedSettings: NSBox! + + @IBOutlet var pollingModeMenu: NSPopUpButton! + @IBOutlet var longerDelayButton: NSButton! + @IBOutlet var pollingCount: NSTextFieldCell! + @IBOutlet var enableMuteButton: NSButton! + + @IBAction func openAdvancedHelp(_: NSButton) { + if let url = URL(string: "https://github.com/the0neyouseek/MonitorControl/wiki/Advanced-Preferences") { + NSWorkspace.shared.open(url) + } + } + + @IBAction func pollingModeValueChanged(_ sender: NSPopUpButton) { + if let display = display as? ExternalDisplay { + let newValue = sender.selectedTag() + let originalValue = display.getPollingMode() + + if newValue != originalValue { + display.setPollingMode(newValue) + if display.getPollingMode() == 4 { + self.pollingCount.isEnabled = true + } else { + self.pollingCount.isEnabled = false + } + self.pollingCount.stringValue = String(display.getPollingCount()) + os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`") + } + } + } + + @IBAction func pollingCountValueChanged(_ sender: NSTextFieldCell) { + if let display = display as? ExternalDisplay { + let newValue = sender.stringValue + let originalValue = "\(display.getPollingCount())" + + if newValue.isEmpty { + self.pollingCount.stringValue = originalValue + } else if let intValue = Int(newValue) { + self.pollingCount.stringValue = String(intValue) + } else { + self.pollingCount.stringValue = "" + } + + 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)`") + } + } + } + + @IBAction func enableMuteButtonToggled(_ sender: NSButton) { + if let display = display as? ExternalDisplay { + switch sender.state { + case .on: + display.enableMuteUnmute = true + case .off: + // If the display is currently muted, toggle back to unmute + // to prevent the display becoming stuck in the muted state + if display.isMuted() { + display.toggleMute() + } + display.enableMuteUnmute = false + default: + break + } + } + } + + @IBAction func longerDelayButtonToggled(_ sender: NSButton) { + if let display = self.display as? ExternalDisplay { + switch sender.state { + case .on: + let alert = 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 + } + } + } + + @IBAction func enabledButtonToggled(_ sender: NSButton) { + if let disp = display { + let isEnabled = sender.state == .on + disp.isEnabled = isEnabled + #if DEBUG + os_log("Toggle enabled display state: %{public}@", type: .info, isEnabled ? "on" : "off") + #endif + } + } + + @IBAction func ddcButtonToggled(_ sender: NSButton) { + if let disp = display { + switch sender.state { + case .off: + disp.forceSw = true + case .on: + disp.forceSw = false + default: + break + } + _ = disp.resetSwBrightness() + app.updateMenus() + let displayInfo = DisplaysPrefsViewController.getDisplayInfo(display: disp) + self.controlMethod.stringValue = displayInfo.controlMethod + } + } + + @IBAction func friendlyNameValueChanged(_ sender: NSTextFieldCell) { + if let disp = display { + let newValue = sender.stringValue + let originalValue = disp.getFriendlyName() + + if newValue.isEmpty { + self.friendlyName.stringValue = originalValue + return + } + + if newValue != originalValue, !newValue.isEmpty { + disp.setFriendlyName(newValue) + NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.friendlyName.rawValue), object: nil) + #if DEBUG + os_log("Value changed for friendly name: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`") + #endif + } + } + } + + @IBAction func disableVolumeOSDButton(_ sender: NSButton) { + if let disp = display as? ExternalDisplay { + switch sender.state { + case .on: + disp.hideOsd = true + case .off: + disp.hideOsd = false + default: + break + } + } + } + + @IBAction func resetSettings(_: NSButton) { + if let disp = display { + if self.ddcButton.isEnabled { + self.ddcButton.state = .on + self.ddcButtonToggled(self.ddcButton) + } + if self.enabledButton.isEnabled { + self.enabledButton.state = .on + self.enabledButtonToggled(self.enabledButton) + } + if self.disableVolumeOSDButton.isEnabled { + self.disableVolumeOSDButton.state = .off + self.disableVolumeOSDButton(self.disableVolumeOSDButton) + } + if self.pollingModeMenu.isEnabled { + self.pollingModeMenu.selectItem(withTag: 2) + self.pollingModeValueChanged(self.pollingModeMenu) + } + if self.longerDelayButton.isEnabled { + self.longerDelayButton.state = .off + self.longerDelayButtonToggled(self.longerDelayButton) + } + if self.enableMuteButton.isEnabled { + self.enableMuteButton.state = .off + self.enableMuteButtonToggled(self.enableMuteButton) + } + self.friendlyName.stringValue = disp.name + self.friendlyNameValueChanged(self.friendlyName) + } + } +} diff --git a/MonitorControl/View Controllers/DisplaysPrefsViewController.swift b/MonitorControl/View Controllers/DisplaysPrefsViewController.swift new file mode 100644 index 00000000..3a54b54f --- /dev/null +++ b/MonitorControl/View Controllers/DisplaysPrefsViewController.swift @@ -0,0 +1,185 @@ +import Cocoa +import os.log +import Preferences + +class DisplaysPrefsViewController: NSViewController, PreferencePane, NSTableViewDataSource, NSTableViewDelegate { + let preferencePaneIdentifier = Preferences.PaneIdentifier.displays + let preferencePaneTitle: String = NSLocalizedString("Displays", comment: "Shown in the main prefs window") + + var toolbarItemIcon: NSImage { + if #available(macOS 11.0, *) { + return NSImage(systemSymbolName: "display.2", accessibilityDescription: "Displays")! + } else { + // Fallback on earlier versions + return NSImage(named: NSImage.computerName)! + } + } + + let prefs = UserDefaults.standard + var displays: [Display] = [] + + @IBOutlet var displayList: NSTableView! + + override func viewDidLoad() { + super.viewDidLoad() + } + + override func viewWillAppear() { + super.viewWillAppear() + self.loadDisplayList() + NotificationCenter.default.addObserver(self, selector: #selector(self.loadDisplayList), name: .displayListUpdate, object: nil) + } + + @objc func loadDisplayList() { + os_log("Reloading Displays preferences display list", type: .info) + self.displays = DisplayManager.shared.getAllDisplays() + self.displayList.reloadData() + self.updateDisplayListRowHeight() + } + + func numberOfRows(in _: NSTableView) -> Int { + return self.displays.count + } + + public static func isImac() -> Bool { + let platformExpertDevice = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")) + if let modelData = IORegistryEntryCreateCFProperty(platformExpertDevice, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data, let modelIdentifierCString = String(data: modelData, encoding: .utf8)?.cString(using: .utf8) { + let modelIdentifier = String(cString: modelIdentifierCString) + return modelIdentifier.contains("iMac") + } + return false + } + + public struct DisplayInfo { + var displayType = "" + var displayImage = "" + var controlMethod = "" + } + + public static func getDisplayInfo(display: Display) -> DisplayInfo { + var displayType = "" + var displayImage = "" + var controlMethod = "" + if display.isVirtual { + displayType = NSLocalizedString("Virtual Display", comment: "Shown in the Display Preferences") + displayImage = "tv.and.mediabox" + controlMethod = NSLocalizedString("No Control Available", comment: "Shown in the Display Preferences") + } else if display is ExternalDisplay { + displayType = NSLocalizedString("External Display", comment: "Shown in the Display Preferences") + displayImage = "display" + if let externalDisplay: ExternalDisplay = display as? ExternalDisplay { + if externalDisplay.isSwOnly() { + controlMethod = NSLocalizedString("Software Only", comment: "Shown in the Display Preferences") + displayImage = "display.trianglebadge.exclamationmark" + } else { + if externalDisplay.isSw() { + controlMethod = NSLocalizedString("Software (Forced)", comment: "Shown in the Display Preferences") + } else { + controlMethod = NSLocalizedString("Hardware (DDC)", comment: "Shown in the Display Preferences") + } + } + } else { + controlMethod = NSLocalizedString("Unspecified", comment: "Shown in the Display Preferences") + } + } else if display is InternalDisplay { + displayType = NSLocalizedString("Built-in Display", comment: "Shown in the Display Preferences") + if self.isImac() { + displayImage = "desktopcomputer" + } else { + displayImage = "laptopcomputer" + } + controlMethod = NSLocalizedString("Hardware (CoreDisplay)", comment: "Shown in the Display Preferences") + } else { + displayType = NSLocalizedString("Other Display", comment: "Shown in the Display Preferences") + displayImage = "display.trianglebadge.exclamationmark" + controlMethod = NSLocalizedString("No Control Available", comment: "Shown in the Display Preferences") + } + return DisplayInfo(displayType: displayType, displayImage: displayImage, controlMethod: controlMethod) + } + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + guard let tableColumn = tableColumn else { + return nil + } + os_log("Populating Displays Table") + let display = self.displays[row] + if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? DisplaysPrefsCellView { + cell.display = display + + // ID + cell.displayId.stringValue = String(display.identifier) + // Firendly name + cell.friendlyName.stringValue = display.getFriendlyName() + cell.friendlyName.isEditable = true + // Enabled + cell.enabledButton.state = display.isEnabled && !display.isVirtual ? .on : .off + cell.enabledButton.isEnabled = !display.isVirtual + // DDC + cell.ddcButton.state = ((display as? ExternalDisplay)?.isSw() ?? true) || ((display as? ExternalDisplay)?.isVirtual ?? true) ? .off : .on + if ((display as? ExternalDisplay)?.isSwOnly() ?? true) || ((display as? ExternalDisplay)?.isVirtual ?? true) { + cell.ddcButton.isEnabled = false + } else { + cell.ddcButton.isEnabled = true + } + // Display type, image, control method + let displayInfo = DisplaysPrefsViewController.getDisplayInfo(display: display) + cell.displayType.stringValue = displayInfo.displayType + cell.controlMethod.stringValue = displayInfo.controlMethod + if #available(macOS 11.0, *) { + cell.displayImage.image = NSImage(systemSymbolName: displayInfo.displayImage, accessibilityDescription: display.name)! + } else { + cell.displayImage.image = NSImage(named: NSImage.computerName)! + } + // Disable Volume OSD + if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isVirtual { + cell.disableVolumeOSDButton.state = externalDisplay.hideOsd ? .on : .off + cell.disableVolumeOSDButton.isEnabled = true + } else { + cell.disableVolumeOSDButton.state = .off + cell.disableVolumeOSDButton.isEnabled = false + } + // Advanced settings + if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isSwOnly(), !externalDisplay.isVirtual { + // DDC read polling mode + cell.pollingModeMenu.isEnabled = true + cell.pollingModeMenu.selectItem(withTag: externalDisplay.getPollingMode()) + // Custom read polling count + if externalDisplay.getPollingMode() == 4 { + cell.pollingCount.isEnabled = true + } else { + cell.pollingCount.isEnabled = false + } + cell.pollingCount.stringValue = String(externalDisplay.getPollingCount()) + // DDC read delay + cell.longerDelayButton.isEnabled = true + cell.longerDelayButton.state = externalDisplay.needsLongerDelay ? .on : .off + cell.enableMuteButton.isEnabled = true + cell.enableMuteButton.state = externalDisplay.enableMuteUnmute ? .on : .off + } else { + cell.pollingModeMenu.selectItem(withTag: 0) + cell.pollingModeMenu.isEnabled = false + cell.pollingCount.stringValue = "" + cell.pollingCount.isEnabled = false + cell.longerDelayButton.state = .off + cell.longerDelayButton.isEnabled = false + cell.enableMuteButton.state = .off + cell.enableMuteButton.isEnabled = false + } + if self.prefs.bool(forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) { + cell.advancedSettings.isHidden = false + } else { + cell.advancedSettings.isHidden = true + } + return cell + } + return nil + } + + func updateDisplayListRowHeight() { + if self.prefs.bool(forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) { + self.displayList.rowHeight = 300 + } else { + self.displayList.rowHeight = 150 + } + } +} diff --git a/MonitorControl/View Controllers/KeysPrefsViewController.swift b/MonitorControl/View Controllers/KeysPrefsViewController.swift deleted file mode 100644 index 76664171..00000000 --- a/MonitorControl/View Controllers/KeysPrefsViewController.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Cocoa -import os.log -import Preferences - -class KeysPrefsViewController: NSViewController, PreferencePane { - var preferencePaneIdentifier = Preferences.PaneIdentifier.keys - var preferencePaneTitle: String = NSLocalizedString("Keys", comment: "Shown in the main prefs window") - - var toolbarItemIcon: NSImage { - if #available(macOS 11.0, *) { - return NSImage(systemSymbolName: "keyboard", accessibilityDescription: "Keys")! - } else { - // Fallback on earlier versions - return NSImage(named: "KeyboardPref")! - } - } - - let prefs = UserDefaults.standard - - @IBOutlet var listenFor: NSPopUpButton! - - override func viewWillAppear() { - super.viewWillAppear() - self.listenFor.selectItem(at: self.prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue)) - } - - @IBAction func listenForChanged(_ sender: NSPopUpButton) { - self.prefs.set(sender.selectedTag(), forKey: Utils.PrefKeys.listenFor.rawValue) - #if DEBUG - os_log("Toggle keys listened for state state: %{public}@", type: .info, sender.selectedItem?.title ?? "") - #endif - NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.listenFor.rawValue), object: nil) - } -} diff --git a/MonitorControl/View Controllers/MainPrefsViewController.swift b/MonitorControl/View Controllers/MainPrefsViewController.swift index f4e1ca34..d6e70264 100644 --- a/MonitorControl/View Controllers/MainPrefsViewController.swift +++ b/MonitorControl/View Controllers/MainPrefsViewController.swift @@ -18,23 +18,54 @@ class MainPrefsViewController: NSViewController, PreferencePane { let prefs = UserDefaults.standard - @IBOutlet var versionLabel: NSTextField! @IBOutlet var startAtLogin: NSButton! + @IBOutlet var hideMenuIcon: NSButton! @IBOutlet var showContrastSlider: NSButton! - @IBOutlet var lowerContrast: NSButton! + @IBOutlet var showVolumeSlider: NSButton! + @IBOutlet var lowerSwAfterBrightness: NSButton! + @IBOutlet var fallbackSw: NSButton! + @IBOutlet var listenFor: NSPopUpButton! + @IBOutlet var allScreens: NSButton! + @IBOutlet var showAdvancedDisplays: NSButton! override func viewDidLoad() { super.viewDidLoad() - self.setVersionNumber() } @available(macOS, deprecated: 10.10) override func viewWillAppear() { super.viewWillAppear() + self.populateSettings() + } + + @available(macOS, deprecated: 10.10) + func populateSettings() { + // This is marked as deprectated but according to the function header it still does not have a replacement as of macOS 12 Monterey and is valid to use. 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.hideMenuIcon.state = self.prefs.bool(forKey: Utils.PrefKeys.hideMenuIcon.rawValue) ? .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.showVolumeSlider.state = self.prefs.bool(forKey: Utils.PrefKeys.showVolume.rawValue) ? .on : .off + self.lowerSwAfterBrightness.state = self.prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) ? .on : .off + self.fallbackSw.state = self.prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) ? .on : .off + self.listenFor.selectItem(at: self.prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue)) + self.allScreens.state = self.prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? .on : .off + self.showAdvancedDisplays.state = self.prefs.bool(forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) ? .on : .off + } + + @IBAction func allScreensTouched(_ sender: NSButton) { + switch sender.state { + case .on: + self.prefs.set(true, forKey: Utils.PrefKeys.allScreens.rawValue) + case .off: + self.prefs.set(false, forKey: Utils.PrefKeys.allScreens.rawValue) + default: break + } + + #if DEBUG + os_log("Toggle allScreens state: %{public}@", type: .info, sender.state == .on ? "on" : "off") + #endif } @IBAction func startAtLoginClicked(_ sender: NSButton) { @@ -47,6 +78,18 @@ class MainPrefsViewController: NSViewController, PreferencePane { } } + @IBAction func hideMenuIconClicked(_ sender: NSButton) { + switch sender.state { + case .on: + self.prefs.set(true, forKey: Utils.PrefKeys.hideMenuIcon.rawValue) + app.statusItem.isVisible = false + case .off: + self.prefs.set(false, forKey: Utils.PrefKeys.hideMenuIcon.rawValue) + app.statusItem.isVisible = true + default: break + } + } + @IBAction func showContrastSliderClicked(_ sender: NSButton) { switch sender.state { case .on: @@ -55,33 +98,96 @@ class MainPrefsViewController: NSViewController, PreferencePane { self.prefs.set(false, forKey: Utils.PrefKeys.showContrast.rawValue) default: break } - + app.updateMenus() #if DEBUG os_log("Toggle show contrast slider state: %{public}@", type: .info, sender.state == .on ? "on" : "off") #endif + } - NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.showContrast.rawValue), object: nil) + @IBAction func showVolumeSliderClicked(_ sender: NSButton) { + switch sender.state { + case .on: + self.prefs.set(true, forKey: Utils.PrefKeys.showVolume.rawValue) + case .off: + self.prefs.set(false, forKey: Utils.PrefKeys.showVolume.rawValue) + default: break + } + app.updateMenus() + #if DEBUG + os_log("Toggle show volume slider state: %{public}@", type: .info, sender.state == .on ? "on" : "off") + #endif + } + + @IBAction func lowerSwAfterBrightnessClicked(_ sender: NSButton) { + switch sender.state { + case .on: + self.prefs.set(true, forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) + case .off: + self.prefs.set(false, forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) + DisplayManager.shared.resetSwBrightnessForAllDisplays() + default: break + } + app.updateMenus() + #if DEBUG + os_log("Toggle software control after brightness state: %{public}@", type: .info, sender.state == .on ? "on" : "off") + #endif + } + + @IBAction func fallbackSwClicked(_ sender: NSButton) { + switch sender.state { + case .on: + self.prefs.set(true, forKey: Utils.PrefKeys.fallbackSw.rawValue) + case .off: + self.prefs.set(false, forKey: Utils.PrefKeys.fallbackSw.rawValue) + default: break + } + DisplayManager.shared.resetSwBrightnessForAllDisplays() + app.updateMenus() + #if DEBUG + os_log("Toggle fallback to software if no DDC: %{public}@", type: .info, sender.state == .on ? "on" : "off") + #endif } - @IBAction func lowerContrastClicked(_ sender: NSButton) { + @IBAction func showAdvancedClicked(_ sender: NSButton) { switch sender.state { case .on: - self.prefs.set(true, forKey: Utils.PrefKeys.lowerContrast.rawValue) + self.prefs.set(true, forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) case .off: - self.prefs.set(false, forKey: Utils.PrefKeys.lowerContrast.rawValue) + self.prefs.set(false, forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) default: break } + NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil) + #if DEBUG + os_log("Show advanced settings in Display clicked: %{public}@", type: .info, sender.state == .on ? "on" : "off") + #endif + } + @IBAction func listenForChanged(_ sender: NSPopUpButton) { + self.prefs.set(sender.selectedTag(), forKey: Utils.PrefKeys.listenFor.rawValue) #if DEBUG - os_log("Toggle lower contrast after brightness state: %{public}@", type: .info, sender.state == .on ? "on" : "off") + os_log("Toggle keys listened for state state: %{public}@", type: .info, sender.selectedItem?.title ?? "") #endif + NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.listenFor.rawValue), object: nil) } - fileprivate func setVersionNumber() { - let versionName = NSLocalizedString("Version", comment: "Version") - let buildName = NSLocalizedString("Build", comment: "Build") - let versionNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "error" - let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "error" - self.versionLabel.stringValue = "\(versionName) \(versionNumber) (\(buildName) \(buildNumber))" + @available(macOS, deprecated: 10.10) + func resetSheetModalHander(modalResponse: NSApplication.ModalResponse) { + if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn { + NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.preferenceReset.rawValue), object: nil) + self.populateSettings() + } + } + + @available(macOS, deprecated: 10.10) + @IBAction func resetPrefsClicked(_: NSButton) { + let alert = 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 self.resetSheetModalHander(modalResponse: modalResponse) }) + } } } diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 597eb671..2e1a33b9 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 947 + 2866 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly diff --git a/OSD.framework/Headers/OSDManager.h b/OSD.framework/Headers/OSDManager.h deleted file mode 100644 index a067a8db..00000000 --- a/OSD.framework/Headers/OSDManager.h +++ /dev/null @@ -1,21 +0,0 @@ -#import "OSDUIHelperProtocol.h" - -@class NSXPCConnection; - -@interface OSDManager : NSObject -{ - id _proxyObject; - NSXPCConnection *connection; -} - -+ (id)sharedManager; -@property(retain) NSXPCConnection *connection; // @synthesize connection; -- (void)showFullScreenImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecToAnimate:(unsigned int)arg4; -- (void)fadeClassicImageOnDisplay:(unsigned int)arg1; -- (void)showImageAtPath:(id)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(id)arg5; -- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 filledChiclets:(unsigned int)arg5 totalChiclets:(unsigned int)arg6 locked:(BOOL)arg7; -- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(id)arg5; -- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4; -@property(readonly) id remoteObjectProxy; // @dynamic remoteObjectProxy; - -@end diff --git a/OSD.framework/Headers/OSDUIHelperProtocol.h b/OSD.framework/Headers/OSDUIHelperProtocol.h deleted file mode 100644 index a1246c01..00000000 --- a/OSD.framework/Headers/OSDUIHelperProtocol.h +++ /dev/null @@ -1,11 +0,0 @@ -@class NSString; - -@protocol OSDUIHelperProtocol -- (void)showFullScreenImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecToAnimate:(unsigned int)arg4; -- (void)fadeClassicImageOnDisplay:(unsigned int)arg1; -- (void)showImageAtPath:(NSString *)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(NSString *)arg5; -- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 filledChiclets:(unsigned int)arg5 totalChiclets:(unsigned int)arg6 locked:(BOOL)arg7; -- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(NSString *)arg5; -- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4; -@end - diff --git a/OSD.framework/OSD b/OSD.framework/OSD deleted file mode 120000 index ee6bfa0a..00000000 --- a/OSD.framework/OSD +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/OSD \ No newline at end of file diff --git a/OSD.framework/Resources b/OSD.framework/Resources deleted file mode 120000 index 953ee36f..00000000 --- a/OSD.framework/Resources +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Resources \ No newline at end of file diff --git a/OSD.framework/Versions/A/OSD b/OSD.framework/Versions/A/OSD deleted file mode 100755 index 58813ae0..00000000 Binary files a/OSD.framework/Versions/A/OSD and /dev/null differ diff --git a/OSD.framework/Versions/A/Resources/Info.plist b/OSD.framework/Versions/A/Resources/Info.plist deleted file mode 100644 index 824b8c0f..00000000 --- a/OSD.framework/Versions/A/Resources/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - BuildMachineOSBuild - 16B2657 - CFBundleDevelopmentRegion - en - CFBundleExecutable - OSD - CFBundleIdentifier - com.apple.OSD - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - OSD - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleSupportedPlatforms - - MacOSX - - CFBundleVersion - 1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 9L173x - DTPlatformVersion - GM - DTSDKBuild - 17A317 - DTSDKName - macosx10.13internal - DTXcode - 0900 - DTXcodeBuild - 9L173x - NSHumanReadableCopyright - Copyright © 2015 Apple Inc. All rights reserved. - - diff --git a/OSD.framework/Versions/A/Resources/version.plist b/OSD.framework/Versions/A/Resources/version.plist deleted file mode 100644 index a387863e..00000000 --- a/OSD.framework/Versions/A/Resources/version.plist +++ /dev/null @@ -1,18 +0,0 @@ - - - - - BuildAliasOf - OSDFramework - BuildVersion - 487 - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - ProjectName - OSDFramework - SourceVersion - 27000000000000 - - diff --git a/OSD.framework/Versions/A/_CodeSignature/CodeResources b/OSD.framework/Versions/A/_CodeSignature/CodeResources deleted file mode 100644 index cd4347dd..00000000 --- a/OSD.framework/Versions/A/_CodeSignature/CodeResources +++ /dev/null @@ -1,139 +0,0 @@ - - - - - files - - Resources/Info.plist - - bTy7OXKIr2tY7ToPw28ekz1xUXU= - - Resources/version.plist - - d0I/dBV8v16urCBanZt9RaZvG1E= - - - files2 - - Resources/Info.plist - - hash2 - - uEmRq0D23jBsIWK+0+UH3bCcn16eQdAwKWglrQbTfQc= - - - Resources/version.plist - - hash2 - - f4xR2tymy1G7xEyxX1+yXJmSgOrrndsypu67avrQ8Ss= - - - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/OSD.framework/Versions/Current b/OSD.framework/Versions/Current deleted file mode 120000 index 8c7e5a66..00000000 --- a/OSD.framework/Versions/Current +++ /dev/null @@ -1 +0,0 @@ -A \ No newline at end of file diff --git a/OSD.framework/XPCServices b/OSD.framework/XPCServices deleted file mode 120000 index 99c46ea2..00000000 --- a/OSD.framework/XPCServices +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/XPCServices \ No newline at end of file diff --git a/README.md b/README.md index 8abee4ac..62a59a4a 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,55 @@ -

MonitorControl

+App icon - -
-Control your external monitor brightness, contrast or volume directly from a menulet or with keyboard native keys. -
+

MonitorControl - Now with Apple Silicon support!

+ +

+Control your external display brightness and volume!
+Use menulet sliders or the native Apple keyboard keys!
+Shows native brightness and volume OSDs as well!
+


- - +
-

Translations: :uk: :fr: :de: :it: :ru: :ukraine: :jp: :poland:

-
- -
- -
- - - downloads - - - - latest version - - - - license - - - - platform - -
- + + +downloads + + + +latest version + + + +license + + + +platform + + + +backers + +
- -
- menulet screenshot -

- general screenshotkeys screenshot - display screenshot - advanced screenshot -
-_Bonus: Using keyboard keys displays the native osd_ - -osd screenshot
-## Download +Screenshot
-Go to [Release](https://github.com/MonitorControl/MonitorControl/releases/latest) and download the latest `.dmg` +
-## Installing with Homebrew Cask +## Download -You can also install MonitorControl with [Homebrew Cask](https://github.com/Homebrew/homebrew-cask). +Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and download the latest `.dmg` -```bash -$ brew install --cask monitorcontrol -``` +## Compatibility + +- macOS Mojave (`10.14`) and up _(note: you can download [version 2.1.0](https://github.com/MonitorControl/MonitorControl/releases/tag/v2.1.0) for macOS Sierra `10.12` support)_ +- Works with monitors controllable via [DDC](https://en.wikipedia.org/wiki/Display_Data_Channel) (or any other display via software dimming) ## How to help @@ -75,17 +64,19 @@ Open [issues](https://github.com/MonitorControl/MonitorControl/issues) if you ha - [SwiftFormat](https://github.com/nicklockwood/SwiftFormat) - [BartyCrouch](https://github.com/Flinesoft/BartyCrouch) (for updating localizations) -Clone the project +Clone the project via this Terminal command: -```sh +``` git clone https://github.com/MonitorControl/MonitorControl.git ``` -Then dependencies will automatically get downloaded when opening the project, if they don't: +If you want to clone one of the branches, add `--single-branch --branch [branchname]` after the `clone` option. + +You're all set ! Now open the `MonitorControl.xcodeproj` with Xcode! The dependencies will automatically get downloaded once you open the project. If they don't: -`File > Swift Packages > Resolve Package Versions` +`File > Packages > Resolve Package Versions` -You're all set ! Now open the `MonitorControl.xcodeproj` with Xcode +(In earlier XCode versions `Packages` menu is titled `Swift Packages`) ### Third party dependencies @@ -94,21 +85,21 @@ You're all set ! Now open the `MonitorControl.xcodeproj` with Xcode - [DDC.swift](https://github.com/reitermarkus/DDC.swift) - [SimplyCoreAudio](https://github.com/rnine/SimplyCoreAudio) -## Support - -- macOS Sierra (`10.12`) and up. -- Works with monitors controllable via [DDC](https://en.wikipedia.org/wiki/Display_Data_Channel). - ## Contributors - [@the0neyouseek](https://github.com/the0neyouseek) -- [@reitermarkus](https://github.com/reitermarkus) - [@JoniVR](https://github.com/JoniVR) +- [@waydabber](https://github.com/waydabber) ## Thanks -- [@bluejamesbond](https://github.com/bluejamesbond/) (Original developer) -- [@Tyilo](https://github.com/Tyilo/) (Fork) -- [@Bensge](https://github.com/Bensge/) - (Used some code from his project [NativeDisplayBrightness](https://github.com/Bensge/NativeDisplayBrightness)) -- [@nhurden](https://github.com/nhurden/) (For the original MediaKeyTap) -- [@kfix](https://github.com/kfix/ddcctl) (For ddcctl) +- [@bluejamesbond](https://github.com/bluejamesbond/) (original developer) +- [@Tyilo](https://github.com/Tyilo/) (fork) +- [@Bensge](https://github.com/Bensge/) - (used some code from his project [NativeDisplayBrightness](https://github.com/Bensge/NativeDisplayBrightness)) +- [@nhurden](https://github.com/nhurden/) (for the original MediaKeyTap) +- [@kfix](https://github.com/kfix/ddcctl) (for ddcctl) +- [@reitermarkus](https://github.com/reitermarkus) (for DDC.Swift) +- [@zhuowei](https://github.com/zhuowei) (figured out M1 I²C communication) +- [@tao-j](https://github.com/tao-j) (figured out M1 I²C write) +- [@alin23](https://github.com/alin23) (generally spearheaded M1 DDC support and figured out a many of the caveats) +- [javierocasio](https://www.deviantart.com/javierocasio) (app icon background) diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 00000000..fa62a28c --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +monitorcontrol.app \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..6c23710f --- /dev/null +++ b/docs/index.html @@ -0,0 +1,15 @@ + + + + + + + MonitorControl - redirect + + + + If you are not redirected automatically, follow this link!. + + \ No newline at end of file