Perpustakaan manajemen jendela cepat untuk macOS
Dalam beberapa tahun terakhir, banyak pengembang sebelumnya di Linux dan Windows telah bermigrasi ke Mac untuk perangkat keras mereka yang sangat baik dan OS berbasis UNIX yang "hanya berfungsi".
Tetapi di sepanjang jalan kami menyerahkan sesuatu yang Anda sayangi: kendalikan lingkungan desktop kami.
Tujuan Swindler adalah untuk membantu kita mengambil kembali kendali itu , dan memberi kita yang terbaik dari kedua dunia.
Menulis manajer jendela untuk macOS itu sulit. Ada banyak tantangan sistemik, termasuk API yang terbatas dan tidak terdokumentasi dengan buruk. Semua manajer jendela pada macO harus menggunakan API aksesibilitas berbasis C, yang sulit digunakan dan secara mengejutkan kereta sendiri.
Akibatnya, pemilihan manajer jendela cukup terbatas, dan banyak yang ada di luar sana memiliki bug yang menjengkelkan, seperti pembekuan, kondisi balapan, "phantom windows", dan bukan "melihat" jendela yang sebenarnya ada di sana. Semakin canggih Window Manager, semakin bergantung pada API ini dan semakin banyak bug ini mulai muncul.
Tugas Swindler adalah memudahkan untuk menulis manajer jendela yang kuat menggunakan API Swift dan lapisan abstraksi yang terdokumentasi dengan baik. Ini membahas masalah API aksesibilitas dengan fitur -fitur ini:
API Swindler sepenuhnya didokumentasikan dan jenis-aman berkat Swift. Jauh lebih mudah dan lebih aman untuk digunakan daripada API aksesibilitas berbasis C. (Lihat contoh di bawah ini.)
Manajer Jendela MacOS mengandalkan IPC: Anda meminta aplikasi untuk posisi jendela, tunggu untuk merespons, meminta agar dipindahkan atau fokus, kemudian menunggu aplikasi untuk mematuhi (atau tidak). Sebagian besar waktu ini berfungsi dengan baik, tetapi bekerja pada belas kasihan dari loop acara aplikasi jarak jauh, yang dapat menyebabkan penundaan multi-detik.
Swindler memelihara model semua aplikasi dan status jendela, sehingga kode Anda tahu segalanya tentang jendela di layar. Bacaan bersifat instan , karena semua negara di -cache dalam proses aplikasi Anda dan tetap up to date. Swindler diuji secara luas untuk memastikan tetap konsisten dengan sistem dalam situasi apa pun.
Jika Anda perlu mengubah ukuran banyak jendela secara bersamaan, misalnya, Anda dapat melakukannya tanpa takut akan satu aplikasi yang tidak responsif memegang segalanya. Permintaan tulis dikirim secara tidak sinkron dan bersamaan, dan API berbasis janji Swindler memudahkan untuk mengikuti keadaan operasi.
Manajer jendela yang lebih canggih harus mengamati peristiwa di Windows, tetapi API Observer tidak didokumentasikan dengan baik dan seringkali mengeluarkan peristiwa yang mungkin Anda harapkan, atau memberikannya dalam urutan yang salah. Misalnya, situasi berikut adalah umum ketika jendela baru muncul:
1. MainWindowChanged on com.google.chrome to <window1>
2. WindowCreated on com.google.chrome: <window1>
Lihat masalahnya? Dengan Swindler, semua acara dipancarkan dalam urutan yang diharapkan, dan yang hilang diisi. Keadaan dalam memori Swindler akan selalu konsisten dengan dirinya sendiri dan dengan peristiwa yang Anda terima, menghindari banyak bug yang sulit didiagnosis.
Sebagai bonus, peristiwa yang disebabkan oleh kode Anda ditandai seperti itu, jadi Anda tidak menanggapi mereka sebagai tindakan pengguna. Fitur ini saja memungkinkan tingkat kecanggihan yang sama sekali baru.
Kode berikut menetapkan semua jendela di layar ke kisi -kisi. Perhatikan kesederhanaan dan kekuatan API berbasis janji. Permintaan dikirim secara bersamaan dan di latar belakang, bukan serial.
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 )
}Menonton acara itu sederhana. Begini cara Anda mengimplementasikan 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
}Aplikasi Anda harus meminta akses ke API AX tepercaya. Untuk melakukan ini, cukup gunakan kode ini di AppDelegate Anda:
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
}Banyak komponen aplikasi pembantu atau "khusus" tidak menanggapi permintaan AX atau merespons dengan kesalahan. Akibatnya, diharapkan untuk melihat sejumlah pesan seperti ini:
<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
Saat ini ini dicatat karena sulit untuk menentukan apakah suatu aplikasi "harus" gagal (terutama pada batas waktu). Selama hal -hal tampak berhasil, Anda dapat mengabaikannya.
Swindler sedang dalam pengembangan dan dalam alpha . Inilah keadaan fitur utamanya:
Anda dapat melihat seluruh API yang direncanakan di sini.
Dokumentasi API (rilis terbaru)
Dokumentasi API (Utama)
Swindler menggunakan Swift Package Manager.
Klon proyek, lalu di shell run Anda:
$ cd Swindler
$ git submodule init
$ git submodule update
Pada titik ini Anda harus dapat membangun Swindler di Xcode dan mulai di jalan Anda!
Anda dapat menjalankan proyek contoh dari baris perintah.
swift run
Anda dapat mengobrol dengan kami di Gitter.
Ikuti saya di Twitter: @tmandry
Swindler dibangun di atas Axswift.