MACOS 용 신속한 창 관리 라이브러리
지난 몇 년 동안 이전에 Linux 및 Windows에있는 많은 개발자들은 "Just Works"라는 우수한 하드웨어 및 UNIX 기반 OS를 위해 Mac으로 마이그레이션했습니다.
그러나 길을 따라 우리는 우리에게 소중한 것을 포기했습니다 : 데스크탑 환경에 대한 통제.
Swindler의 목표는 우리가 그 통제권을 되찾고 두 세계의 최선을 다하는 것을 돕는 것입니다 .
MacOS 용 창 관리자를 작성하는 것은 어렵습니다. 제한된 문서화 및 제한된 문서화 된 API를 포함하여 많은 체계적인 과제가 있습니다. MacOS의 모든 창 관리자는 사용하기 어렵고 놀랍게도 버그가있는 C 기반 접근성 API를 사용해야합니다.
결과적으로, 윈도우 관리자의 선택은 상당히 제한되어 있으며, 많은 사람들이 동결, 레이스 조건, "팬텀 윈도우"와 같은 성가신 버그를 가지고 있으며 실제로 존재하는 창문을 보지 않습니다. 창 관리자가 더 정교할수록이 API에 더 의존하고 더 많은 버그가 나타나기 시작합니다.
Swindler의 임무는 잘 문서화 된 Swift API 및 추상화 레이어를 사용하여 강력한 창 관리자를 쉽게 작성할 수 있도록하는 것입니다. 이러한 기능으로 접근성 API의 문제를 해결합니다.
Swift 덕분에 Swindler의 API는 완전히 문서화되어 있으며 유형 안전합니다. C 기반 접근성 API보다 사용하기가 훨씬 쉽고 안전합니다. (아래 예제를 참조하십시오.)
MACOS의 창 관리자는 IPC에 의존합니다. 응용 프로그램에 창의 위치를 요청하고 응답을 기다리고 , 이동하거나 집중하도록 요청한 다음 응용 프로그램이 준수 할 때까지 기다립니다 . 대부분의 경우 이것은 잘 작동하지만 원격 애플리케이션의 이벤트 루프의 자비에서 작동하며, 이는 긴 다중 초 지연으로 이어질 수 있습니다.
Swindler는 모든 응용 프로그램과 창 상태의 모델을 유지하므로 코드는 화면의 창에 대한 모든 것을 알고 있습니다. 모든 상태가 응용 프로그램 프로세스 내에서 캐시되고 최신 상태가되기 때문에 읽기는 즉각적입니다 . Swindler는 모든 상황에서 시스템과 일치하게 유지되도록 광범위하게 테스트됩니다.
예를 들어, 많은 창을 동시에 크기를 조정 해야하는 경우, 다른 모든 것을 보유하고있는 응답하지 않는 응용 프로그램에 대한 두려움없이 그렇게 할 수 있습니다. 쓰기 요청은 비동기 적으로 동시에 파견되며 Swindler의 약속 기반 API를 사용하면 운영 상태를 쉽게 유지할 수 있습니다.
보다 정교한 창 관리자는 Windows에서 이벤트를 관찰해야하지만 관찰자 API는 잘 문서화되어 있지 않으며 종종 예상 할 수있는 이벤트를 제외하거나 잘못된 순서로 전달합니다. 예를 들어, 새로운 창이 나타날 때 다음 상황이 일반적입니다.
1. MainWindowChanged on com.google.chrome to <window1>
2. WindowCreated on com.google.chrome: <window1>
문제가 보이십니까? Swindler를 사용하면 모든 이벤트가 예상 순서로 방출되고 누락 된 이벤트는 채워집니다. Swindler의 메모리 내 상태는 항상 그 자체와받는 이벤트와 일치하여 진단하기 어려운 많은 버그를 피할 수 있습니다.
보너스로 코드로 인한 이벤트는 그에 따라 표시되므로 사용자 조치로 응답하지 않습니다. 이 기능만으로도 완전히 새로운 수준의 정교함이 가능합니다.
다음 코드는 화면의 모든 창을 그리드에 할당합니다. 약속 기반 API의 단순성과 힘에 유의하십시오. 요청은 동시에 그리고 백그라운드에서 연속적이지 않은 배경으로 발송됩니다.
Swindler . initialize ( ) . then { state -> Void in
let screen = state . screens . first!
let allPlacedOnGrid = screen . knownWindows . enumerate ( ) . map { index , window in
let rect = gridRect ( screen , index )
return window . frame . set ( rect )
}
when ( allPlacedOnGrid ) { _ in
print ( " all done! " )
}
} . catch { error in
// ...
}
func gridRect ( screen : Swindler . Screen , index : Int ) -> CGRect {
let gridSteps = 3
let position = CGSize ( width : screen . width / gridSteps ,
height : screen . height / gridSteps )
let size = CGPoint ( x : gridSize . width * ( index % gridSteps ) ,
y : gridSize . height * ( index / gridSteps ) )
return CGRect ( origin : position , size : size )
}이벤트를 보는 것은 간단합니다. Snap-to-grid를 구현하는 방법은 다음과 같습니다.
swindlerState . on { ( event : WindowMovedEvent ) in
guard event . external == true else {
// Ignore events that were caused by us.
return
}
let snapped = closestGridPosition ( event . window . frame . value )
event . window . frame . value = snapped
}신청서는 신뢰할 수있는 AX API에 대한 액세스를 요청해야합니다. 이렇게하려면 AppDelegate 에서이 코드를 사용하기 만하면됩니다.
func applicationDidFinishLaunching ( _ aNotification : Notification ) {
guard AXSwift . checkIsProcessTrusted ( prompt : true ) else {
print ( " Not trusted as an AX process; please authorize and re-launch " )
NSApp . terminate ( self )
return
}
// your code here
}많은 도우미 또는 다른 "특별"앱 구성 요소는 AX 요청에 응답하거나 오류로 응답하지 않습니다. 결과적으로 다음과 같은 여러 메시지가 표시 될 것으로 예상됩니다.
<Debug>: Window <AXUnknown "<AXUIElement 0x610000054eb0> {pid=464}" (pid=464)> has subrole AXUnknown, unwatching
<Debug>: Application invalidated: com.apple.dock
<Debug>: Couldn't initialize window for element <AXUnknown "<AXUIElement 0x610000054eb0> {pid=464}" (pid=464)> () of com.google.Chrome: windowIgnored(<AXUnknown "<AXUIElement 0x610000054eb0> {pid=464}" (pid=464)>)
<Notice>: Could not watch application com.apple.dock (pid=308): invalidObject(AXError.NotificationUnsupported)
<Debug>: Couldn't initialize window for element <AXScrollArea "<AXUIElement 0x61800004ed90> {pid=312}" (pid=312)> (desktop) of com.apple.finder: AXError.NotificationUnsupported
현재 이들은 앱이 "실패 해야하는지 (특히 타임 아웃에서)를 결정하기가 어렵 기 때문에 기록됩니다. 일이 작동하는 것처럼 보이면 무시할 수 있습니다.
Swindler는 개발 중이며 알파 에 있습니다. 다음은 주요 기능의 상태입니다.
여기에서 계획된 API 전체를 볼 수 있습니다.
API 문서 (최신 릴리스)
API 문서 (메인)
Swindler는 Swift 패키지 관리자를 사용합니다.
프로젝트를 복제 한 다음 쉘 실행에서 :
$ cd Swindler
$ git submodule init
$ git submodule update
이 시점에서 Xcode에서 Swindler를 구축하고 길을 시작할 수 있어야합니다!
명령 줄에서 예제 프로젝트를 실행할 수 있습니다.
swift run
당신은 Gitter에서 우리와 채팅 할 수 있습니다.
트위터에서 나를 팔로우하십시오 : @tmandry
Swindler는 Axswift에 구축되었습니다.