Skip to content

Commit

Permalink
filter out non real windows using alt-tab algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
ShlomoCode committed Jul 18, 2024
1 parent ee19803 commit 84b4b8d
Show file tree
Hide file tree
Showing 10 changed files with 737 additions and 76 deletions.
30 changes: 29 additions & 1 deletion DockDoor.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

/* Begin PBXBuildFile section */
0531F8D22C3CC04600327808 /* AppearanceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0531F8D12C3CC04600327808 /* AppearanceSettingsView.swift */; };
0549E5DD2C48B5E800E3AE8D /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0549E5DC2C48B5E800E3AE8D /* Sysctl.swift */; };
0549E5DF2C48BB9500E3AE8D /* AXUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0549E5DE2C48BB9500E3AE8D /* AXUIElement.swift */; };
0549E5E12C48BBD100E3AE8D /* CGWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0549E5E02C48BBD100E3AE8D /* CGWindow.swift */; };
0549E5E32C48BD8000E3AE8D /* CGWindowID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0549E5E22C48BD8000E3AE8D /* CGWindowID.swift */; };
0549E5E52C48BF4500E3AE8D /* BackgroundWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0549E5E42C48BF4500E3AE8D /* BackgroundWork.swift */; };
0596C2C32C3E060D00DCABEF /* PrivateApis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596C2C22C3E060D00DCABEF /* PrivateApis.swift */; };
05A25B912C3EF28E002AC594 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A25B902C3EF28E002AC594 /* Extensions.swift */; };
3A105FD62C1BED660015EC66 /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A105FD52C1BED660015EC66 /* BlurView.swift */; };
Expand Down Expand Up @@ -52,6 +57,11 @@

