Skip to content

Commit

Permalink
Implement more robust window focus mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
ianyh committed Aug 8, 2023
1 parent 74b618e commit c8a7bdf
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 14 deletions.
26 changes: 12 additions & 14 deletions Amethyst.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
402DB6F21742E41A00D1C936 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 402DB6F01742E41A00D1C936 /* Credits.rtf */; };
402DB6F81742E41A00D1C936 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 402DB6F61742E41A00D1C936 /* MainMenu.xib */; };
402DB6FF1742E44E00D1C936 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 402DB6FE1742E44E00D1C936 /* Carbon.framework */; };
402F6FA62A81C9E30036B512 /* SkyLight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 402F6FA52A81C9E30036B512 /* SkyLight.framework */; };
403E1A2A2337173600DB7B2A /* FloatingLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 403E1A292337173600DB7B2A /* FloatingLayoutTests.swift */; };
403E1A2C233719E500DB7B2A /* TallLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 403E1A2B233719E500DB7B2A /* TallLayoutTests.swift */; };
4045416F268FFDA000861BE8 /* CustomLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4045416E268FFDA000861BE8 /* CustomLayout.swift */; };
Expand Down Expand Up @@ -124,19 +125,6 @@
};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
40B42F3225315F410000380A /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 12;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
1A4B46EA20AA7717003D5110 /* NSTableView+Amethyst.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTableView+Amethyst.swift"; sourceTree = "<group>"; };
2A6D9A4025E5D24D006A36B5 /* AppManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppManager.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -178,6 +166,7 @@
402DB6EB1742E41A00D1C936 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
402DB6F11742E41A00D1C936 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = "<group>"; };
402DB6FE1742E44E00D1C936 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
402F6FA52A81C9E30036B512 /* SkyLight.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SkyLight.framework; path = /System/Library/PrivateFrameworks/SkyLight.framework; sourceTree = "<absolute>"; };
40378E22238F39B900D11E22 /* Amethyst.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Amethyst.entitlements; sourceTree = "<group>"; };
403E1A292337173600DB7B2A /* FloatingLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingLayoutTests.swift; sourceTree = "<group>"; };
403E1A2B233719E500DB7B2A /* TallLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TallLayoutTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -271,6 +260,7 @@
40C3F91E1BD1B22E00F58660 /* Security.framework in Frameworks */,
40CF37C029B440A100CDB07A /* ArgumentParser in Frameworks */,
ED989E6BAE0E8D035277478A /* Pods_Amethyst.framework in Frameworks */,
402F6FA62A81C9E30036B512 /* SkyLight.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -386,6 +376,7 @@
402DB6E01742E41A00D1C936 /* Frameworks */ = {
isa = PBXGroup;
children = (
402F6FA52A81C9E30036B512 /* SkyLight.framework */,
40C3F9241BD1B36C00F58660 /* libz.tbd */,
40C3F9221BD1B35E00F58660 /* libc++.tbd */,
40C3F91A1BD1B22E00F58660 /* Security.framework */,
Expand Down Expand Up @@ -608,7 +599,6 @@
402DB6DB1742E41A00D1C936 /* Frameworks */,
402DB6DC1742E41A00D1C936 /* Resources */,
D47F3405558308F2EB634A66 /* [CP] Embed Pods Frameworks */,
40B42F3225315F410000380A /* Embed Frameworks */,
);
buildRules = (
);
Expand Down Expand Up @@ -1114,6 +1104,10 @@
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Amethyst/Amethyst-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SYSTEM_FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
WRAPPER_EXTENSION = app;
};
name = Debug;
Expand Down Expand Up @@ -1152,6 +1146,10 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Amethyst/Amethyst-Bridging-Header.h";
SYSTEM_FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
WRAPPER_EXTENSION = app;
};
name = Release;
Expand Down
57 changes: 57 additions & 0 deletions Amethyst/Model/Window.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@
import Foundation
import Silica

// swiftlint:disable identifier_name
@_silgen_name("GetProcessForPID") @discardableResult
func GetProcessForPID(_ pid: pid_t, _ psn: inout ProcessSerialNumber) -> OSStatus

@_silgen_name("_SLPSSetFrontProcessWithOptions") @discardableResult
func _SLPSSetFrontProcessWithOptions(_ psn: inout ProcessSerialNumber, _ wid: UInt32, _ mode: UInt32) -> CGError

@_silgen_name("SLPSPostEventRecordTo") @discardableResult
func SLPSPostEventRecordTo(_ psn: inout ProcessSerialNumber, _ bytes: inout UInt8) -> CGError

let kCPSUserGenerated: UInt32 = 0x200
// swiftlint:enable identifier_name

/// Generic protocol for objects acting as windows in the system.
protocol WindowType: Equatable {
associatedtype Screen: ScreenType
Expand Down Expand Up @@ -270,8 +283,52 @@ extension AXWindow: WindowType {
- Returns:
`true` if the window was successfully focused, `false` otherwise.
- Description:
What a mess. See: https://github.com/Hammerspoon/hammerspoon/issues/370#issuecomment-545545468
*/
@discardableResult override func focus() -> Bool {
var pid = self.pid()
var wid = self.cgID()
var psn = ProcessSerialNumber()
let status = GetProcessForPID(pid, &psn)

guard status == noErr else {
return false
}

var cgStatus = _SLPSSetFrontProcessWithOptions(&psn, wid, kCPSUserGenerated)

guard cgStatus == .success else {
return false
}

var bytes1 = [UInt8](repeating: 0, count: 0xf8)
bytes1[0x04] = 0xF8
bytes1[0x08] = 0x01
bytes1[0x3a] = 0x10
memcpy(&bytes1[0x3c], &wid, MemoryLayout<UInt32>.size)
memset(&bytes1[0x20], 0xFF, 0x10)
cgStatus = bytes1.withUnsafeMutableBufferPointer { pointer in
return SLPSPostEventRecordTo(&psn, &pointer.baseAddress!.pointee)
}
guard cgStatus == .success else {
return false
}

var bytes2 = [UInt8](repeating: 0, count: 0xf8)
bytes2[0x04] = 0xF8
bytes2[0x08] = 0x02
bytes2[0x3a] = 0x10
memcpy(&bytes2[0x3c], &wid, MemoryLayout<UInt32>.size)
memset(&bytes2[0x20], 0xFF, 0x10)
cgStatus = bytes2.withUnsafeMutableBufferPointer { pointer in
return SLPSPostEventRecordTo(&psn, &pointer.baseAddress!.pointee)
}
guard cgStatus == .success else {
return false
}

guard super.focus() else {
return false
}
Expand Down

0 comments on commit c8a7bdf

Please sign in to comment.