From 51429f25af5cd7c8434c9800800e2428c1eb379a Mon Sep 17 00:00:00 2001 From: Phil Marell Date: Sun, 5 Jan 2025 00:17:54 +1100 Subject: [PATCH 01/13] Add ability to drag out status item to remove --- MonitorControl/Support/AppDelegate.swift | 25 ++++++++++++++++--- MonitorControl/Support/MenuHandler.swift | 4 +-- .../MenuslidersPrefsViewController.swift | 9 +++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/MonitorControl/Support/AppDelegate.swift b/MonitorControl/Support/AppDelegate.swift index 297e0dd..6d1013b 100644 --- a/MonitorControl/Support/AppDelegate.swift +++ b/MonitorControl/Support/AppDelegate.swift @@ -11,11 +11,17 @@ import SimplyCoreAudio import Sparkle class AppDelegate: NSObject, NSApplicationDelegate { - let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + let statusItem: NSStatusItem = { + let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) + item.behavior = .removalAllowed + return item + }() var mediaKeyTap = MediaKeyTapManager() var keyboardShortcuts = KeyboardShortcutsManager() let coreAudio = SimplyCoreAudio() var accessibilityObserver: NSObjectProtocol! + var statusItemObserver: NSObjectProtocol! + var statusItemVisibilityChangedByUser = true var reconfigureID: Int = 0 // dispatched reconfigure command ID var sleepID: Int = 0 // sleep event ID var safeMode = false @@ -83,7 +89,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationWillTerminate(_: Notification) { os_log("Goodbye!", type: .info) DisplayManager.shared.resetSwBrightnessForAllDisplays(noPrefSave: true) - self.statusItem.isVisible = true + self.updateStatusItemVisibility(true) } private func setPrefsBuildNumber() { @@ -169,6 +175,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.willSleepNotification, object: nil) NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotification), name: NSWorkspace.didWakeNotification, object: nil) _ = DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name(rawValue: NSNotification.Name.accessibilityApi.rawValue), object: nil, queue: nil) { _ in DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { self.updateMediaKeyTap() } } // listen for accessibility status changes + self.statusItemObserver = statusItem.observe(\.isVisible, options: [.old, .new]) { _, _ in self.statusItemVisibilityChanged() } } @objc private func sleepNotification() { @@ -270,7 +277,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { if let bundleID = Bundle.main.bundleIdentifier { prefs.removePersistentDomain(forName: bundleID) } - app.statusItem.isVisible = true + app.updateStatusItemVisibility(true) self.setDefaultPrefs() self.checkPermissions() self.updateMediaKeyTap() @@ -352,4 +359,16 @@ class AppDelegate: NSObject, NSApplicationDelegate { onboardingVc?.window?.center() NSApp.activate(ignoringOtherApps: true) } + + private func statusItemVisibilityChanged() { + if !self.statusItem.isVisible, self.statusItemVisibilityChangedByUser { + prefs.set(MenuIcon.hide.rawValue, forKey: PrefKey.menuIcon.rawValue) + } + } + + func updateStatusItemVisibility(_ visible: Bool) { + statusItemVisibilityChangedByUser = false + statusItem.isVisible = visible + statusItemVisibilityChangedByUser = true + } } diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index fcd79aa..fd61cd5 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -33,7 +33,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { if !dontClose { self.cancelTrackingWithoutAnimation() } - app.statusItem.isVisible = prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.show.rawValue ? true : false + app.updateStatusItemVisibility(prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.show.rawValue ? true : false) self.clearMenu() let currentDisplay = DisplayManager.shared.getCurrentDisplay() var displays: [Display] = [] @@ -185,7 +185,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { self.addDisplayMenuBlock(addedSliderHandlers: addedSliderHandlers, blockName: display.readPrefAsString(key: .friendlyName) != "" ? display.readPrefAsString(key: .friendlyName) : display.name, monitorSubMenu: monitorSubMenu, numOfDisplays: numOfDisplays, asSubMenu: asSubMenu) } if addedSliderHandlers.count > 0, prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.sliderOnly.rawValue { - app.statusItem.isVisible = true + app.updateStatusItemVisibility(true) } } diff --git a/MonitorControl/View Controllers/Preferences/MenuslidersPrefsViewController.swift b/MonitorControl/View Controllers/Preferences/MenuslidersPrefsViewController.swift index a27237c..3d132ea 100644 --- a/MonitorControl/View Controllers/Preferences/MenuslidersPrefsViewController.swift +++ b/MonitorControl/View Controllers/Preferences/MenuslidersPrefsViewController.swift @@ -80,6 +80,7 @@ class MenuslidersPrefsViewController: NSViewController, SettingsPane { override func viewDidLoad() { super.viewDidLoad() self.populateSettings() + prefs.addObserver(self, forKeyPath: PrefKey.menuIcon.rawValue, context: nil) } func populateSettings() { @@ -210,4 +211,12 @@ class MenuslidersPrefsViewController: NSViewController, SettingsPane { app.updateMenusAndKeys() self.updateGridLayout() } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + guard let object = object as? AnyObject else { return } + if object === prefs, keyPath == PrefKey.menuIcon.rawValue { + self.populateSettings() + self.updateGridLayout() + } + } } From 6e7acf018fa7ca35e404eefa31bc66e073e494e7 Mon Sep 17 00:00:00 2001 From: Alex Rattray Date: Sat, 11 Jan 2025 17:27:03 -0500 Subject: [PATCH 02/13] Make v4.2.0->v4.3.3 migration more prominent in README As suggested here: https://github.com/MonitorControl/MonitorControl/issues/1663#issuecomment-2450353050 --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e136352..121a837 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ App icon
-

MonitorControl - now compatible with macOS Sequoia

+

MonitorControl

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

Download for macOS @@ -24,6 +24,12 @@ Use menubar extra sliders or the keyboard, including native Apple keys!