/* Begin PBXFileReference section */
0531F8D12C3CC04600327808 /* AppearanceSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsView.swift; sourceTree = "<group>"; };
0549E5DC2C48B5E800E3AE8D /* Sysctl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sysctl.swift; sourceTree = "<group>"; };
0549E5DE2C48BB9500E3AE8D /* AXUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AXUIElement.swift; sourceTree = "<group>"; };
0549E5E02C48BBD100E3AE8D /* CGWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGWindow.swift; sourceTree = "<group>"; };
0549E5E22C48BD8000E3AE8D /* CGWindowID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGWindowID.swift; sourceTree = "<group>"; };
0549E5E42C48BF4500E3AE8D /* BackgroundWork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundWork.swift; sourceTree = "<group>"; };
0596C2C22C3E060D00DCABEF /* PrivateApis.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateApis.swift; sourceTree = "<group>"; };
05A25B902C3EF28E002AC594 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
3A105FD52C1BED660015EC66 /* BlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -109,6 +119,18 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
0549E5E62C48C36100E3AE8D /* api-wrappers */ = {
isa = PBXGroup;
children = (
0596C2C22C3E060D00DCABEF /* PrivateApis.swift */,
0549E5DC2C48B5E800E3AE8D /* Sysctl.swift */,
0549E5DE2C48BB9500E3AE8D /* AXUIElement.swift */,
0549E5E02C48BBD100E3AE8D /* CGWindow.swift */,
0549E5E22C48BD8000E3AE8D /* CGWindowID.swift */,
);
path = "api-wrappers";
sourceTree = "<group>";
};
3A105FD42C1BED5B0015EC66 /* Components */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -148,6 +170,7 @@
BB157B672C0E31CE00997315 /* DockDoor */ = {
isa = PBXGroup;
children = (
0549E5E62C48C36100E3AE8D /* api-wrappers */,
C119BDF02C2AEDBA00E06E18 /* DockDoorDebug.entitlements */,
BB8247782C2889B20098A440 /* Info.plist */,
BB4ED9062C3C75CA00BBDD16 /* Localizable.xcstrings */,
Expand Down Expand Up @@ -176,7 +199,6 @@
BB157B772C0E32EF00997315 /* Utilities */ = {
isa = PBXGroup;
children = (
0596C2C22C3E060D00DCABEF /* PrivateApis.swift */,
BB2567C52C10C5F000C0C93E /* DockUtils.swift */,
BB157B782C0E330100997315 /* WindowUtil.swift */,
BB157B7A2C0E343000997315 /* SystemPreferencesHelper.swift */,
Expand All @@ -187,6 +209,7 @@
BBE7CC932C225D9700AB8F4D /* App Icon.swift */,
BB7CA33C2C31F1B00012E303 /* WindowClosureObservers.swift */,
05A25B902C3EF28E002AC594 /* Extensions.swift */,
0549E5E42C48BF4500E3AE8D /* BackgroundWork.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -317,15 +340,19 @@
files = (
0531F8D22C3CC04600327808 /* AppearanceSettingsView.swift in Sources */,
BB6A4F1C2C1CFCFF00CB4C9E /* PermissionsSettingsView.swift in Sources */,
0549E5E52C48BF4500E3AE8D /* BackgroundWork.swift in Sources */,
BB3967FD2C291D5A004F1AB6 /* StackedShadow.swift in Sources */,
BBF4139A2C40A64A00AA6733 /* FluidGradient.swift in Sources */,
BB7CA33D2C31F1B00012E303 /* WindowClosureObservers.swift in Sources */,
BB157B802C0E8E6700997315 /* MessageUtil.swift in Sources */,
0549E5E32C48BD8000E3AE8D /* CGWindowID.swift in Sources */,
3A105FD62C1BED660015EC66 /* BlurView.swift in Sources */,
BB1CBD5D2C1BCA4F003969BC /* Misc Utils.swift in Sources */,
05A25B912C3EF28E002AC594 /* Extensions.swift in Sources */,
3A105FD92C1C049E0015EC66 /* dockStyle.swift in Sources */,
BBE7CC942C225D9700AB8F4D /* App Icon.swift in Sources */,
0549E5DF2C48BB9500E3AE8D /* AXUIElement.swift in Sources */,
0549E5DD2C48B5E800E3AE8D /* Sysctl.swift in Sources */,
BB3968022C2A6CC2004F1AB6 /* Marquee.swift in Sources */,
BB157B822C0EB29E00997315 /* DockObserver.swift in Sources */,
BBA153FA2C11FFD500119C02 /* consts.swift in Sources */,
Expand All @@ -337,6 +364,7 @@
3A105FDD2C1C0EE20015EC66 /* DynStack.swift in Sources */,
BB4ED9092C3CD97400BBDD16 /* Traffic Light Buttons.swift in Sources */,
C119BDF22C2AFA7600E06E18 /* WindowSwitcherSettingsView.swift in Sources */,
0549E5E12C48BBD100E3AE8D /* CGWindow.swift in Sources */,
BB2567C62C10C5F000C0C93E /* DockUtils.swift in Sources */,
BBE7CC912C22429A00AB8F4D /* settings.swift in Sources */,
BBF413942C40978400AA6733 /* WindowPreviewHoverContainer.swift in Sources */,
Expand Down
77 changes: 77 additions & 0 deletions DockDoor/Utilities/BackgroundWork.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Foundation

// queues and dedicated threads to observe background events such as keyboard inputs, or accessibility events
class BackgroundWork {
static var mainQueueConcurrentWorkQueue: DispatchQueue!
static var accessibilityCommandsQueue: DispatchQueue!
static var axCallsQueue: DispatchQueue!
static var crashReportsQueue: DispatchQueue!
static var accessibilityEventsThread: BackgroundThreadWithRunLoop!
static var mouseEventsThread: BackgroundThreadWithRunLoop!
static var systemPermissionsThread: BackgroundThreadWithRunLoop!
static var repeatingKeyThread: BackgroundThreadWithRunLoop!

// we cap concurrent tasks to .processorCount to avoid thread explosion on the .global queue
static let globalSemaphore = DispatchSemaphore(value: ProcessInfo.processInfo.processorCount)
// Thread.start() is async; we use a semaphore to ensure threads are actually ready before we continue the launch sequence
static let threadStartSemaphore = DispatchSemaphore(value: 0)

// swift static variables are lazy; we artificially force the threads to init
static func start() {
mainQueueConcurrentWorkQueue = DispatchQueue.globalConcurrent("mainQueueConcurrentWorkQueue", .userInteractive)
accessibilityCommandsQueue = DispatchQueue.globalConcurrent("accessibilityCommandsQueue", .userInteractive)
axCallsQueue = DispatchQueue.globalConcurrent("axCallsQueue", .userInteractive)
crashReportsQueue = DispatchQueue.globalConcurrent("crashReportsQueue", .utility)
accessibilityEventsThread = BackgroundThreadWithRunLoop("accessibilityEventsThread", .userInteractive)
mouseEventsThread = BackgroundThreadWithRunLoop("mouseEventsThread", .userInteractive)
repeatingKeyThread = BackgroundThreadWithRunLoop("repeatingKeyThread", .userInteractive)
}

static func startSystemPermissionThread() {
systemPermissionsThread = BackgroundThreadWithRunLoop("systemPermissionsThread", .utility)
}
}

extension DispatchQueue {
static func globalConcurrent(_ label: String, _ qos: DispatchQoS) -> DispatchQueue {
return DispatchQueue(label: label, attributes: .concurrent, target: .global(qos: qos.qosClass))
}

func asyncWithCap(_ deadline: DispatchTime? = nil, _ fn: @escaping () -> Void) {
let block = {
fn()
BackgroundWork.globalSemaphore.signal()
}
BackgroundWork.globalSemaphore.wait()
if let deadline = deadline {
asyncAfter(deadline: deadline, execute: block)
} else {
async(execute: block)
}
}
}

class BackgroundThreadWithRunLoop {
var thread: Thread?
var runLoop: CFRunLoop?
var hasSentSemaphoreSignal = false

init(_ name: String, _ qos: DispatchQoS) {
thread = Thread {
self.runLoop = CFRunLoopGetCurrent()
while !self.thread!.isCancelled {
if !self.hasSentSemaphoreSignal {
BackgroundWork.threadStartSemaphore.signal()
self.hasSentSemaphoreSignal = true
}
CFRunLoopRun()
// avoid tight loop while waiting for the first runloop source to be added
Thread.sleep(forTimeInterval: 0.1)
}
}
thread!.name = name
thread!.qualityOfService = qos.toQualityOfService()
thread!.start()
BackgroundWork.threadStartSemaphore.wait()
}
}
1 change: 0 additions & 1 deletion DockDoor/Utilities/DockObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ final class DockObserver {
let mouseLocation = event.location
observer.handleMouseEvent(mouseLocation: mouseLocation)
} else if type == .rightMouseDown || type == .leftMouseDown || type == .otherMouseDown {
let mouseLocation = event.location
if observer.getCurrentAppUnderMouse() != nil { // Required to allow clicking the traffic light buttons in the preview
SharedPreviewWindowCoordinator.shared.hideWindow()
}
Expand Down
25 changes: 25 additions & 0 deletions DockDoor/Utilities/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,28 @@ extension Color {
)
}
}

extension pid_t {
func isZombie() -> Bool {
var kinfo = kinfo_proc()
var size = MemoryLayout<kinfo_proc>.stride
var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, self]
sysctl(&mib, u_int(mib.count), &kinfo, &size, nil, 0)
_ = withUnsafePointer(to: &kinfo.kp_proc.p_comm) {
String(cString: UnsafeRawPointer($0).assumingMemoryBound(to: CChar.self))
}
return kinfo.kp_proc.p_stat == SZOMB
}
}

extension DispatchQoS {
func toQualityOfService() -> QualityOfService {
switch self {
case .userInteractive: return .userInteractive
case .userInitiated: return .userInitiated
case .utility: return .utility
case .background: return .background
default: return .default
}
}
}
Loading

0 comments on commit 84b4b8d

Please sign in to comment.