مكتبة لإدارة النوافذ السريعة ل macos
في السنوات القليلة الماضية ، قام العديد من المطورين سابقًا على Linux و Windows بالترحيل إلى MAC لأجهزةهم الممتازة ونظام التشغيل القائم على UNIX "فقط يعمل".
ولكن على طول الطريق تخلينا عن شيء عزيز علينا: التحكم في بيئة سطح المكتب لدينا.
الهدف من Swindler هو مساعدتنا في استعادة هذه السيطرة ، ومنحنا أفضل ما في العالمين.
من الصعب كتابة مديري النوافذ لـ MacOS. هناك الكثير من التحديات النظامية ، بما في ذلك واجهات برمجة التطبيقات المحدودة والسيئة الموثقة. يجب على جميع مديري النوافذ على MACOS استخدام واجهات برمجة تطبيقات إمكانية الوصول المستندة إلى C ، والتي يصعب استخدامها وهم عربات التي تجرها الدواب بأنفسهم.
ونتيجة لذلك ، فإن اختيار مديري النوافذ محدود للغاية ، والعديد من الأشخاص الذين لديهم أخطاء مزعجة ، مثل التجميد ، وظروف السباق ، و "Windows Windows" ، وليس "رؤية" النوافذ الموجودة بالفعل. كلما كان مدير النافذة أكثر تطوراً ، كلما تعتمد على واجهات برمجة التطبيقات هذه ، كلما بدأت هذه الأخطاء في الظهور.
تتمثل مهمة Swindler في تسهيل كتابة مديري النوافذ القوية باستخدام واجهة برمجة تطبيقات Swift وطبقة التجريد الموثقة جيدًا. يعالج مشاكل API إمكانية الوصول مع هذه الميزات:
تم توثيق واجهة برمجة تطبيقات Swindler بالكامل وعملية من نوعها بفضل Swift. من الأسهل بكثير وأمان الاستخدام من واجهات برمجة تطبيقات إمكانية الوصول المستندة إلى C. (انظر المثال أدناه.)
يعتمد مديرو النوافذ على MACOS على IPC: أنت تطلب طلبًا لموضع النافذة ، وانتظر حتى يستجيب ، أو يطلبون نقله أو تركيزه ، ثم انتظر حتى يتوافق التطبيق (أو لا). في معظم الأوقات ، يعمل هذا بشكل جيد ، لكنه يعمل تحت رحمة حلقة حدث التطبيق عن بُعد ، والتي يمكن أن تؤدي إلى تأخير طويل متعدد ثانية.
يحتفظ Swindler بنموذج لجميع التطبيقات وحالات النوافذ ، لذلك يعرف الكود الخاص بك كل شيء عن النوافذ على الشاشة. القراءات فورية ، لأن جميع الحالة يتم تخزينها مؤقتًا في عملية طلبك وتبقى محدثة. يتم اختبار Swindler على نطاق واسع لضمان بقائه متسقًا مع النظام في أي موقف.
إذا كنت بحاجة إلى تغيير حجم الكثير من النوافذ في وقت واحد ، على سبيل المثال ، يمكنك القيام بذلك دون خوف من تطبيق واحد لا يستجيب يحمل كل شيء آخر. يتم إرسال طلبات الكتابة بشكل غير متزامن وبشكل متزامن ، ويجعل واجهة برمجة تطبيقات Swindler القائمة على الوعد من السهل مواكبة حالة العمليات.
يتعين على مديري النوافذ الأكثر تطوراً مراقبة الأحداث على Windows ، لكن واجهة برمجة تطبيقات Observer ليست موثقة جيدًا وغالبًا ما تترك الأحداث التي قد تتوقعها ، أو تسليمها بالترتيب الخاطئ. على سبيل المثال ، يكون الموقف التالي شائعًا عند ظهور نافذة جديدة:
1. MainWindowChanged on com.google.chrome to <window1>
2. WindowCreated on com.google.chrome: <window1>
ترى المشكلة؟ مع Swindler ، يتم تنبعث جميع الأحداث بالترتيب المتوقع ، ويتم ملء الأحداث المفقودة. ستكون حالة Swindler في الذاكرة دائمًا متسقة مع نفسها ومع الأحداث التي تتلقاها ، وتجنب العديد من الأخطاء التي يصعب تشخيصها.
كمكافأة ، يتم تمييز الأحداث الناجمة عن الكود الخاص بك على هذا النحو ، لذلك لا ترد عليها كإجراءات للمستخدم. هذه الميزة وحدها تجعل مستوى جديد تمامًا من التطور ممكنًا.
يقوم الرمز التالي بتعيين جميع النوافذ على الشاشة على شبكة. لاحظ بساطة وقوة واجهة برمجة التطبيقات القائمة على الوعد. يتم إرسال الطلبات بشكل متزامن وفي الخلفية ، وليس بشكل متسلسل.
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 الموثوقة. للقيام بذلك ، ما عليك سوى استخدام هذا الرمز في 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 (رئيسية)
يستخدم Swindler Swift Package Manager.
استنساخ المشروع ، ثم في تشغيل القشرة:
$ cd Swindler
$ git submodule init
$ git submodule update
في هذه المرحلة ، يجب أن تكون قادرًا على بناء Swindler في Xcode والبدء في طريقك!
يمكنك تشغيل مشروع المثال من سطر الأوامر.
swift run
يمكنك الدردشة معنا على Gitter.
اتبعني على Twitter: tmandry
تم بناء Swindler على Axswift.