+> [!WARNING] +> **v4.2.0 [crashes](https://github.com/MonitorControl/MonitorControl/issues/1663)** on macOS 15.1.x and cannot auto-update; please reinstall to v4.3.3, for example with: +> ``` +> brew reinstall monitorcontrol +> ``` + ## Download Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and download the latest `.dmg`, or you can install via Homebrew: From 9ed1e3e543d9c0903a20fb66db29faee41d3d7fd Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Mon, 20 Jan 2025 13:31:45 +0100 Subject: [PATCH 03/13] Update README.md --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 121a837..127ab85 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,7 @@ Use menubar extra sliders or the keyboard, including native Apple keys!


> [!WARNING] -> **v4.2.0 [crashes](https://github.com/MonitorControl/MonitorControl/issues/1663)** on macOS 15.1.x and cannot auto-update; please reinstall to v4.3.3, for example with: -> ``` -> brew reinstall monitorcontrol -> ``` +> MonitorControl v4.2.0 [may crash](https://github.com/MonitorControl/MonitorControl/issues/1663) on macOS 15 Sequoia on certain configurations. Additionally, the v4.2.0 version will not auto update to the [latest app version](https://github.com/MonitorControl/MonitorControl/releases). Please upgrade manually to fix the issue and to receive future updates. ## Download From 667e3d98cac0aeaee758381bf32038547c5ddeae Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Mon, 20 Jan 2025 13:33:34 +0100 Subject: [PATCH 04/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 127ab85..064a637 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Use menubar extra sliders or the keyboard, including native Apple keys!


> [!WARNING] -> MonitorControl v4.2.0 [may crash](https://github.com/MonitorControl/MonitorControl/issues/1663) on macOS 15 Sequoia on certain configurations. Additionally, the v4.2.0 version will not auto update to the [latest app version](https://github.com/MonitorControl/MonitorControl/releases). Please upgrade manually to fix the issue and to receive future updates. +> MonitorControl v4.2.0 [may crash](https://github.com/MonitorControl/MonitorControl/issues/1663) on certain configurations running macOS 15 Sequoia. Additionally, this version will not automatically update to the [latest app version](https://github.com/MonitorControl/MonitorControl/releases). To resolve the issue and ensure future updates, please upgrade manually. ## Download From 81170cd7fc582470f3bb75feeb18d0405c2a9a6e Mon Sep 17 00:00:00 2001 From: Wei GENG Date: Thu, 6 Feb 2025 11:29:09 +0100 Subject: [PATCH 05/13] Update README.md (#1727) fix brew install cask command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 064a637..58bd15c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Use menubar extra sliders or the keyboard, including native Apple keys!

Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and download the latest `.dmg`, or you can install via Homebrew: ```shell -brew install MonitorControl +brew install --cask monitorcontrol ``` ## Major features From 796ab5a7f7759cbbf8ec5ba13d2f75591af62137 Mon Sep 17 00:00:00 2001 From: Jirka Date: Fri, 25 Jul 2025 23:41:57 +0200 Subject: [PATCH 06/13] Update InternetAccessPolicy.strings (#1775) --- MonitorControl/UI/cs.lproj/InternetAccessPolicy.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MonitorControl/UI/cs.lproj/InternetAccessPolicy.strings b/MonitorControl/UI/cs.lproj/InternetAccessPolicy.strings index 0088fdd..dcc437b 100644 --- a/MonitorControl/UI/cs.lproj/InternetAccessPolicy.strings +++ b/MonitorControl/UI/cs.lproj/InternetAccessPolicy.strings @@ -5,4 +5,4 @@ "SoftwareUpdateDenyConsequences" = "Pokud nepovolíte tato připojení, nebudete moct dostávat oznámení o nových verzích ani bezpečnostních aktualizacích. Bezpečnostní aktualizace jsou důležité na ochranu proti malwaru."; /* Software update purpose */ -"SoftwareUpdatePurpose" = "MonitorControl kontroluje, jestli nejsou k dispozici nové verze nebo bezpečnostní aktualizace."; +"SoftwareUpdatePurpose" = "MonitorControl kontroluje, zda nejsou k dispozici nové verze nebo bezpečnostní aktualizace."; From a42160328654d3e43833fc4221652f22fb1dcd2f Mon Sep 17 00:00:00 2001 From: Jirka Date: Fri, 25 Jul 2025 23:42:29 +0200 Subject: [PATCH 07/13] Update Localizable.strings (#1776) --- .../UI/cs.lproj/Localizable.strings | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/MonitorControl/UI/cs.lproj/Localizable.strings b/MonitorControl/UI/cs.lproj/Localizable.strings index e0aab7e..1256215 100644 --- a/MonitorControl/UI/cs.lproj/Localizable.strings +++ b/MonitorControl/UI/cs.lproj/Localizable.strings @@ -2,16 +2,16 @@ "About" = "O aplikaci"; /* Shown in the alert dialog */ -"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "Zdá se, že jas a barvy ovládá ještě nějaká další aplikace, což způsobuje problémy.\n\nBuďto jinou aplikaci ukončete, nebo v MonitorControl vypněte ovládání gamy pro vaše displeje!"; +"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "Zdá se, že jas a barvy ovládá ještě nějaká další aplikace, což způsobuje problémy.\n\nBuďto jinou aplikaci ukončete, nebo v MonitorControl vypněte ovládání gamy pro Vaše displeje!"; /* Shown in the main prefs window */ "App menu" = "Nabídka"; /* 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." = "Určitě chcete zapnout delší prodlevu? Může dojít k zamrznutí systému, což by vyžadovalo restart. Možnost \„Spustit po přihlášení\“ se z bezpečnostních důvodů vypne."; +"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." = "Opravdu chcete zapnout delší prodlevu? Může dojít k zamrznutí systému, což by vyžadovalo restart. Volba "Spustit po přihlášení" se z bezpečnostních důvodů vypne."; /* Shown in the alert dialog */ -"Are you sure you want to reset all settings?" = "Určitě chcete obnovit všechny předvolby?"; +"Are you sure you want to reset all settings?" = "Opravdu chcete obnovit všechna nastavení?"; /* Shown in menu */ "Brightness" = "Jas"; @@ -23,7 +23,7 @@ "Built-in Display" = "Vestavěný displej"; /* Shown in menu */ -"Check for updates…" = "Vyhledat aktualizace…"; +"Check for updates…" = "Zkontrolovat aktualizace..."; /* Shown in menu */ "Contrast" = "Kontrast"; @@ -65,7 +65,7 @@ "Increase" = "Zvýšit"; /* Shown in the alert dialog */ -"Is f.lux or similar running?" = "Běží f.lux nebo něco podobného?"; +"Is f.lux or similar running?" = "Neběží f.lux nebo něco podobného?"; /* Shown in the main prefs window */ "Keyboard" = "Klávesnice"; @@ -83,22 +83,22 @@ "Other Display" = "Jiný displej"; /* Shown in the alert dialog */ -"Settings for an incompatible previous app version detected. Default settings are reloaded." = "Nalezeny předvolby pro předchozí, nekompatibilní verzi aplikace. Načetly se výchozí hodnoty."; +"Settings for an incompatible previous app version detected. Default settings are reloaded." = "Nalezena nastavení pro předchozí, nekompatibilní verzi aplikace. Načetla se výchozí nastavení."; /* Shown in menu */ -"Settings…" = "Předvolby…"; +"Settings…" = "Nastavení..."; /* Shown in menu */ "Quit" = "Ukončit"; /* Shown in the alert dialog */ -"Reset Settings?" = "Obnovit předvolby?"; +"Reset Settings?" = "Obnovit nastavení?"; /* Shown in the alert dialog */ -"Safe Mode Activated" = "Bezpečný režim aktivní"; +"Safe Mode Activated" = "Bezpečný režim aktivován"; /* Shown in the alert dialog */ -"Shift was pressed during launch. MonitorControl started in safe mode. Default settings are reloaded, DDC read is blocked." = "Běhěm spuštění byl zmáčknutý Shift. MonitorControl běží v bezpečném režimu. Byly načteny výchozí předvolby, čtení DDC je zablokováno."; +"Shift was pressed during launch. MonitorControl started in safe mode. Default settings are reloaded, DDC read is blocked." = "Běhěm spuštění byl stisknutý Shift. MonitorControl běží v bezpečném režimu. Byla načtena výchozí nastavení; čtení DDC je zablokováno."; /* Shown in the alert dialog */ "Shortcuts not available" = "Zkratky nejsou k dispozici"; @@ -107,31 +107,31 @@ "Software (gamma)" = "Softwarové (gama)"; /* Shown in the Display Settings */ -"Software (gamma, forced)" = "Softwarové (gama, nucené)"; +"Software (gamma, forced)" = "Softwarové (gama, vynucené)"; /* Shown in the Display Settings */ "Software (shade)" = "Softwarové (stínování)"; /* Shown in the Display Settings */ -"Software (shade, forced)" = "Software (stínování, nucené)"; +"Software (shade, forced)" = "Software (stínování, vynucené)"; /* Shown in the Display Settings */ -"This display allows for software brightness control via gamma table manipulation or shade as it does not support hardware control. Reasons for this might be using the HDMI port of a Mac mini (which blocks hardware DDC control) or having a blacklisted display." = "Jas tohoto displeje lze ovládat softwarově – manipulací gamy nebo stínování, protože hardwarové ovládání nepodporuje. Důvodem může být připojení přes HDMI port na Macu mini (který blokuje hardwarové ovládání DDC) nebo to, že displej patří na seznam nepodporovaných."; +"This display allows for software brightness control via gamma table manipulation or shade as it does not support hardware control. Reasons for this might be using the HDMI port of a Mac mini (which blocks hardware DDC control) or having a blacklisted display." = "Jas tohoto displeje lze ovládat softwarově – manipulací gamy nebo stínování, protože hardwarové ovládání nepodporuje. Důvodem může být připojení přes HDMI port na Macu Mini (který blokuje hardwarové ovládání DDC) nebo to, že displej patří na seznam nepodporovaných."; /* Shown in the Display Settings */ -"This display has an unspecified control status." = "Tento displej má nespecifikovaný kontrolní stav."; +"This display has an unspecified control status." = "Tento displej má nespecifikovaný stav ovládání."; /* Shown in the Display Settings */ -"This display is reported to support hardware DDC control but the current settings allow for software control only." = "Tento displej by měl podporovat hardwarové DDC ovládání, ale současná nastavení umožňují ovládání jen přes software."; +"This display is reported to support hardware DDC control but the current settings allow for software control only." = "Tento displej by měl podporovat hardwarové DDC ovládání, ale současná nastavení umožňují ovládání jen softwarové ovládání."; /* Shown in the Display Settings */ -"This display is reported to support hardware DDC control. If you encounter issues, you can disable hardware DDC control to force software control." = "Tento displej by měl podporovat hardwarové DDC ovládání. Pokud narazíte na problém, můžete hardwarové ovládání DDC vypnout a použít vynucené ovládání přes software."; +"This display is reported to support hardware DDC control. If you encounter issues, you can disable hardware DDC control to force software control." = "Tento displej by měl podporovat hardwarové DDC ovládání. Pokud narazíte na problém, můžete hardwarové ovládání DDC vypnout a použít vynucené softwarové ovládání."; /* Shown in the Display Settings */ "This display supports native Apple brightness protocol. This allows macOS to control this display without MonitorControl as well." = "Tento displej podporuje nativní jasový protokol Apple. Díky tomu ho může macOS ovládat i bez MonitorControl."; /* Shown in the Display Settings */ -"This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode." = "Toto je virtuální displej (např. AirPlay, Sidecar, DisplayLink a podobně), což neumožňuje ovládání gamy přes software ani hardware. Jako náhrada slouží stínování, ale jen za předpokladu, že displej není nastaven na zrcadlení. Změny se neprojeví na ukazateli myši a můžou se objevit vizuální artefakty při přepínání režimu na celou obrazovku."; +"This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode." = "Toto je virtuální displej (např. AirPlay, Sidecar, DisplayLink a podobně), který neumožňuje hardwarové, ani softwarové ovládání gamy. Jako náhrada slouží stínování, ale jen za předpokladu, že displej není nastaven na zrcadlení. Změny se neprojeví na ukazateli myši a můžou se objevit vizuální artefakty při přepínání režimu na celou obrazovku."; /* Unknown display name */ "Unknown" = "Neznámý"; From 2f1a2e043c5b5cf2015ce4d020220d825d65f383 Mon Sep 17 00:00:00 2001 From: Jirka Date: Fri, 25 Jul 2025 23:43:10 +0200 Subject: [PATCH 08/13] Update Main.strings (#1777) --- MonitorControl/UI/cs.lproj/Main.strings | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/MonitorControl/UI/cs.lproj/Main.strings b/MonitorControl/UI/cs.lproj/Main.strings index c334037..8f982e1 100644 --- a/MonitorControl/UI/cs.lproj/Main.strings +++ b/MonitorControl/UI/cs.lproj/Main.strings @@ -44,7 +44,7 @@ "7zf-m1-gJO.title" = "Zobrazovat značky na posuvníku"; /* Class = "NSTextFieldCell"; title = "Slider knob will snap to 0%, 25%, 50%, 75% and 100% when in proximity making setting these values easier. Disable for finer control."; ObjectID = "8Gx-Ya-zhp"; */ -"8Gx-Ya-zhp.title" = "Posuvník se bude přitahovat na hodnoty 0%, 25%, 50%, 75% a 100%, aby šly snadno nastavit. Pro přesnější ovládání můžete možnost vypnout."; +"8Gx-Ya-zhp.title" = "Posuvník se bude přitahovat na hodnoty 0 %, 25 %, 50 %, 75 % a 100 %, aby šly snadno nastavit. Pro přesnější ovládání můžete možnost vypnout."; /* Class = "NSButtonCell"; title = "Use fine OSD scale for brightness and contrast"; ObjectID = "8Q8-57-xnT"; */ "8Q8-57-xnT.title" = "Používat jemnější škálu pro jas a kontrast"; @@ -62,10 +62,10 @@ "9yL-no-aWa.title" = "Zkusit přečíst nastavení displeje"; /* Class = "NSTextFieldCell"; title = "Show tick marks at 0%, 25%, 50%, 75% and 100% for accuracy."; ObjectID = "A8P-vn-DEJ"; */ -"A8P-vn-DEJ.title" = "Pro větší přesnost označit na posuvníku hodnoty 0%, 25%, 50%, 75% a 100%."; +"A8P-vn-DEJ.title" = "Pro větší přesnost označí na posuvníku hodnoty 0 %, 25 %, 50 %, 75 % a 100 %."; /* Class = "NSTextFieldCell"; title = "Use brightness, volume and other settings from last time or use defaults. Values will be applied to the display upon first change by the user."; ObjectID = "an7-Aj-3fZ"; */ -"an7-Aj-3fZ.title" = "Zachovat jas, hlasitost a další nastavení od minula, nebo použít výchozí hodnoty. Nastavení se použijí na displej po první změně uživatelem."; +"an7-Aj-3fZ.title" = "Zachová jas, hlasitost a další nastavení od minula, nebo použije výchozí hodnoty. Nastavení se použijí na displej po první změně uživatelem."; /* Class = "NSMenuItem"; title = "Use audio device name to determine which display to control"; ObjectID = "AqF-uD-KCY"; */ "AqF-uD-KCY.title" = "Určit podle názvu zvukového zařízení"; @@ -83,7 +83,7 @@ "Bid-UL-blc.title" = "(Software->DDC)"; /* Class = "NSTextFieldCell"; title = "For hardware (DDC) controlled displays only. Results may vary."; ObjectID = "bIe-6O-xEH"; */ -"bIe-6O-xEH.title" = "Pouze pro displeje ovládané hardwarem (DDC). Výsledky se mohou různit."; +"bIe-6O-xEH.title" = "Jen pro displeje ovládané hardwarem (DDC). Výsledky se mohou lišit."; /* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ "bkM-Px-U3b.title" = "Vypnout systémový ukazatel hlasitosti"; @@ -137,7 +137,7 @@ "f6J-Ui-uMB.title" = "Normálně se klávesovými zkratkami přidává / ubírá vždy celý dílek, zatímco pro jemnější ovládání je třeba držet Shift+Option. Když ale zaškrtnete tuto možnost, jemnější ovládání bude tím výchozím."; /* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ -"f9g-8s-gdd.title" = "Resetovat jméno"; +"f9g-8s-gdd.title" = "Resetovat název"; /* Class = "NSButtonCell"; title = "Automatically check for updates"; ObjectID = "Faf-9L-TXx"; */ "Faf-9L-TXx.title" = "Automaticky hledat aktualizace"; @@ -176,10 +176,10 @@ "H9X-it-sXs.title" = "Ručně přejmenovat zvukové zařízení:"; /* Class = "NSTextFieldCell"; title = "Relaunch the app to access Settings if the menu option is not accessible. Use the button below to quit the app."; ObjectID = "hF7-fM-aKr"; */ -"hF7-fM-aKr.title" = "Když menu v řádku nabídek není k dispozici, k předvolbám se dostanete tak, že aplikaci ukončíte a znovu spustíte. K ukončení můžete použít tlačítko níže:"; +"hF7-fM-aKr.title" = "Když menu v řádku nabídek není k dispozici, k nastavení se dostanete tak, že aplikaci ukončíte a znovu spustíte. K ukončení můžete použít tlačítko níže:"; /* Class = "NSButtonCell"; title = "Get current"; ObjectID = "hkC-vq-IcD"; */ -"hkC-vq-IcD.title" = "Vyplnit stávající"; +"hkC-vq-IcD.title" = "Získat aktuální"; /* Class = "NSMenuItem"; title = "Hide"; ObjectID = "HUT-Qc-kuu"; */ "HUT-Qc-kuu.title" = "Skrýt"; @@ -212,13 +212,13 @@ "JWJ-OY-VtE.title" = "Spouštět MonitorControl po přihlášení"; /* Class = "NSTextFieldCell"; title = "Note: you can press Shift during startup for 'Safe mode' to restore defaults and avoid reading or setting anything."; ObjectID = "Jx2-gO-nq9"; */ -"Jx2-gO-nq9.title" = "Poznámka: Když běhěm spouštění podržíte Shift, aktivuje se tzv. ‚bezpečný režim‘ – načtou se výchozí hodnoty a z displejů se nebude nic číst ani zapisovat."; +"Jx2-gO-nq9.title" = "Poznámka: Když během spouštění podržíte Shift, aktivuje se "Bezpečný režim" – načtou se výchozí hodnoty a z displejů se nebude nic číst ani zapisovat."; /* Class = "NSButtonCell"; title = "Enable for Apple branded and built-in displays as well"; ObjectID = "K6A-4z-1aQ"; */ "K6A-4z-1aQ.title" = "Povolit i pro vestavěný displej a pro monitory Apple"; /* Class = "NSTextFieldCell"; title = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Settings > Security and Privacy > Accessibility."; ObjectID = "kBJ-Zf-1k2"; */ -"kBJ-Zf-1k2.title" = "Pokud chcete ovládat displeje výchozími macOS klávesami, MonitorControl pořebuje přístup ke \„zpřístupnění\“. \nMůžete ho udělit tím, že přidáte MonitorControl do sekce Předvolby systému > Zabezpečení a soukromí > Zpřístupnění."; +"kBJ-Zf-1k2.title" = "Pokud chcete ovládat displeje výchozími klávesami macOS, MonitorControl pořebuje přístup ke "zpřístupnění".\nMůžete ho udělit tím, že přidáte MonitorControl do sekce Předvolby systému > Zabezpečení a soukromí > Zpřístupnění."; /* Class = "NSTextFieldCell"; title = "Screen to control:"; ObjectID = "Kfj-WK-aSL"; */ "Kfj-WK-aSL.title" = "Kterou obrazovku ovládat:"; @@ -239,7 +239,7 @@ "ltL-gR-K3Z.title" = "Kterou obrazovku ovládat:"; /* Class = "NSTextFieldCell"; title = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; ObjectID = "Mh5-1A-apq"; */ -"Mh5-1A-apq.title" = "Ovládejte jas, kontrast a hlasitost svých externích displejů přímo z vašeho Macu pomocí posuvníků v nabídce a/nebo kláves, včetně výchozích kláves Apple."; +"Mh5-1A-apq.title" = "Ovládejte jas, kontrast a hlasitost svých externích displejů přímo z Vašeho Macu pomocí posuvníků v nabídce a/nebo kláves, včetně výchozích kláves Apple."; /* Class = "NSButtonCell"; title = "Enable slider snapping"; ObjectID = "MlU-hl-d46"; */ "MlU-hl-d46.title" = "Povolit přichytávání posuvníku"; @@ -260,7 +260,7 @@ "na6-mS-MPi.title" = "Vyhnout se změnám gamy"; /* Class = "NSTextFieldCell"; title = "Ensure MonitorControl is always running when you need it by launching the app at startup."; ObjectID = "nk6-Gh-Mfs"; */ -"nk6-Gh-Mfs.title" = "Spouštět MonitorControl po přihlášení, aby byl vždy po ruce."; +"nk6-Gh-Mfs.title" = "Spouští MonitorControl po přihlášení, aby byl vždy po ruce."; /* Class = "NSTextFieldCell"; title = "Brightness up"; ObjectID = "nty-g6-Sde"; */ "nty-g6-Sde.title" = "Zvýšit jas"; @@ -281,7 +281,7 @@ "Orv-yj-Nad.title" = "počet:"; /* Class = "NSTextFieldCell"; title = "Use the brightness keys of your Apple keyboard to control brightness. You can hold Control to adjust the built-in display, Control+Command to adjust external displays. Hold Shift+Option for fine control. Control+Option+Command adjusts contrast on DDC compatible displays."; ObjectID = "pa0-Hz-ace"; */ -"pa0-Hz-ace.title" = "Používejte normální klávesy jasu na vaší Apple klávesnici. Přidržením klávesy Control můžete ovládat jen vestavěný displej, přidržením Control+Command jen externí displeje, pro jemnější ovládání použijte Shift+Option. Přidržením Control+Option+Command můžete měnit kontrast na kompatibilních DDC displejích."; +"pa0-Hz-ace.title" = "Používejte normální klávesy jasu na Vaší Apple klávesnici. Přidržením klávesy Control můžete ovládat jen vestavěný displej, přidržením Control+Command jen externí displeje, pro jemnější ovládání použijte Shift+Option. Přidržením Control+Option+Command můžete měnit kontrast na kompatibilních DDC displejích."; /* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ "PaK-1f-DsW.title" = "Metoda ovládání:"; @@ -311,7 +311,7 @@ "qO0-dB-yUs.title" = "V menu zobrazovat posuvník kontrastu"; /* Class = "NSTextFieldCell"; title = "Volume control (DDC only):"; ObjectID = "qoh-Gn-f11"; */ -"qoh-Gn-f11.title" = "Ovládání hlasitosti (pouze u DDC):"; +"qoh-Gn-f11.title" = "Ovládání hlasitosti (jen u DDC):"; /* Class = "NSTextFieldCell"; title = "Show percentage next to slider for more precision."; ObjectID = "qXy-CL-Wf1"; */ "qXy-CL-Wf1.title" = "Pro větší přesnost zobrazovat vedle posuvníku procenta."; @@ -335,7 +335,7 @@ "u6s-Pb-BCG.title" = "Ikona v řádku nabídek"; /* Class = "NSButtonCell"; title = "Show advanced settings"; ObjectID = "UBq-Od-SIB"; */ -"UBq-Od-SIB.title" = "Zobrazit pokročilé volby"; +"UBq-Od-SIB.title" = "Zobrazit pokročilá nastavení"; /* Class = "NSTextFieldCell"; title = "Works if an audio device is selected with no native volume control."; ObjectID = "uF5-a9-Ngz"; */ "uF5-a9-Ngz.title" = "Funguje u zvukových zařízení, která nemají vlastní ovládání hlasitosti."; @@ -356,10 +356,10 @@ "vri-pv-tJ4.title" = "Více displejů:"; /* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ -"vwm-hY-on5.title" = "režim pollingu při čtení DDC:"; +"vwm-hY-on5.title" = "Režim dotazování při čtení DDC:"; /* Class = "NSTextFieldCell"; title = "General options:"; ObjectID = "W58-ch-j69"; */ -"W58-ch-j69.title" = "Obecné možnosti:"; +"W58-ch-j69.title" = "Obecné volby:"; /* Class = "NSTextFieldCell"; title = "Useful when a display tends to reset its settings during sleep."; ObjectID = "w8B-x6-sq5"; */ "w8B-x6-sq5.title" = "Užitečné pro displeje, které mají tendenci resetovat svá nastavení, jakmile usnou."; @@ -374,13 +374,13 @@ "xjq-hs-wWB.title" = "Načíst nastavení z displeje. Nemusí fungovat se všemi zařízeními."; /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ -"xLa-PN-rsq.title" = "Pouze pokud je k dispozici alespoň jeden posuvník"; +"xLa-PN-rsq.title" = "Jen pokud je k dispozici alespoň jeden posuvník"; /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Standardní i vlastní zkratky"; /* Class = "NSTextFieldCell"; title = "Works best with various syncing and 'control all' keyboard settings enabled."; ObjectID = "XU4-Bn-bwH"; */ -"XU4-Bn-bwH.title" = "Funguje nejlépe s různými možnostmi synchronizace, sjednoceného ovládání apod."; +"XU4-Bn-bwH.title" = "Funguje nejlépe s různými nastaveními synchronizace, sjednoceného ovládání apod."; /* Class = "NSTextFieldCell"; title = "Available"; ObjectID = "yBJ-5d-I7e"; */ "yBJ-5d-I7e.title" = "K dispozici"; @@ -389,7 +389,7 @@ "YHZ-VL-QJ3.title" = "Škála OSD pokryje celý rozsah hardwarového jasu – jakmile klesne až na nulu, displej se bude dál ztmívat softwarem."; /* Class = "NSTextFieldCell"; title = "Warning! With this option enabled, you might find yourself in a position when you end up with a blank display. This, combined with disabled keyboard controls can be frustrating."; ObjectID = "yi3-e1-wsL"; */ -"yi3-e1-wsL.title" = "Pozor! Pokud tuto možnost zapnete, můžete se dostat do situace, kdy na displeji není nic vidět. To může být frustrující, obzvlášť pokud máte zároveň vypnuté klávesové zkratky-"; +"yi3-e1-wsL.title" = "Pozor! Pokud tuto možnost zapnete, můžete se dostat do situace, kdy na displeji není nic vidět. To může být frustrující, obzvlášť pokud máte zároveň vypnuté klávesové zkratky."; /* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ "YqZ-LS-YvR.title" = "Identifikátor:"; From f62c7e66ce8b7116771de441b7c3b734c73524ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo=20Here=C3=B1=C3=BA?= Date: Sun, 16 Nov 2025 06:57:44 -0300 Subject: [PATCH 09/13] Fix typo in Spanish translation in Localizable.strings (#1806) --- MonitorControl/UI/es.lproj/Localizable.strings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MonitorControl/UI/es.lproj/Localizable.strings b/MonitorControl/UI/es.lproj/Localizable.strings index f8ccd2c..67ec484 100644 --- a/MonitorControl/UI/es.lproj/Localizable.strings +++ b/MonitorControl/UI/es.lproj/Localizable.strings @@ -98,7 +98,7 @@ "Safe Mode Activated" = "Modo Seguro Activado"; /* Shown in the alert dialog */ -"Shift was pressed during launch. MonitorControl started in safe mode. Default settings are reloaded, DDC read is blocked." = "La techa Shift fue presionada durante el lanzamiento. MonitorControl se inició en modo seguro. Se han cargado las preferencias por defecto, la lectura DDC está bloqueada."; +"Shift was pressed during launch. MonitorControl started in safe mode. Default settings are reloaded, DDC read is blocked." = "La tecla Shift fue presionada durante el lanzamiento. MonitorControl se inició en modo seguro. Se han cargado las preferencias por defecto, la lectura DDC está bloqueada."; /* Shown in the alert dialog */ "Shortcuts not available" = "Atajos no disponibles"; @@ -132,7 +132,7 @@ "This display supports native Apple brightness protocol. This allows macOS to control this display without MonitorControl as well." = "Esta pantalla soporta el protocolo de brillo nativo de Apple. Esto le permite también a macOS controlar la pantalla sin MonitorControl."; /* Shown in the Display Settings */ -"This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode." = "Esto es una pantalla virtual (ejemplos: AirPlay, Sidecar, pantalla conectada a través del dock DisplayLink o similar) el cual no permite el control a través de gamma ni por hardware ni por software. El sombreado es usado como sustituto, pero solo en escenarios sin espejo. El cursor del ratón no verá afectado pero pueden aparecer objetos extraños cuando se entra/sale del modo pantalla completa."; +"This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode." = "Esto es una pantalla virtual (ejemplos: AirPlay, Sidecar, pantalla conectada a través del dock DisplayLink o similar) el cual no permite el control a través de gamma ni por hardware ni por software. El sombreado es usado como sustituto, pero solo en escenarios sin espejo. El cursor del ratón no se verá afectado pero pueden aparecer objetos extraños cuando se entra/sale del modo pantalla completa."; /* Unknown display name */ "Unknown" = "Desconocido"; From d4309e6ec59adf08d7b732b398a0611ec8c640cc Mon Sep 17 00:00:00 2001 From: NEO Date: Sun, 16 Nov 2025 17:58:59 +0800 Subject: [PATCH 10/13] feat: support "only when external display show menu bar icon" option (#1817) Co-authored-by: neo --- MonitorControl/Enums/PrefKey.swift | 1 + MonitorControl/Support/MenuHandler.swift | 14 +++++++++++++- MonitorControl/UI/Base.lproj/Main.storyboard | 1 + MonitorControl/UI/cs.lproj/Main.strings | 3 +++ MonitorControl/UI/de.lproj/Main.strings | 3 +++ MonitorControl/UI/en.lproj/Main.strings | 3 +++ MonitorControl/UI/es.lproj/Main.strings | 3 +++ MonitorControl/UI/fr.lproj/Main.strings | 3 +++ MonitorControl/UI/hi.lproj/Main.strings | 3 +++ MonitorControl/UI/hu.lproj/Main.strings | 3 +++ MonitorControl/UI/it.lproj/Main.strings | 3 +++ MonitorControl/UI/ja.lproj/Main.strings | 3 +++ MonitorControl/UI/ko.lproj/Main.strings | 3 +++ MonitorControl/UI/nl.lproj/Main.strings | 3 +++ MonitorControl/UI/pl.lproj/Main.strings | 3 +++ MonitorControl/UI/pt-BR.lproj/Main.strings | 3 +++ MonitorControl/UI/pt-PT.lproj/Main.strings | 3 +++ MonitorControl/UI/ru.lproj/Main.strings | 3 +++ MonitorControl/UI/sk.lproj/Main.strings | 3 +++ MonitorControl/UI/tr.lproj/Main.strings | 3 +++ MonitorControl/UI/zh-Hans.lproj/Main.strings | 3 +++ MonitorControl/UI/zh-Hant-TW.lproj/Main.strings | 3 +++ 22 files changed, 72 insertions(+), 1 deletion(-) diff --git a/MonitorControl/Enums/PrefKey.swift b/MonitorControl/Enums/PrefKey.swift index 3b08aff..76b5f29 100644 --- a/MonitorControl/Enums/PrefKey.swift +++ b/MonitorControl/Enums/PrefKey.swift @@ -191,6 +191,7 @@ enum MenuIcon: Int { case show = 0 case sliderOnly = 1 case hide = 2 + case externalOnly = 3 } enum MenuItemStyle: Int { diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index fd61cd5..65c3ad9 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -33,7 +33,19 @@ class MenuHandler: NSMenu, NSMenuDelegate { if !dontClose { self.cancelTrackingWithoutAnimation() } - app.updateStatusItemVisibility(prefs.integer(forKey: PrefKey.menuIcon.rawValue) == MenuIcon.show.rawValue ? true : false) + let menuIconPref = prefs.integer(forKey: PrefKey.menuIcon.rawValue) + var showIcon = false + if menuIconPref == MenuIcon.show.rawValue { + showIcon = true + } else if menuIconPref == MenuIcon.externalOnly.rawValue { + let externalDisplays = DisplayManager.shared.displays.filter { + CGDisplayIsBuiltin($0.identifier) == 0 + } + if externalDisplays.count > 0 { + showIcon = true + } + } + app.updateStatusItemVisibility(showIcon) self.clearMenu() let currentDisplay = DisplayManager.shared.getCurrentDisplay() var displays: [Display] = [] diff --git a/MonitorControl/UI/Base.lproj/Main.storyboard b/MonitorControl/UI/Base.lproj/Main.storyboard index 2f76365..f5a9bb4 100644 --- a/MonitorControl/UI/Base.lproj/Main.storyboard +++ b/MonitorControl/UI/Base.lproj/Main.storyboard @@ -368,6 +368,7 @@ ++ diff --git a/MonitorControl/UI/cs.lproj/Main.strings b/MonitorControl/UI/cs.lproj/Main.strings index 8f982e1..44466c0 100644 --- a/MonitorControl/UI/cs.lproj/Main.strings +++ b/MonitorControl/UI/cs.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Jen pokud je k dispozici alespoň jeden posuvník"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Pouze když je externí displej přítomen"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Standardní i vlastní zkratky"; diff --git a/MonitorControl/UI/de.lproj/Main.strings b/MonitorControl/UI/de.lproj/Main.strings index e9cdaad..cedb3e0 100644 --- a/MonitorControl/UI/de.lproj/Main.strings +++ b/MonitorControl/UI/de.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Nur wenn mindestens ein Regler vorhanden ist"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Nur wenn externer Bildschirm vorhanden ist"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Sowohl Standard- als auch benutzerdefinierte Tastenkombinationen"; diff --git a/MonitorControl/UI/en.lproj/Main.strings b/MonitorControl/UI/en.lproj/Main.strings index 1a01c19..7c40246 100644 --- a/MonitorControl/UI/en.lproj/Main.strings +++ b/MonitorControl/UI/en.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Only if at least one slider is present"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Only when external display is present"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Both standard and custom shortcuts"; diff --git a/MonitorControl/UI/es.lproj/Main.strings b/MonitorControl/UI/es.lproj/Main.strings index 14d59f2..ce85bd0 100644 --- a/MonitorControl/UI/es.lproj/Main.strings +++ b/MonitorControl/UI/es.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Sólo si hay presente al menos un slider"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Solo cuando la pantalla externa está presente"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Ambos, atajos estándar y personalizados"; diff --git a/MonitorControl/UI/fr.lproj/Main.strings b/MonitorControl/UI/fr.lproj/Main.strings index 1066945..9bef7aa 100644 --- a/MonitorControl/UI/fr.lproj/Main.strings +++ b/MonitorControl/UI/fr.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Uniquement si au moins un curseur est présent"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Seulement lorsqu'un écran externe est présent"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Raccourcis standard et personnalisés"; diff --git a/MonitorControl/UI/hi.lproj/Main.strings b/MonitorControl/UI/hi.lproj/Main.strings index 8e04df4..157076c 100644 --- a/MonitorControl/UI/hi.lproj/Main.strings +++ b/MonitorControl/UI/hi.lproj/Main.strings @@ -428,6 +428,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "केवल तभी जब कम से कम एक स्लाइडर मौजूद हो"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "केवल तभी जब बाहरी डिस्प्ले मौजूद हो"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "मानक और कस्टम दोनों शॉर्टकट"; diff --git a/MonitorControl/UI/hu.lproj/Main.strings b/MonitorControl/UI/hu.lproj/Main.strings index 47fcc26..de1a5e0 100644 --- a/MonitorControl/UI/hu.lproj/Main.strings +++ b/MonitorControl/UI/hu.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Csak ha legalább egy vezérlő megjelenik"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Csak ha külső kijelző van jelen"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Hagyományos és egyedi billentyűkombinációk"; diff --git a/MonitorControl/UI/it.lproj/Main.strings b/MonitorControl/UI/it.lproj/Main.strings index 53e2e57..b233e6e 100644 --- a/MonitorControl/UI/it.lproj/Main.strings +++ b/MonitorControl/UI/it.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Solo se è presente almeno uno slider"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Solo quando è presente un display esterno"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Entrambe le abbreviazioni standard e personalizzate"; diff --git a/MonitorControl/UI/ja.lproj/Main.strings b/MonitorControl/UI/ja.lproj/Main.strings index 25b3475..eff265c 100644 --- a/MonitorControl/UI/ja.lproj/Main.strings +++ b/MonitorControl/UI/ja.lproj/Main.strings @@ -428,6 +428,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "少なくとも 1 つのスライダーが存在する場合のみ"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "外部ディスプレイがある場合のみ"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "標準ショートカットとカスタムショートカットの両方"; diff --git a/MonitorControl/UI/ko.lproj/Main.strings b/MonitorControl/UI/ko.lproj/Main.strings index ec428e2..eed67a5 100644 --- a/MonitorControl/UI/ko.lproj/Main.strings +++ b/MonitorControl/UI/ko.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "슬라이더가 하나 이상 있는 경우에만"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "외부 디스플레이가 있을 때만"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "표준 및 사용자 정의 단축키 둘 다"; diff --git a/MonitorControl/UI/nl.lproj/Main.strings b/MonitorControl/UI/nl.lproj/Main.strings index 98eea32..e6f117e 100644 --- a/MonitorControl/UI/nl.lproj/Main.strings +++ b/MonitorControl/UI/nl.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Alleen als er ten minste één schuifregelaar aanwezig is"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Alleen wanneer een extern beeldscherm aanwezig is"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Zowel standaard als aangepaste sneltoetsen"; diff --git a/MonitorControl/UI/pl.lproj/Main.strings b/MonitorControl/UI/pl.lproj/Main.strings index aa5e0d0..5a80ee2 100644 --- a/MonitorControl/UI/pl.lproj/Main.strings +++ b/MonitorControl/UI/pl.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Tylko w przypadku obecności co najmniej jednego suwaka"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Tylko gdy monitor zewnętrzny jest obecny"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Skróty standardowe oraz użytkownika"; diff --git a/MonitorControl/UI/pt-BR.lproj/Main.strings b/MonitorControl/UI/pt-BR.lproj/Main.strings index 4ce3a95..8b846f4 100644 --- a/MonitorControl/UI/pt-BR.lproj/Main.strings +++ b/MonitorControl/UI/pt-BR.lproj/Main.strings @@ -379,6 +379,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Apenas se pelo menos um controle deslizante estiver presente"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Somente quando o monitor externo estiver presente"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Atalhos padrão e personalizados"; diff --git a/MonitorControl/UI/pt-PT.lproj/Main.strings b/MonitorControl/UI/pt-PT.lproj/Main.strings index e6044e4..bfbb74f 100644 --- a/MonitorControl/UI/pt-PT.lproj/Main.strings +++ b/MonitorControl/UI/pt-PT.lproj/Main.strings @@ -379,6 +379,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Apenas se pelo menos um controle deslizante estiver presente"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Apenas quando um ecrã externo estiver presente"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Atalhos padrão e personalizados"; diff --git a/MonitorControl/UI/ru.lproj/Main.strings b/MonitorControl/UI/ru.lproj/Main.strings index f011210..d3abb49 100644 --- a/MonitorControl/UI/ru.lproj/Main.strings +++ b/MonitorControl/UI/ru.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Только при наличии хотя бы одного ползунка"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Только при наличии внешнего дисплея"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Как стандартные, так и пользовательские сочетания клавиш"; diff --git a/MonitorControl/UI/sk.lproj/Main.strings b/MonitorControl/UI/sk.lproj/Main.strings index 6288cf2..c628a64 100644 --- a/MonitorControl/UI/sk.lproj/Main.strings +++ b/MonitorControl/UI/sk.lproj/Main.strings @@ -401,6 +401,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Iba ak je prítomný aspoň jeden posuvník"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Iba keď je prítomný externý displej"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Štandardné aj vlastné skratky"; diff --git a/MonitorControl/UI/tr.lproj/Main.strings b/MonitorControl/UI/tr.lproj/Main.strings index f860639..4b73342 100644 --- a/MonitorControl/UI/tr.lproj/Main.strings +++ b/MonitorControl/UI/tr.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "Yalnızca en az bir kaydırıcı varsa"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "Yalnızca harici ekran mevcut olduğunda"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Hem standart hem de özel kısayollar"; diff --git a/MonitorControl/UI/zh-Hans.lproj/Main.strings b/MonitorControl/UI/zh-Hans.lproj/Main.strings index f76f218..8d9867b 100644 --- a/MonitorControl/UI/zh-Hans.lproj/Main.strings +++ b/MonitorControl/UI/zh-Hans.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "只有当至少一个滑杆可用时"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "仅当存在外置显示器时"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "标准及自定义快捷键"; diff --git a/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings b/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings index cc10e78..ad84f26 100644 --- a/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings +++ b/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings @@ -376,6 +376,9 @@ /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ "xLa-PN-rsq.title" = "只有當至少一個滑桿可用時"; +/* Class = "NSMenuItem"; title = "Only when external display is present"; ObjectID = "Tb1-6s-qOo"; */ +"Tb1-6s-qOo.title" = "僅當存在外置顯示器時"; + /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "標準及自定快速鍵"; From 195a8e88ec60068c27c035c27d99c3acb6e60249 Mon Sep 17 00:00:00 2001 From: sametbrr <92684948+sametbrr@users.noreply.github.com> Date: Sun, 16 Nov 2025 12:59:58 +0300 Subject: [PATCH 11/13] sorting by name added (#1774) --- MonitorControl/Info.plist | 2 +- MonitorControl/Support/DisplayManager.swift | 34 +++++++++++++++++++-- MonitorControl/Support/MenuHandler.swift | 1 + MonitorControlHelper/Info.plist | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 6648c50..69810af 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 7122 + 7141 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index 7ace448..f53d5bb 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -240,8 +240,38 @@ class DisplayManager { self.displays.compactMap { $0 as? OtherDisplay } } + func sortDisplays() { + // Opsiyonel: sıralamadan önce log al + let before = displays.map { $0.name } + os_log("Displays before sorting: %{public}@", before) + + // In‑place sıralama + displays.sort { lhs, rhs in + lhs.name.localizedStandardCompare(rhs.name) == .orderedAscending + } + + // Opsiyonel: sıralamadan sonra log al + let after = displays.map { $0.name } + os_log("Displays after sorting: %{public}@", after) + } + + func sortDisplaysByFriendlyName() -> [Display] { + return displays.sorted { lhs, rhs in + let lhsTitle = lhs.readPrefAsString(key: .friendlyName).isEmpty + ? lhs.name + : lhs.readPrefAsString(key: .friendlyName) + let rhsTitle = rhs.readPrefAsString(key: .friendlyName).isEmpty + ? rhs.name + : rhs.readPrefAsString(key: .friendlyName) + return lhsTitle.localizedStandardCompare(rhsTitle) == .orderedDescending + } + } + + + + /// displays dizisini sıralar ve döner func getAllDisplays() -> [Display] { - self.displays + return displays } func getDdcCapableDisplays() -> [OtherDisplay] { @@ -283,7 +313,7 @@ class DisplayManager { func clearDisplays() { self.displays = [] } - + func addDisplayCounterSuffixes() { var nameDisplays: [String: [Display]] = [:] for display in self.displays { diff --git a/MonitorControl/Support/MenuHandler.swift b/MonitorControl/Support/MenuHandler.swift index 65c3ad9..6fcd486 100644 --- a/MonitorControl/Support/MenuHandler.swift +++ b/MonitorControl/Support/MenuHandler.swift @@ -53,6 +53,7 @@ class MenuHandler: NSMenu, NSMenuDelegate { displays.append(contentsOf: DisplayManager.shared.getAppleDisplays()) } displays.append(contentsOf: DisplayManager.shared.getOtherDisplays()) + displays = DisplayManager.shared.sortDisplaysByFriendlyName() let relevant = prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.relevant.rawValue let combine = prefs.integer(forKey: PrefKey.multiSliders.rawValue) == MultiSliders.combine.rawValue let numOfDisplays = displays.filter { !$0.isDummy }.count diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 3d3b539..e6cc0a2 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 7122 + 7141 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly From e72fab4e11c436358800fb916c7d84e2874d9ba9 Mon Sep 17 00:00:00 2001 From: vrqq Date: Thu, 15 Jan 2026 19:46:44 +0800 Subject: [PATCH 12/13] Fix build error (#1830) --- MonitorControl/UI/cs.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MonitorControl/UI/cs.lproj/Localizable.strings b/MonitorControl/UI/cs.lproj/Localizable.strings index 1256215..b2d535c 100644 --- a/MonitorControl/UI/cs.lproj/Localizable.strings +++ b/MonitorControl/UI/cs.lproj/Localizable.strings @@ -8,7 +8,7 @@ "App menu" = "Nabídka"; /* 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." = "Opravdu chcete zapnout delší prodlevu? Může dojít k zamrznutí systému, což by vyžadovalo restart. Volba "Spustit po přihlášení" se z bezpečnostních důvodů vypne."; +"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." = "Opravdu chcete zapnout delší prodlevu? Může dojít k zamrznutí systému, což by vyžadovalo restart. Volba \"Spustit po přihlášení\" se z bezpečnostních důvodů vypne."; /* Shown in the alert dialog */ "Are you sure you want to reset all settings?" = "Opravdu chcete obnovit všechna nastavení?"; From fc19ce2bd2767182a8a061e8d1ea10990239b41d Mon Sep 17 00:00:00 2001 From: waydabber <37590873+waydabber@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:32:15 +0100 Subject: [PATCH 13/13] Update README.md --- README.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 58bd15c..b24b97c 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Use menubar extra sliders or the keyboard, including native Apple keys!


> [!WARNING] -> MonitorControl v4.2.0 [may crash](https://github.com/MonitorControl/MonitorControl/issues/1663) on certain configurations running macOS 15 Sequoia. Additionally, this version will not automatically update to the [latest app version](https://github.com/MonitorControl/MonitorControl/releases). To resolve the issue and ensure future updates, please upgrade manually. +> MonitorControl v4.2.0 [may crash](https://github.com/MonitorControl/MonitorControl/issues/1663) on certain configurations running macOS 15 Sequoia or Tahoe. Additionally, this version will not automatically update to the [latest app version](https://github.com/MonitorControl/MonitorControl/releases). To resolve the issue and ensure future updates, please upgrade manually. ## Download @@ -47,7 +47,7 @@ brew install --cask monitorcontrol - Support for custom keyboard shortcuts as well as standard brightness and media keys on Apple keyboards. - Dozens of customization options to tweak the inner workings of the app to suit your hardware and needs (don't forget to enable `Show advanced settings` in app Settings). - Simple, unobtrusive UI to blend in to the general aesthetics of macOS. -- **One of the best app of its kind, completely FREE.** +- Completely FREE. For additional features, more advanced brightness control with XDR/HDR brightness upscaling and support for more Mac models and displays, check out [BetterDisplay](https://github.com/waydabber/BetterDisplay#readme)! @@ -81,7 +81,9 @@ For additional features, more advanced brightness control with XDR/HDR brightnes _* With some limitations - full functionality available on macOS 11 Big Sur or newer._ -For macOS Sequoia compatibility [v4.3.2 or newer](https://github.com/MonitorControl/MonitorControl/releases) is required! +For macOS Sequoia and Tahoe 26 compatibility [v4.3.3 or newer](https://github.com/MonitorControl/MonitorControl/releases) is required! + +Please note that current versions have limited native macOS OSD support on macOS Tahoe - although the Control Center brightness or volume OSD appears, the OSD percentage value will not show or update. ### Supported displays @@ -96,17 +98,10 @@ Notable exceptions for hardware control compatibility: - Some displays (notably EIZO) use MCCS over USB or an entirely custom protocol for control. These displays are supported with software dimming only. - DisplayLink docks and dongles do not allow for DDC control on Macs, only software dimming is available for these connections. -Compatibility with - -- f.lux users: please activate `Avoid gamma table manipulation` under `Settings` » `Displays`! This step is not needed if you use Night Shift. -- [BetterDisplay](https://betterdisplay.pro/) users: either activate `Avoid gamma table manipulation` in MonitorControl or turn off `Allow color table adjustments` in BetterDisplay (under Settings/Displays/Overview). You might want to disable native keyboard control either in MonitorControl or BetterDisplay, depending on which app you want to use for brightness control and dimming. - ## Contributing to the project -- You can help out [by contributiong to the project with your one-time donation or by being a regular Sponsor](https://opencollective.com/monitorcontrol)! - If you want, you can fork the code, make improvements and submit a pull request to improve the app. Accepting a PR is solely in the hands of the maintainer - before making fundamental changes expecting it to be accepted, please consult the maintainer of the project! - ## How to build ### Required @@ -135,17 +130,12 @@ git clone https://github.com/MonitorControl/MonitorControl.git - [KeyboardShortcuts](https://github.com/sindresorhus/KeyboardShortcuts) - [Sparkle](https://github.com/sparkle-project/Sparkle) -## Hall of Honor +## Credits -### Current maintainer of the project - -- [@waydabber](https://github.com/waydabber), developer of [BetterDisplay](https://github.com/waydabber/BetterDisplay#readme). - -### Former maintainers, special contributors - -- [@the0neyouseek](https://github.com/the0neyouseek) - previous (now honorary) maintainer -- [@JoniVR](https://github.com/JoniVR) - previous (now honorary) maintainer -- [@alin23](https://github.com/alin23) (generally spearheaded M1 DDC support and figured out a many of the caveats) +- [@waydabber](https://github.com/waydabber), maintainer, developer of [BetterDisplay](https://github.com/waydabber/BetterDisplay#readme). +- [@the0neyouseek](https://github.com/the0neyouseek) - honorary maintainer +- [@JoniVR](https://github.com/JoniVR) - honorary maintainer +- [@alin23](https://github.com/alin23) - spearheaded M1 DDC support, developer of [Lunar](https://lunar.fyi) - [@mathew-kurian](https://github.com/mathew-kurian/) (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))