Browse code
Miscellaneous changes
Ed Langley authored on 08/04/2018 01:26:06
Showing 5 changed files
Showing 5 changed files
... | ... |
@@ -122,11 +122,6 @@ |
122 | 122 |
(object :pointer) |
123 | 123 |
(ivar :pointer)) |
124 | 124 |
|
125 |
-(defcfun (class-get-instance-variable "class_getInstanceVariable" :library foundation) |
|
126 |
- :pointer |
|
127 |
- (class :pointer) |
|
128 |
- (name :string)) |
|
129 |
- |
|
130 | 125 |
(defcfun (object-get-instance-variable "object_getInstanceVariable" :library foundation) |
131 | 126 |
:pointer |
132 | 127 |
(object :pointer) |
... | ... |
@@ -170,6 +165,7 @@ |
170 | 165 |
(push (mem-aref methods :pointer n) |
171 | 166 |
result))))))) |
172 | 167 |
|
168 |
+ |
|
173 | 169 |
(defun make-nsstring (str) |
174 | 170 |
[[#@NSString @(alloc)] @(initWithCString:encoding:) :string str :uint 1]) |
175 | 171 |
|
... | ... |
@@ -200,18 +196,6 @@ |
200 | 196 |
*selector-cache* |
201 | 197 |
(sel-register-name name))) |
202 | 198 |
|
203 |
-(defmacro with-selectors ((&rest selector-specs) &body body) |
|
204 |
- `(let (,@(mapcar (fw.lu:destructuring-lambda ((sym foreign-selector)) |
|
205 |
- `(,sym (ensure-selector ,foreign-selector))) |
|
206 |
- (mapcar (fw.lu:glambda (spec) |
|
207 |
- (:method ((spec symbol)) |
|
208 |
- (list spec (normalize-selector-name |
|
209 |
- (string-downcase spec)))) |
|
210 |
- (:method ((spec cons)) |
|
211 |
- (list (car spec) (cadr spec)))) |
|
212 |
- selector-specs))) |
|
213 |
- ,@body)) |
|
214 |
- |
|
215 | 199 |
(defmacro with-objc-classes ((&rest class-defs) &body body) |
216 | 200 |
`(let (,@(mapcar (fw.lu:destructuring-lambda ((lisp-name foreign-name)) |
217 | 201 |
`(,lisp-name (objc-look-up-class ,foreign-name))) |
... | ... |
@@ -219,6 +203,90 @@ |
219 | 203 |
,@body)) |
220 | 204 |
|
221 | 205 |
|
206 |
+ |
|
207 |
+(cffi:defcvar (ns-app "NSApp" :library appkit) :pointer) |
|
208 |
+ |
|
209 |
+(defclass objc-class () |
|
210 |
+ ((%objc-class-name :initarg :name :reader name) |
|
211 |
+ (%class-pointer :initarg :pointer :reader class-pointer) |
|
212 |
+ (%cache :initform (make-hash-table :test 'equal) :allocation :class :reader objc-class-cache))) |
|
213 |
+ |
|
214 |
+(defclass objc-selector () |
|
215 |
+ ((%objc-selector-name :initarg :name :reader name) |
|
216 |
+ (%selector-pointer :initarg :pointer :reader selector-pointer) |
|
217 |
+ (%args :initarg :args :reader args) |
|
218 |
+ (%result-type :initarg :result-type :reader result-type) |
|
219 |
+ (%cache :initform (make-hash-table :test 'equal) :allocation :class :reader objc-selector-cache)) |
|
220 |
+ (:metaclass closer-mop:funcallable-standard-class)) |
|
221 |
+ |
|
222 |
+(defun make-message-lambda-form (args rettype) |
|
223 |
+ (alexandria:with-gensyms ((target :target)) |
|
224 |
+ (fw.lu:with (arg-syms (mapcar (serapeum:op _ (gensym "arg")) args)) |
|
225 |
+ `(lambda (selector) |
|
226 |
+ (lambda (,target ,@arg-syms) |
|
227 |
+ (cffi:foreign-funcall |
|
228 |
+ "objc_msgSend" |
|
229 |
+ :pointer ,target |
|
230 |
+ :pointer selector |
|
231 |
+ ,@(mapcan #'list args arg-syms) |
|
232 |
+ ,rettype)))))) |
|
233 |
+ |
|
234 |
+(defmethod initialize-instance :after ((sel objc-selector) &key &allow-other-keys) |
|
235 |
+ (with-accessors ((pointer selector-pointer) |
|
236 |
+ (args args) |
|
237 |
+ (rettype result-type)) |
|
238 |
+ sel |
|
239 |
+ (closer-mop:set-funcallable-instance-function |
|
240 |
+ sel |
|
241 |
+ (funcall (compile nil (make-message-lambda-form args rettype)) |
|
242 |
+ pointer)))) |
|
243 |
+ |
|
244 |
+(defgeneric reset-class-cache (class) |
|
245 |
+ (:method ((class symbol)) |
|
246 |
+ (reset-class-cache (find-class class))) |
|
247 |
+ (:method ((class class)) |
|
248 |
+ (setf (slot-value (closer-mop:class-prototype class) '%cache) |
|
249 |
+ (make-hash-table :test 'equal)))) |
|
250 |
+ |
|
251 |
+ |
|
252 |
+(define-condition no-such-objc-class (serious-condition) |
|
253 |
+ ((%wanted-name :initarg :wanted-name :reader wanted-name)) |
|
254 |
+ (:report (lambda (c s) |
|
255 |
+ (format s "No such Objective-C class: ~a" (wanted-name c))))) |
|
256 |
+ |
|
257 |
+(defun %ensure-wrapped-objc-class (name) |
|
258 |
+ (let* ((class-cache (objc-class-cache (closer-mop:class-prototype (find-class 'objc-class)))) |
|
259 |
+ (cached (gethash name class-cache))) |
|
260 |
+ (if cached |
|
261 |
+ cached |
|
262 |
+ (let ((objc-class (objc-look-up-class name))) |
|
263 |
+ (if (null-pointer-p objc-class) |
|
264 |
+ (error 'no-such-objc-class :wanted-name name) |
|
265 |
+ (setf (gethash name class-cache) |
|
266 |
+ (make-instance 'objc-class |
|
267 |
+ :name name |
|
268 |
+ :pointer objc-class))))))) |
|
269 |
+ |
|
270 |
+;; TODO: should this error if there is no corresponding selector? Or should we let that fall through to message sending? |
|
271 |
+(defun %ensure-wrapped-objc-selector (name target-class result-type args) |
|
272 |
+ (assert (= (count #\: name) |
|
273 |
+ (length args)) |
|
274 |
+ (name args) |
|
275 |
+ "Invalid number of arg types for selector ~s" name) |
|
276 |
+ |
|
277 |
+ (let* ((class-cache (objc-selector-cache (closer-mop:class-prototype (find-class 'objc-selector)))) |
|
278 |
+ (cached (gethash (list name target-class) |
|
279 |
+ class-cache))) |
|
280 |
+ (if cached |
|
281 |
+ cached |
|
282 |
+ (let ((objc-selector (ensure-selector name))) |
|
283 |
+ (setf (gethash (list name target-class) class-cache) |
|
284 |
+ (make-instance 'objc-selector |
|
285 |
+ :name name |
|
286 |
+ :pointer objc-selector |
|
287 |
+ :result-type result-type |
|
288 |
+ :args args)))))) |
|
289 |
+ |
|
222 | 290 |
(defgeneric make-objc-instance (class &rest args) |
223 | 291 |
(:method ((class string) &rest args) |
224 | 292 |
(apply #'make-objc-instance (objc-look-up-class class) args)) |
... | ... |
@@ -233,18 +301,36 @@ |
233 | 301 |
(with-selectors (alloc init) |
234 | 302 |
[[class alloc] init]))) |
235 | 303 |
|
304 |
+(defun ensure-wrapped-objc-class (name) |
|
305 |
+ (tagbody |
|
306 |
+ retry (restart-case (return-from ensure-wrapped-objc-class |
|
307 |
+ (%ensure-wrapped-objc-class name)) |
|
308 |
+ (use-value (new) |
|
309 |
+ :interactive (lambda () |
|
310 |
+ (format t "New Objective-C class name: ") |
|
311 |
+ (multiple-value-list (read))) |
|
312 |
+ :report "Retry with new class name" |
|
313 |
+ (setf name new) |
|
314 |
+ (go retry))))) |
|
236 | 315 |
|
237 |
-(cffi:defcvar (ns-app "NSApp" :library appkit) :pointer) |
|
238 |
- |
|
239 |
-#| |
|
240 |
-(uiop:nest (with-selectors (alloc init drain)) |
|
241 |
- (with-objc-classes ((nsobject "NSAutoreleasepool"))) |
|
242 |
- (eval-objc (objc-msg-send |
|
243 |
- (objc-msg-send |
|
244 |
- (objc-msg-send nsobject alloc) |
|
245 |
- init) |
|
246 |
- drain))) |
|
247 |
-(with-selectors (alloc init)) |
|
316 |
+(defmacro with-selectors ((&rest selector-specs) &body body) |
|
317 |
+ `(let (,@(mapcar (fw.lu:destructuring-lambda ((sym foreign-selector)) |
|
318 |
+ `(,sym (ensure-selector ,foreign-selector))) |
|
319 |
+ (mapcar (fw.lu:glambda (spec) |
|
320 |
+ (:method ((spec symbol)) |
|
321 |
+ (list spec (normalize-selector-name |
|
322 |
+ (string-downcase spec)))) |
|
323 |
+ (:method ((spec cons)) |
|
324 |
+ (list (car spec) (cadr spec)))) |
|
325 |
+ selector-specs))) |
|
326 |
+ ,@body)) |
|
248 | 327 |
|
249 |
-|# |
|
250 | 328 |
|
329 |
+(defmacro with-typed-selectors ((&rest defs) &body body) |
|
330 |
+ (let ((expanded-defs (loop for ((name objc-name) args ret-type) in defs |
|
331 |
+ collect |
|
332 |
+ `((,name (&rest r) (apply ,name r)) |
|
333 |
+ (,name (%ensure-wrapped-objc-selector ,objc-name ',ret-type ',args)))))) |
|
334 |
+ `(let (,@(mapcar #'second expanded-defs)) |
|
335 |
+ (flet (,@(mapcar #'first expanded-defs)) |
|
336 |
+ ,@body)))) |
... | ... |
@@ -1,5 +1,10 @@ |
1 | 1 |
(in-package :objc-runtime) |
2 | 2 |
|
3 |
+#+ccl |
|
4 |
+(defgeneric send-message (object message &rest args) |
|
5 |
+ (:method ((object ccl:macptr) (message (eql 'alloc)) &rest args) |
|
6 |
+ (apply #'objc-msg-send object (ensure-selector "alloc") args))) |
|
7 |
+ |
|
3 | 8 |
(defun read-until (test symbol-prefix &optional stop-before-chars) |
4 | 9 |
"Read from a string until" |
5 | 10 |
(lambda (s c b) |