feat: more fine-grained cursor-follows-focus preference (closes #4734)

This commit is contained in:
lwouis committed 2025-09-15 22:10:41 +02:00
1 parent 3c79840a29
commit 985a681d72
6 files changed
+68 -35

No files matched your search

+6
View File
@@ -286,6 +286,9 @@
/* No comment provided by engineer. */
"Multiple screens" = "Multiple screens";
/* No comment provided by engineer. */
"Never" = "Never";
/* No comment provided by engineer. */
"Never send crash reports" = "Never send crash reports";
@@ -298,6 +301,9 @@
/* No comment provided by engineer. */
"Not allowed" = "Not allowed";
/* No comment provided by engineer. */
"Only on different screen" = "Only on different screen";
/* No comment provided by engineer. */
"Open Accessibility Preferences…" = "Open Accessibility Preferences…";
+14
View File
@@ -437,6 +437,20 @@ enum ShowAppsOrWindowsPreference: CaseIterable, MacroPreference {
}
}
enum CursorFollowFocus: CaseIterable, MacroPreference {
case never
case always
case differentScreen
var localizedString: LocalizedString {
switch self {
case .never: return NSLocalizedString("Never", comment: "")
case .always: return NSLocalizedString("Always", comment: "")
case .differentScreen: return NSLocalizedString("Only on different screen", comment: "")
}
}
}
enum ShowTitlesPreference: CaseIterable, MacroPreference {
case windowTitle
case appName
+2 -2
View File
@@ -23,7 +23,7 @@ class Preferences {
"arrowKeysEnabled": "true",
"vimKeysEnabled": "false",
"mouseHoverEnabled": "false",
"cursorFollowFocusEnabled": "false",
"cursorFollowFocus": CursorFollowFocus.never.indexAsString,
"showMinimizedWindows": ShowHowPreference.show.indexAsString,
"showMinimizedWindows2": ShowHowPreference.show.indexAsString,
"showMinimizedWindows3": ShowHowPreference.show.indexAsString,
@@ -110,7 +110,7 @@ class Preferences {
// periphery:ignore
static var vimKeysEnabled: Bool { CachedUserDefaults.bool("vimKeysEnabled") }
static var mouseHoverEnabled: Bool { CachedUserDefaults.bool("mouseHoverEnabled") }
static var cursorFollowFocusEnabled: Bool { CachedUserDefaults.bool("cursorFollowFocusEnabled") }
static var cursorFollowFocus: CursorFollowFocus { CachedUserDefaults.macroPref("cursorFollowFocus", CursorFollowFocus.allCases) }
static var showTabsAsWindows: Bool { CachedUserDefaults.bool("showTabsAsWindows") }
static var hideColoredCircles: Bool { CachedUserDefaults.bool("hideColoredCircles") }
static var windowDisplayDelay: DispatchTimeInterval { DispatchTimeInterval.milliseconds(CachedUserDefaults.int("windowDisplayDelay")) }
+43 -31
View File
@@ -20,37 +20,40 @@ class PreferencesMigrations {
private static func updateToNewPreferences(_ versionInPlist: String) {
// x.compare(y) is .orderedDescending if x > y
if versionInPlist.compare("7.26.0", options: .numeric) != .orderedDescending {
migrateShowWindowlessApps()
if versionInPlist.compare("7.25.0", options: .numeric) != .orderedDescending {
migrateHideWindowlessApps()
if versionInPlist.compare("7.13.1", options: .numeric) != .orderedDescending {
migrateGestures()
if versionInPlist.compare("7.8.0", options: .numeric) != .orderedDescending {
migrateMenubarIconWithNewShownToggle()
if versionInPlist.compare("7.0.0", options: .numeric) != .orderedDescending {
migratePreferencesIndexes()
if versionInPlist.compare("6.43.0", options: .numeric) != .orderedDescending {
migrateBlacklists()
if versionInPlist.compare("6.28.1", options: .numeric) != .orderedDescending {
migrateMinMaxWindowsWidthInRow()
if versionInPlist.compare("6.27.1", options: .numeric) != .orderedDescending {
// "Start at login" new implem doesn't use Login Items; we remove the entry from previous versions
(PreferencesMigrations.self as AvoidDeprecationWarnings.Type).migrateLoginItem()
if versionInPlist.compare("6.23.0", options: .numeric) != .orderedDescending {
// "Show windows from:" got the "Active Space" option removed
migrateShowWindowsFrom()
if versionInPlist.compare("6.18.1", options: .numeric) != .orderedDescending {
// nextWindowShortcut used to be able to have modifiers already present in holdShortcut; we remove these
migrateNextWindowShortcuts()
// dropdowns preferences used to store English text; now they store indexes
migrateDropdownsFromTextToIndexes()
// the "Hide menubar icon" checkbox was replaced with a dropdown of: icon1, icon2, hidden
migrateMenubarIconFromCheckboxToDropdown()
// "Show minimized/hidden/fullscreen windows" checkboxes were replaced with dropdowns
migrateShowWindowsCheckboxToDropdown()
// "Max size on screen" was split into max width and max height
migrateMaxSizeOnScreenToWidthAndHeight()
if versionInPlist.compare("7.27.0", options: .numeric) != .orderedDescending {
migrateCursorFollowFocus()
if versionInPlist.compare("7.26.0", options: .numeric) != .orderedDescending {
migrateShowWindowlessApps()
if versionInPlist.compare("7.25.0", options: .numeric) != .orderedDescending {
migrateHideWindowlessApps()
if versionInPlist.compare("7.13.1", options: .numeric) != .orderedDescending {
migrateGestures()
if versionInPlist.compare("7.8.0", options: .numeric) != .orderedDescending {
migrateMenubarIconWithNewShownToggle()
if versionInPlist.compare("7.0.0", options: .numeric) != .orderedDescending {
migratePreferencesIndexes()
if versionInPlist.compare("6.43.0", options: .numeric) != .orderedDescending {
migrateBlacklists()
if versionInPlist.compare("6.28.1", options: .numeric) != .orderedDescending {
migrateMinMaxWindowsWidthInRow()
if versionInPlist.compare("6.27.1", options: .numeric) != .orderedDescending {
// "Start at login" new implem doesn't use Login Items; we remove the entry from previous versions
(PreferencesMigrations.self as AvoidDeprecationWarnings.Type).migrateLoginItem()
if versionInPlist.compare("6.23.0", options: .numeric) != .orderedDescending {
// "Show windows from:" got the "Active Space" option removed
migrateShowWindowsFrom()
if versionInPlist.compare("6.18.1", options: .numeric) != .orderedDescending {
// nextWindowShortcut used to be able to have modifiers already present in holdShortcut; we remove these
migrateNextWindowShortcuts()
// dropdowns preferences used to store English text; now they store indexes
migrateDropdownsFromTextToIndexes()
// the "Hide menubar icon" checkbox was replaced with a dropdown of: icon1, icon2, hidden
migrateMenubarIconFromCheckboxToDropdown()
// "Show minimized/hidden/fullscreen windows" checkboxes were replaced with dropdowns
migrateShowWindowsCheckboxToDropdown()
// "Max size on screen" was split into max width and max height
migrateMaxSizeOnScreenToWidthAndHeight()
}
}
}
}
@@ -63,6 +66,15 @@ class PreferencesMigrations {
}
}
// cursorFollowFocus was a toggle. It's now a dropdown
// before: cursorFollowFocusEnabled: true/false
// after: cursorFollowFocus: 0 (never), 1 (always), 2 (differentScreen)
private static func migrateCursorFollowFocus() {
if let old = UserDefaults.standard.string(forKey: "cursorFollowFocusEnabled") {
UserDefaults.standard.set(old == "true" ? 1 : 0, forKey: "cursorFollowFocus")
}
}
// allow showWindowlessApps to have the third value `show`, in addition to `hide` and `showAtTheEnd`
// before: showAtTheEnd: 0, hide: 1
// after: show: 0, hide: 1, showAtTheEnd: 2
+2 -1
View File
@@ -189,7 +189,8 @@ class App: AppCenterApplication {
hideUi(true)
if let window = selectedWindow, MissionControl.state() == .inactive || MissionControl.state() == .showDesktop {
window.focus()
if Preferences.cursorFollowFocusEnabled {
if Preferences.cursorFollowFocus == .always || (
Preferences.cursorFollowFocus == .differentScreen && (Spaces.screenSpacesMap.first { $0.value.contains { space in window.spaceIds.contains(space) } })?.key != NSScreen.active()?.uuid()) {
moveCursorToSelectedWindow(window)
}
} else {
@@ -9,7 +9,7 @@ class AdditionalControlsSheet: SheetWindow {
let enableMouse = TableGroupView.Row(leftTitle: NSLocalizedString("Select windows on mouse hover", comment: ""),
rightViews: [LabelAndControl.makeSwitch("mouseHoverEnabled")])
let enableCursorFollowFocus = TableGroupView.Row(leftTitle: NSLocalizedString("Cursor follows focus", comment: ""),
rightViews: [LabelAndControl.makeSwitch("cursorFollowFocusEnabled")])
rightViews: [LabelAndControl.makeDropdown("cursorFollowFocus", CursorFollowFocus.allCases)])
ControlsTab.arrowKeysCheckbox = enableArrows.rightViews[0] as? Switch
ControlsTab.vimKeysCheckbox = enableVimKeys.rightViews[0] as? Switch
ControlsTab.arrowKeysEnabledCallback(ControlsTab.arrowKeysCheckbox)