Browse code
feat(notifications): initial support for distributed notifications
Edward Langley authored on 18/09/2022 10:15:42
Showing 3 changed files
Showing 3 changed files
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,70 @@ |
1 |
+(defpackage :objc.notification |
|
2 |
+ (:use :cl ) |
|
3 |
+ (:export |
|
4 |
+ #:main-loop-ticker |
|
5 |
+ #:dnc |
|
6 |
+ #:observe-notifications |
|
7 |
+ #:*mailbox*)) |
|
8 |
+(in-package :objc.notification) |
|
9 |
+(serapeum:eval-always |
|
10 |
+ (named-readtables:in-readtable :objc-readtable)) |
|
11 |
+ |
|
12 |
+(defun main-loop-ticker () |
|
13 |
+ (let ((main-run-loop [#@NSRunLoop @(mainRunLoop)])) |
|
14 |
+ (loop do |
|
15 |
+ (sleep 0.1) |
|
16 |
+ (trivial-main-thread:with-body-in-main-thread (:blocking t) |
|
17 |
+ (objc-runtime::tick-ns-runloop main-run-loop |
|
18 |
+ 0.1))))) |
|
19 |
+ |
|
20 |
+(defun dnc () |
|
21 |
+ [#@NSDistributedNotificationCenter |
|
22 |
+ @(defaultCenter)]) |
|
23 |
+ |
|
24 |
+(defvar *mailbox*) |
|
25 |
+(cffi:defcallback handle-notification :void |
|
26 |
+ ((_ :pointer) (__ :pointer) (notification :pointer)) |
|
27 |
+ (declare (ignore _ __)) |
|
28 |
+ (sb-concurrency:send-message |
|
29 |
+ *mailbox* |
|
30 |
+ (objc-runtime.data-extractors:extract-from-objc |
|
31 |
+ [notification @(userInfo)]))) |
|
32 |
+ |
|
33 |
+(defvar *notification-handler*) |
|
34 |
+(defun setup-delegate () |
|
35 |
+ (if (boundp '*notification-handler*) |
|
36 |
+ *notification-handler* |
|
37 |
+ (let ((delegate-class |
|
38 |
+ (objc-runtime::objc-allocate-class-pair |
|
39 |
+ #@NSObject |
|
40 |
+ (format nil "FWNotificationHandler~a" |
|
41 |
+ (gensym)) |
|
42 |
+ 0))) |
|
43 |
+ (objc-runtime::class-add-method |
|
44 |
+ delegate-class |
|
45 |
+ @(handle-notification:) |
|
46 |
+ (cffi:callback handle-notification) |
|
47 |
+ "v@:@") |
|
48 |
+ (setf *mailbox* |
|
49 |
+ (sb-concurrency:make-mailbox) |
|
50 |
+ |
|
51 |
+ *notification-handler* |
|
52 |
+ [[delegate-class @(alloc)] @(init)])))) |
|
53 |
+ |
|
54 |
+(define-condition notifications-not-initialized (error) |
|
55 |
+ ()) |
|
56 |
+ |
|
57 |
+(defun observe-notifications (dnc notification-name) |
|
58 |
+ (tagbody start |
|
59 |
+ (restart-case |
|
60 |
+ (if (boundp '*notification-handler*) |
|
61 |
+ [dnc @(addObserver:selector:name:object:) |
|
62 |
+ :pointer *notification-handler* |
|
63 |
+ :pointer @(handle-notification:) |
|
64 |
+ :pointer (objc-runtime::make-nsstring |
|
65 |
+ notification-name) |
|
66 |
+ :pointer (cffi:null-pointer)] |
|
67 |
+ (error 'notifications-not-initialized)) |
|
68 |
+ (setup-and-retry () |
|
69 |
+ (setup-delegate) |
|
70 |
+ (go start))))) |
... | ... |
@@ -34,6 +34,15 @@ |
34 | 34 |
:data-lens) |
35 | 35 |
:components ((:file "scripting-bridge"))) |
36 | 36 |
|
37 |
+(defsystem :objc-runtime/notifications |
|
38 |
+ :description "" |
|
39 |
+ :author "Ed L <edward@elangley.org>" |
|
40 |
+ :license "MIT" |
|
41 |
+ :depends-on (:objc-runtime |
|
42 |
+ :trivial-main-thread |
|
43 |
+ (:require :sb-concurrency)) |
|
44 |
+ :components ((:file "notification"))) |
|
45 |
+ |
|
37 | 46 |
(defsystem :objc-runtime/clim-objc-browser |
38 | 47 |
:description "" |
39 | 48 |
:author "Ed L <edward@elangley.org>" |
... | ... |
@@ -142,6 +142,10 @@ |
142 | 142 |
:pointer |
143 | 143 |
(method :pointer)) |
144 | 144 |
|
145 |
+(defcfun (method-get-type-encoding "method_getTypeEncoding") |
|
146 |
+ :string |
|
147 |
+ (method :pointer)) |
|
148 |
+ |
|
145 | 149 |
(defcfun (sel-get-name "sel_getName") |
146 | 150 |
:string |
147 | 151 |
(sel o-selector)) |
... | ... |
@@ -414,3 +418,17 @@ |
414 | 418 |
`(let (,@(mapcar #'second expanded-defs)) |
415 | 419 |
(flet (,@(mapcar #'first expanded-defs)) |
416 | 420 |
,@body)))) |
421 |
+ |
|
422 |
+(defun description (nsobject) |
|
423 |
+ [nsobject @(description)]@) |
|
424 |
+ |
|
425 |
+(defun future-ns-date (seconds) |
|
426 |
+ [[#@NSDate @(alloc)] |
|
427 |
+ @(initWithTimeIntervalSinceNow:) |
|
428 |
+ :double (coerce seconds 'double-float)]) |
|
429 |
+ |
|
430 |
+(defun tick-ns-runloop (run-loop &optional (time 0.5d0)) |
|
431 |
+ (let ((date (future-ns-date time))) |
|
432 |
+ (unwind-protect [run-loop @(runUntilDate:) |
|
433 |
+ :pointer date] |
|
434 |
+ [date @(release)]))) |