feat: can pass the --logs= flags at launch to show logs

This commit is contained in:
lwouis committed 2024-11-10 13:10:20 +01:00
1 parent f7de2bb6d9
commit 81eb07ee98
17 files changed
+139 -131

No files matched your search

+20 -8
View File
@@ -22,7 +22,7 @@
1C96132D9BFCC988B0013509 /* app_icons_show_running_applications_windows_light@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1C961334F059C39979BEDF19 /* app_icons_show_running_applications_windows_light@2x.jpg */; };
1C961383737C00845E881EA6 /* thumbnails_show_app_badges_light@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1C9617A90991E963760F7475 /* thumbnails_show_app_badges_light@2x.jpg */; };
1C9614261DF293C650675A6C /* titles_hide_tabs_as_windows_light@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1C9619DEB8B7905DBF9A6030 /* titles_hide_tabs_as_windows_light@2x.jpg */; };
1C96143D5AD69C894A4D8375 /* LogManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C96110EB5B28C814DA35465 /* LogManager.swift */; };
1C96143D5AD69C894A4D8375 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C96110EB5B28C814DA35465 /* Logger.swift */; };
1C96149CFE6DB491DCAEA943 /* titles_light@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1C961B26B70C826BBD762AC5 /* titles_light@2x.jpg */; };
1C9614C924F2EEB592314C67 /* app_icons_show_running_windows_light@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1C96127120349FE18C5C39DA /* app_icons_show_running_windows_light@2x.jpg */; };
1C9614D96191FACFACD38055 /* thumbnails_align_thumbnails_center_light@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1C9610071E9F3434C893DC95 /* thumbnails_align_thumbnails_center_light@2x.jpg */; };
@@ -74,6 +74,7 @@
5F706EC32BA448D8004D542D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5F706EC12BA448D8004D542D /* InfoPlist.strings */; };
76D02BB22BFE7C9E0056008D /* Pods_alt_tab_macos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0712B3BEA2B3780398C0999 /* Pods_alt_tab_macos.framework */; };
AA974BA929B7D84C0099A29E /* PreviewPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA974BA829B7D84C0099A29E /* PreviewPanel.swift */; };
BF0C80484AA63306D0DB4DB2 /* SpacesEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0C8DF008F1EB5F23291A13 /* SpacesEvents.swift */; };
BF0C8052AE41B1B10E42BFCE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C875C983226CB16DBD90F /* InfoPlist.strings */; };
BF0C8053A58DFB383A3E3351 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C8E237569FA2A8FE20707 /* InfoPlist.strings */; };
BF0C807D26E465F467B066F7 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C849EBA5A547912BD8BB9 /* Localizable.strings */; };
@@ -84,6 +85,7 @@
BF0C81A79128CF877FE895CC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C8A48BBB3BF649864DB08 /* InfoPlist.strings */; };
BF0C81B64A1205F066AC796A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C80404D3455D496C02F29 /* Localizable.strings */; };
BF0C81D836A8A4CA393B135F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C82E55127D38ABF969CA0 /* InfoPlist.strings */; };
BF0C8203D0EFEDEED0F908E8 /* ScreensEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0C822D3BEDAB1F1C9F775E /* ScreensEvents.swift */; };
BF0C820C6E89C2D90FA30A4B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C8F67ABD271F26FA0EDEF /* Localizable.strings */; };
BF0C8224CFD1ED511F3F0063 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C8D94228D90FE99D4A3C8 /* Localizable.strings */; };
BF0C823630E3DEAC576FAFE6 /* menubar-1@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BF0C88BF67CF4D71002A60EB /* menubar-1@2x.png */; };
@@ -120,6 +122,7 @@
BF0C898511686611E4D7D81E /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0C8B2C057099EDABE46779 /* Button.swift */; };
BF0C89C49CFBAAB4646BB8CB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C82A8848224E76B880A83 /* InfoPlist.strings */; };
BF0C89F0632E0A2EC52D9168 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C87749F1A64E2D3305181 /* InfoPlist.strings */; };
BF0C8A3F32B2177AF407DC7E /* DockEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0C870C14C20C936BA4AF40 /* DockEvents.swift */; };
BF0C8A739A74695E60F16369 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C8062E78677398A4A217B /* InfoPlist.strings */; };
BF0C8A95AAD9DADC95887A2D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C895A9AF79A869EE6B108 /* Localizable.strings */; };
BF0C8AC57CE5E9BBEEE2442A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BF0C885D34CDCE2AFC5A94F7 /* InfoPlist.strings */; };
@@ -160,7 +163,7 @@
D04BA15A1B0C4871EA7CB899 /* GeneralTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BACE22DC907F03D193075 /* GeneralTab.swift */; };
D04BA1621718FF26F8D5E75D /* CustomRecorderControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE333F7170E87C5AC0EF /* CustomRecorderControl.swift */; };
D04BA1637E125D38546C26E2 /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA8AC77465E1B2BC947CF /* StackView.swift */; };
D04BA1766FBCB2E941D081A5 /* WorkspaceEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA76AEE37D6656EB80126 /* WorkspaceEvents.swift */; };
D04BA1766FBCB2E941D081A5 /* RunningApplicationsEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA76AEE37D6656EB80126 /* RunningApplicationsEvents.swift */; };
D04BA1B133D53572D7B312C2 /* ThumbnailFontIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA1DF8CAB2FAB7FE9244B /* ThumbnailFontIconView.swift */; };
D04BA1C85041FB043FD43E65 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA05006D56C7AA011C0CE /* Localizable.strings */; };
D04BA1CEC6B9C8945FEC8740 /* ThumbnailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA258B56193958D60978A /* ThumbnailView.swift */; };
@@ -254,7 +257,7 @@
1C961093FB75180759EC6972 /* app_icons_hide_app_badges_light@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "app_icons_hide_app_badges_light@2x.jpg"; sourceTree = "<group>"; };
1C9610B2E76F1E429C8D3660 /* titles_show_running_windows_light@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "titles_show_running_windows_light@2x.jpg"; sourceTree = "<group>"; };
1C9611039BDBE0C84F349BA1 /* titles_show_status_icons_light@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "titles_show_status_icons_light@2x.jpg"; sourceTree = "<group>"; };
1C96110EB5B28C814DA35465 /* LogManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogManager.swift; sourceTree = "<group>"; };
1C96110EB5B28C814DA35465 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
1C96112432E87D36F90AFBED /* translate_i18n_tools.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = translate_i18n_tools.py; sourceTree = "<group>"; };
1C9611334B667767A4514B57 /* thumbnails_hide_space_number_labels_light@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "thumbnails_hide_space_number_labels_light@2x.jpg"; sourceTree = "<group>"; };
1C961139B16ADE6E0B8A33A6 /* thumbnails_show_running_applications_windows_light@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "thumbnails_show_running_applications_windows_light@2x.jpg"; sourceTree = "<group>"; };
@@ -333,6 +336,7 @@
BF0C816F38751995E4F49BB0 /* he */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = he; path = InfoPlist.strings; sourceTree = "<group>"; };
BF0C817E063D1405392D6C5B /* he */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = he; path = Localizable.strings; sourceTree = "<group>"; };
BF0C81D602ED642A48D50B78 /* notarytool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = notarytool; sourceTree = "<group>"; };
BF0C822D3BEDAB1F1C9F775E /* ScreensEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreensEvents.swift; sourceTree = "<group>"; };
BF0C828AF7BCC4F47E70B28F /* menubar-2.svg */ = {isa = PBXFileReference; lastKnownFileType = file.svg; path = "menubar-2.svg"; sourceTree = "<group>"; };
BF0C82C381FCBCF8109735AC /* pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = pl; path = InfoPlist.strings; sourceTree = "<group>"; };
BF0C82D44C2DFAA5D8F60394 /* sq */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sq; path = Localizable.strings; sourceTree = "<group>"; };
@@ -360,6 +364,7 @@
BF0C864F182B6155A66D241D /* KeyRepeatTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyRepeatTimer.swift; sourceTree = "<group>"; };
BF0C86C2BB70A8E05D2103CA /* cs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = cs; path = Localizable.strings; sourceTree = "<group>"; };
BF0C86E06A44AC151FEA4903 /* sv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sv; path = InfoPlist.strings; sourceTree = "<group>"; };
BF0C870C14C20C936BA4AF40 /* DockEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DockEvents.swift; sourceTree = "<group>"; };
BF0C87320241EAE01E38EF53 /* .periphery.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.yaml; path = .periphery.yml; sourceTree = "<group>"; };
BF0C87897C24638DDE4A9889 /* app-icons-style.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "app-icons-style.jpg"; sourceTree = "<group>"; };
BF0C87B913292EE53EDE4220 /* menubar-1.svg */ = {isa = PBXFileReference; lastKnownFileType = file.svg; path = "menubar-1.svg"; sourceTree = "<group>"; };
@@ -411,6 +416,7 @@
BF0C8D7DE89E594FEE6DA692 /* ta */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ta; path = Localizable.strings; sourceTree = "<group>"; };
BF0C8D87C20B7308B16498B6 /* et */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = et; path = InfoPlist.strings; sourceTree = "<group>"; };
BF0C8D9E024876AD9A92BE8D /* sr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sr; path = Localizable.strings; sourceTree = "<group>"; };
BF0C8DF008F1EB5F23291A13 /* SpacesEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpacesEvents.swift; sourceTree = "<group>"; };
BF0C8DF400A1AF64EB0CD0B3 /* TrafficLightButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrafficLightButton.swift; sourceTree = "<group>"; };
BF0C8E1FBCBC7B64C69D933C /* titles-style-full.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "titles-style-full.jpg"; sourceTree = "<group>"; };
BF0C8E25373671B528AD448D /* screen-recording@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "screen-recording@2x.png"; sourceTree = "<group>"; };
@@ -509,7 +515,7 @@
D04BA72AC9B57A1673C28B2E /* android-chrome-256x256.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "android-chrome-256x256.png"; sourceTree = "<group>"; };
D04BA7457E30F608E139B695 /* zh-TW */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = Localizable.strings; sourceTree = "<group>"; };
D04BA765138B5E1C512245BE /* Thanks.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Thanks.md; sourceTree = "<group>"; };
D04BA76AEE37D6656EB80126 /* WorkspaceEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WorkspaceEvents.swift; sourceTree = "<group>"; };
D04BA76AEE37D6656EB80126 /* RunningApplicationsEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RunningApplicationsEvents.swift; sourceTree = "<group>"; };
D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AcknowledgmentsTab.swift; sourceTree = "<group>"; };
D04BA7957E5E02FB09BCE10C /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = de; path = InfoPlist.strings; sourceTree = "<group>"; };
D04BA7A758026814667273DC /* convert_iconset_to_icns.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = convert_iconset_to_icns.sh; sourceTree = "<group>"; };
@@ -1171,7 +1177,7 @@
D04BA1C271F0DA573345B860 /* permission-window */,
D04BAAF79737A0673502FEB5 /* AppCenterApplication.h */,
D04BA48BC82D3060C3A1AB11 /* AppCenterApplication.m */,
1C96110EB5B28C814DA35465 /* LogManager.swift */,
1C96110EB5B28C814DA35465 /* Logger.swift */,
);
path = ui;
sourceTree = "<group>";
@@ -1643,9 +1649,12 @@
children = (
D04BA8FDCF137D892114F5F3 /* AccessibilityEvents.swift */,
D04BA4A621A8A15660F973C1 /* KeyboardEvents.swift */,
D04BA76AEE37D6656EB80126 /* WorkspaceEvents.swift */,
D04BA76AEE37D6656EB80126 /* RunningApplicationsEvents.swift */,
D04BA5D9B4EBEB9E4333AE39 /* UserDefaultsEvents.swift */,
D04BAF320F4D43F0DDFE063E /* MouseEvents.swift */,
BF0C870C14C20C936BA4AF40 /* DockEvents.swift */,
BF0C8DF008F1EB5F23291A13 /* SpacesEvents.swift */,
BF0C822D3BEDAB1F1C9F775E /* ScreensEvents.swift */,
);
path = events;
sourceTree = "<group>";
@@ -2102,7 +2111,7 @@
5F21C9E02C6E94240091F72F /* ShortcutsWhenActiveSheet.swift in Sources */,
D04BAE8B16A06A10E2FA94DE /* AccessibilityEvents.swift in Sources */,
D04BAAAF5CFA991D3B078DB8 /* KeyboardEvents.swift in Sources */,
D04BA1766FBCB2E941D081A5 /* WorkspaceEvents.swift in Sources */,
D04BA1766FBCB2E941D081A5 /* RunningApplicationsEvents.swift in Sources */,
D04BA0AE9865276FF8EF5DEB /* UserDefaultsEvents.swift in Sources */,
D04BA4A11F821548EE3C5E95 /* Bash.swift in Sources */,
5F21C9E62C6E94920091F72F /* AnimationsSheet.swift in Sources */,
@@ -2126,8 +2135,11 @@
BF0C83578F7292F307E30751 /* PopupButtonLikeSystemSettings.swift in Sources */,
1C961F9CF4F1BEDF04ACAEE0 /* Switch.swift in Sources */,
1C96182D2ECA735740ED474E /* ImageTextButtonView.swift in Sources */,
1C96143D5AD69C894A4D8375 /* LogManager.swift in Sources */,
1C96143D5AD69C894A4D8375 /* Logger.swift in Sources */,
BF0C860F1779DDE8C0171EA0 /* WindowlessAppIndicator.swift in Sources */,
BF0C8A3F32B2177AF407DC7E /* DockEvents.swift in Sources */,
BF0C80484AA63306D0DB4DB2 /* SpacesEvents.swift in Sources */,
BF0C8203D0EFEDEED0F908E8 /* ScreensEvents.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -55,6 +55,12 @@
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
<CommandLineArguments>
<CommandLineArgument
argument = "--logs=info"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Debug"
-27
View File
@@ -2,8 +2,6 @@ import Foundation
class MissionControl {
private static var state_ = MissionControlState.inactive
private static var axObserver: AXObserver?
private static var axUiElement: AXUIElement?
static func state() -> MissionControlState {
if #available(macOS 12.0, *) {
@@ -32,29 +30,4 @@ class MissionControl {
}
return false
}
static func observe(_ dockPid: pid_t) {
if #available(macOS 12.0, *) {
axUiElement = AXUIElementCreateApplication(dockPid)
AXObserverCreate(dockPid, axObserverCallbackDock, &axObserver)
// are we sure we always get a non-nil axObserver?
for notification in MissionControlState.allCases {
retryAxCallUntilTimeout {
try axUiElement!.subscribeToNotification(axObserver!, notification.rawValue, nil)
}
}
CFRunLoopAddSource(BackgroundWork.missionControlThread.runLoop, AXObserverGetRunLoopSource(axObserver!), .defaultMode)
} else {
// we could handle macOS < 12 here like yabai does. However, they poll with ax calls until they notice Mission Control stops
// this takes up ressources when Mission Control is open. If the user keeps it open for a few hours, this would accelerate battery usage
// SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 1204, NULL);
// then listen every 0.1f * NSEC_PER_SEC for layer == 18 and owner = "Dock"
// when found, mission control is not active anymore
}
}
}
fileprivate let axObserverCallbackDock: AXObserverCallback = { _, element, notificationName, _ in
logger.d(notificationName, element)
MissionControl.setState(MissionControlState(rawValue: notificationName as String)!)
}
+2 -2
View File
@@ -40,7 +40,7 @@ class Application: NSObject {
}
deinit {
logger.i("Deinit app", runningApplication.bundleIdentifier ?? runningApplication.bundleURL ?? "nil")
logger.d("Deinit app", runningApplication.bundleIdentifier ?? runningApplication.bundleURL ?? "nil")
}
override var description: String {
@@ -73,7 +73,7 @@ class Application: NSObject {
if runningApplication.activationPolicy != .prohibited && axUiElement == nil {
axUiElement = AXUIElementCreateApplication(pid)
AXObserverCreate(pid, axObserverCallback, &axObserver)
logger.i("Adding app", pid ?? "nil", runningApplication.bundleIdentifier ?? "nil")
logger.d("Adding app", pid ?? "nil", runningApplication.bundleIdentifier ?? "nil")
observeEvents()
}
}
+3 -3
View File
@@ -21,7 +21,7 @@ class Applications {
static func initialDiscovery() {
addInitialRunningApplications()
addInitialRunningApplicationsWindows()
WorkspaceEvents.observeRunningApplications()
RunningApplicationsEvents.observe()
}
static func addInitialRunningApplications() {
@@ -48,7 +48,7 @@ class Applications {
static func addRunningApplications(_ runningApps: [NSRunningApplication]) {
runningApps.forEach {
if $0.bundleIdentifier == "com.apple.dock" {
MissionControl.observe($0.processIdentifier)
DockEvents.observe($0.processIdentifier)
}
if isActualApplication($0) {
Applications.list.append(Application($0))
@@ -68,7 +68,7 @@ class Applications {
}
Windows.list.removeAll { $0.application.runningApplication.isEqual(runningApp) }
}
guard Windows.list.count > 0 else { App.app.hideUi(); return }
if Windows.list.count == 0 { App.app.hideUi(); return }
if windowsOnTheLeftOfFocusedWindow > 0 {
Windows.cycleFocusedWindowIndex(-windowsOnTheLeftOfFocusedWindow)
}
+2 -22
View File
@@ -7,25 +7,6 @@ class Spaces {
static var screenSpacesMap = [ScreenUuid: [CGSSpaceID]]()
static var idsAndIndexes = [(CGSSpaceID, SpaceIndex)]()
static func observeSpaceChanges() {
NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.activeSpaceDidChangeNotification, object: nil, queue: nil, using: { _ in
logger.i("OS event", "activeSpaceDidChangeNotification")
refreshAllIdsAndIndexes()
updateCurrentSpace()
// if UI was kept open during Space transition, the Spaces may be obsolete; we refresh them
Windows.list.forEachAsync { $0.updatesWindowSpace() }
// from macos 12.2 beta onwards, we can't get other-space windows; grabbing windows when switching spaces mitigates the issue
// also, updating windows on Space transition works around an issue with Safari where its fullscreen windows spawn not in fullscreen.
// resize/move events happen and the window is still not fullscreen. AltTab doesn't get informed that the window is later fullscreen.
// updating on Space change helps correct the window to being fullscreen
Applications.manuallyUpdateWindows()
})
NSWorkspace.shared.notificationCenter.addObserver(forName: NSApplication.didChangeScreenParametersNotification, object: nil, queue: nil, using: { _ in
logger.i("OS event", "didChangeScreenParametersNotification")
refreshAllIdsAndIndexes()
})
}
static func refreshCurrentSpaceId() {
// it seems that in some rare scenarios, some of these values are nil; we wrap to avoid crashing
if let mainScreen = NSScreen.main,
@@ -34,10 +15,9 @@ class Spaces {
}
}
static func initialDiscovery() {
static func initialize() {
refreshAllIdsAndIndexes()
updateCurrentSpace()
observeSpaceChanges()
}
static func updateCurrentSpace() {
@@ -45,7 +25,7 @@ class Spaces {
currentSpaceIndex = idsAndIndexes.first { (spaceId: CGSSpaceID, _) -> Bool in
spaceId == currentSpaceId
}?.1 ?? SpaceIndex(1)
logger.i("Current Space", currentSpaceId)
logger.i(currentSpaceIndex, currentSpaceId)
}
static func refreshAllIdsAndIndexes() -> Void {
+3 -3
View File
@@ -54,7 +54,7 @@ class Window: CustomStringConvertible {
}
application.removeWindowslessAppWindow()
checkIfFocused(application, wid)
logger.i("Adding window", cgWindowId ?? "nil", title ?? "nil", application.runningApplication.bundleIdentifier ?? "nil")
logger.d("Adding window", cgWindowId ?? "nil", title ?? "nil", application.runningApplication.bundleIdentifier ?? "nil")
observeEvents()
}
@@ -64,11 +64,11 @@ class Window: CustomStringConvertible {
self.title = application.runningApplication.localizedName
Window.globalCreationCounter += 1
self.creationOrder = Window.globalCreationCounter
logger.i("Adding app-window", title ?? "nil", application.runningApplication.bundleIdentifier ?? "nil")
logger.d(title ?? "nil", application.runningApplication.bundleIdentifier ?? "nil")
}
deinit {
logger.i("Deinit window", title ?? "nil", application.runningApplication.bundleIdentifier ?? "nil")
logger.d(title ?? "nil", application.runningApplication.bundleIdentifier ?? "nil")
}
var description: String {
+1 -1
View File
@@ -8,10 +8,10 @@ let axObserverCallback: AXObserverCallback = { _, element, notificationName, _ i
}
fileprivate func handleEvent(_ type: String, _ element: AXUIElement) throws {
logger.i("Accessibility event", type, try element.title() ?? "nil")
// events are handled concurrently, thus we check that the app is still running
if let pid = try element.pid(),
try pid != ProcessInfo.processInfo.processIdentifier || (element.subrole() != kAXUnknownSubrole) {
logger.d(type, pid, try element.title() ?? "nil")
switch type {
case kAXApplicationActivatedNotification: try applicationActivated(element, pid)
case kAXApplicationHiddenNotification,
+31
View File
@@ -0,0 +1,31 @@
import Foundation
class DockEvents {
private static var axObserver: AXObserver?
private static var axUiElement: AXUIElement?
static func observe(_ dockPid: pid_t) {
if #available(macOS 12.0, *) {
axUiElement = AXUIElementCreateApplication(dockPid)
AXObserverCreate(dockPid, handleEvent, &axObserver)
// are we sure we always get a non-nil axObserver?
for notification in MissionControlState.allCases {
retryAxCallUntilTimeout {
try axUiElement!.subscribeToNotification(axObserver!, notification.rawValue, nil)
}
}
CFRunLoopAddSource(BackgroundWork.missionControlThread.runLoop, AXObserverGetRunLoopSource(axObserver!), .defaultMode)
} else {
// we could handle macOS < 12 here like yabai does. However, they poll with ax calls until they notice Mission Control stops
// this takes up ressources when Mission Control is open. If the user keeps it open for a few hours, this would accelerate battery usage
// SLSRegisterConnectionNotifyProc(g_connection, connection_handler, 1204, NULL);
// then listen every 0.1f * NSEC_PER_SEC for layer == 18 and owner = "Dock"
// when found, mission control is not active anymore
}
}
}
fileprivate let handleEvent: AXObserverCallback = { _, element, notificationName, _ in
logger.d(notificationName, element)
MissionControl.setState(MissionControlState(rawValue: notificationName as String)!)
}
+2 -2
View File
@@ -26,7 +26,7 @@ private func observe_() {
place: .headInsertEventTap,
options: .defaultTap,
eventsOfInterest: eventMask,
callback: mouseHandler,
callback: handleEvent,
userInfo: nil)
if let eventTap = eventTap {
MouseEvents.toggle(false)
@@ -37,7 +37,7 @@ private func observe_() {
}
}
private let mouseHandler: CGEventTapCallBack = {_, type, cgEvent, _ in
private let handleEvent: CGEventTapCallBack = { _, type, cgEvent, _ in
if type == .leftMouseDown {
isPointerInsideUi_()
if !isPointerInsideUi {
@@ -1,23 +1,22 @@
import Cocoa
class WorkspaceEvents {
class RunningApplicationsEvents {
private static var appsObserver: NSKeyValueObservation!
private static var previousValueOfRunningApps: Set<NSRunningApplication>!
static func observeRunningApplications() {
static func observe() {
previousValueOfRunningApps = Set(NSWorkspace.shared.runningApplications)
appsObserver = NSWorkspace.shared.observe(\.runningApplications, options: [.old, .new], changeHandler: observerCallback)
appsObserver = NSWorkspace.shared.observe(\.runningApplications, options: [.old, .new], changeHandler: handleEvent)
}
static func observerCallback<A>(_: NSWorkspace, _ change: NSKeyValueObservedChange<A>) {
static func handleEvent<A>(_: NSWorkspace, _ change: NSKeyValueObservedChange<A>) {
let workspaceApps = Set(NSWorkspace.shared.runningApplications)
// TODO: symmetricDifference has bad performance
let diff = Array(workspaceApps.symmetricDifference(previousValueOfRunningApps))
logger.d(change.kind, diff.map { ($0.processIdentifier, $0.bundleIdentifier) })
if change.kind == .insertion {
logger.i("OS event", "apps launched", diff.map { ($0.processIdentifier, $0.bundleIdentifier) })
Applications.addRunningApplications(diff)
} else if change.kind == .removal {
logger.i("OS event", "apps quit", diff.map { ($0.processIdentifier, $0.bundleIdentifier) })
Applications.removeRunningApplications(diff)
}
previousValueOfRunningApps = workspaceApps
+10
View File
@@ -0,0 +1,10 @@
import Cocoa
class ScreensEvents {
static func observe() {
NSWorkspace.shared.notificationCenter.addObserver(forName: NSApplication.didChangeScreenParametersNotification, object: nil, queue: nil, using: { notification in
logger.i(notification.name, NSScreen.screens.map { ($0.uuid(), $0.frame) })
Spaces.refreshAllIdsAndIndexes()
})
}
}
+18
View File
@@ -0,0 +1,18 @@
import Cocoa
class SpacesEvents {
static func observe() {
NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.activeSpaceDidChangeNotification, object: nil, queue: nil, using: { notification in
logger.d(notification.name)
Spaces.refreshAllIdsAndIndexes()
Spaces.updateCurrentSpace()
// if UI was kept open during Space transition, the Spaces may be obsolete; we refresh them
Windows.list.forEachAsync { $0.updatesWindowSpace() }
// from macos 12.2 beta onwards, we can't get other-space windows; grabbing windows when switching spaces mitigates the issue
// also, updating windows on Space transition works around an issue with Safari where its fullscreen windows spawn not in fullscreen.
// resize/move events happen and the window is still not fullscreen. AltTab doesn't get informed that the window is later fullscreen.
// updating on Space change helps correct the window to being fullscreen
Applications.manuallyUpdateWindows()
})
}
}
@@ -10,6 +10,11 @@ class UserDefaultsEvents: NSObject {
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
handleEvent(keyPath)
}
private func handleEvent(_ keyPath: String?) {
logger.d(keyPath, PoliciesTab.policyLock, Preferences.updatePolicy)
guard !PoliciesTab.policyLock else { return }
let buttons = PoliciesTab.updatesPolicyDropdown!
let id = buttonIdToUpdate()
+9 -5
View File
@@ -50,7 +50,7 @@ class App: AppCenterApplication, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
appCenterDelegate = AppCenterCrash()
App.shared.disableRelaunchOnLogin()
LogManager.setup()
Logger.initialize()
#if DEBUG
UserDefaults.standard.set(true, forKey: "NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints")
#endif
@@ -69,7 +69,9 @@ class App: AppCenterApplication, NSApplicationDelegate {
self.loadMainMenuXib()
self.thumbnailsPanel = ThumbnailsPanel()
self.previewPanel = PreviewPanel()
Spaces.initialDiscovery()
Spaces.initialize()
SpacesEvents.observe()
ScreensEvents.observe()
Applications.initialDiscovery()
self.preferencesWindow = PreferencesWindow()
self.feedbackWindow = FeedbackWindow()
@@ -122,7 +124,8 @@ class App: AppCenterApplication, NSApplicationDelegate {
}
func hideUi(_ keepPreview: Bool = false) {
logger.i("hideUi")
logger.i()
if appIsBeingUsed == false { return } // already hidden
appIsBeingUsed = false
isFirstSummon = true
MouseEvents.toggle(false)
@@ -171,8 +174,9 @@ class App: AppCenterApplication, NSApplicationDelegate {
}
func focusTarget() {
logger.i("focusTarget")
focusSelectedWindow(Windows.focusedWindow())
let focusedWindow = Windows.focusedWindow()
logger.i(focusedWindow ?? "nil")
focusSelectedWindow(focusedWindow)
}
@objc func checkForUpdatesNow(_ sender: NSMenuItem) {
+21 -51
View File
@@ -3,68 +3,38 @@ import Foundation
let logger = SwiftyBeaver.self
class LogManager {
private static let maxDays = 1 // Set maximum log retention days
private static var timer: Timer?
class Logger {
static let flag = "--logs="
static func setup() {
setupLogger()
if ((logger.destinations.first { $0 is FileDestination } as? FileDestination)?.logFileURL != nil) {
startLogFileCleanupTimer()
}
}
private static func setupLogger() {
let format = "$Dyyyy-MM-dd HH:mm:ss.SSS$d $C$L$c $N.swift:$l $F - $M"
static func initialize() {
let console = ConsoleDestination()
console.format = format
let file = FileDestination()
file.format = format
#if DEBUG
console.minLevel = .verbose
file.minLevel = .verbose
console.useTerminalColors = true
console.levelString.verbose = "VERB"
console.levelString.debug = "DEBG"
console.levelString.info = "INFO"
console.levelString.warning = "WARN"
console.levelString.error = "ERRO"
console.format = "$C$DHH:mm:ss$d $L$c $N.swift:$l $F $M"
console.minLevel = decideLevel()
logger.addDestination(console)
logger.addDestination(file)
#else
console.minLevel = .error
file.minLevel = .error
// logger.addDestination(console)
// logger.addDestination(file)
#endif
if let logFileURL = file.logFileURL {
logger.info("Default log file path: \(logFileURL.path)")
}
}
private static func startLogFileCleanupTimer() {
// Schedule a timer to run every 24 hours to clean up log files
timer = Timer.scheduledTimer(timeInterval: 86400, target: self, selector: #selector(cleanupLogFiles), userInfo: nil, repeats: true)
// Set tolerance to save battery
timer?.tolerance = 3600
}
@objc private static func cleanupLogFiles() {
guard let fileDestination = logger.destinations.first(where: { $0 is FileDestination }) as? FileDestination,
let logFileURL = fileDestination.logFileURL else { return }
let fileManager = FileManager.default
// Get the file attributes to check the creation date
if let attributes = try? fileManager.attributesOfItem(atPath: logFileURL.path),
let creationDate = attributes[.creationDate] as? Date {
// Calculate the expiration date
let expirationDate = Calendar.current.date(byAdding: .day, value: -maxDays, to: Date())
// If the log file is older than the specified retention period, delete it
if creationDate < expirationDate ?? Date() {
fileDestination.deleteLogFile()
static func decideLevel() -> SwiftyBeaver.Level {
if let level = CommandLine.arguments.first { $0.starts(with: flag) }?.substring(from: flag.endIndex) {
switch level {
case "verbose": return .verbose
case "debug": return .debug
case "info": return .info
case "warning": return .warning
case "error": return .error
default: break
}
}
return .error
}
}
extension SwiftyBeaver {
class func isVerboseEnabled() -> Bool {
return isEnabled(level: .verbose)
}
@@ -25,7 +25,7 @@ class PermissionsWindow: NSWindow, NSWindowDelegate {
func windowWillClose(_ notification: Notification) {
logger.d("PermissionsWindow windowWillClose", SystemPermissions.preStartupPermissionsPassed)
logger.d(SystemPermissions.preStartupPermissionsPassed)
if !SystemPermissions.preStartupPermissionsPassed {
if SystemPermissions.accessibilityIsGranted() == .notGranted || SystemPermissions.screenRecordingIsGranted() == .notGranted {
logger.e("Before using this app, you need to give permission in System Preferences > Security & Privacy > Privacy > Accessibility.",