chiark / gitweb /
Stock item bindings updated to Gtk+ 2.8
[clg] / glib / proxy.lisp
CommitLineData
55212af1 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2005 Espen S. Johnsen <espen@users.sf.net>
b44caf77 3;;
55212af1 4;; Permission is hereby granted, free of charge, to any person obtaining
5;; a copy of this software and associated documentation files (the
6;; "Software"), to deal in the Software without restriction, including
7;; without limitation the rights to use, copy, modify, merge, publish,
8;; distribute, sublicense, and/or sell copies of the Software, and to
9;; permit persons to whom the Software is furnished to do so, subject to
10;; the following conditions:
b44caf77 11;;
55212af1 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
b44caf77 14;;
55212af1 15;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
b44caf77 22
fb9bc912 23;; $Id: proxy.lisp,v 1.37 2006/02/26 16:12:25 espen Exp $
b44caf77 24
25(in-package "GLIB")
26
b44caf77 27;;;; Superclass for all metaclasses implementing some sort of virtual slots
28
29(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 30 (defclass virtual-slots-class (standard-class)
935a783c 31 ())
b44caf77 32
33 (defclass direct-virtual-slot-definition (standard-direct-slot-definition)
ba25fa44 34 ((setter :reader slot-definition-setter :initarg :setter)
935a783c 35 (getter :reader slot-definition-getter :initarg :getter)
64bce834 36 (unbound :reader slot-definition-unbound :initarg :unbound)
935a783c 37 (boundp :reader slot-definition-boundp :initarg :boundp)))
b44caf77 38
935a783c 39 (defclass effective-virtual-slot-definition (standard-effective-slot-definition)
40 ((setter :reader slot-definition-setter :initarg :setter)
41 (getter :reader slot-definition-getter :initarg :getter)
64bce834 42 (unbound :reader slot-definition-unbound :initarg :unbound)
82defe4d 43 (boundp :reader slot-definition-boundp :initarg :boundp)))
935a783c 44
82defe4d 45 (defclass direct-special-slot-definition (standard-direct-slot-definition)
c23cc486 46 ((special :initarg :special :accessor slot-definition-special)))
b44caf77 47
82defe4d 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
c23cc486 49 ((special :initarg :special :accessor slot-definition-special))))
82defe4d 50
51(defvar *unbound-marker* (gensym "UNBOUND-MARKER-"))
52
53(defun most-specific-slot-value (instances slot &optional (default *unbound-marker*))
54 (let ((object (find-if
55 #'(lambda (ob)
56 (and (slot-exists-p ob slot) (slot-boundp ob slot)))
57 instances)))
58 (if object
59 (slot-value object slot)
60 default)))
61
b44caf77 62
6baf860c 63(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
c23cc486 64 (cond
65 ((eq (getf initargs :allocation) :virtual)
66 (find-class 'direct-virtual-slot-definition))
67 ((getf initargs :special)
68 (find-class 'direct-special-slot-definition))
69 (t (call-next-method))))
b44caf77 70
6baf860c 71(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
c23cc486 72 (cond
73 ((eq (getf initargs :allocation) :virtual)
74 (find-class 'effective-virtual-slot-definition))
75 ((getf initargs :special)
76 (find-class 'effective-special-slot-definition))
77 (t (call-next-method))))
b44caf77 78
935a783c 79
80(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
64bce834 81 (if (not (slot-boundp slotd 'getter))
82 (setf
935a783c 83 (slot-value slotd 'reader-function)
64bce834 84 #'(lambda (object)
85 (declare (ignore object))
adcadd53 86 (error "Slot is not readable: ~A" (slot-definition-name slotd)))
64bce834 87 (slot-value slotd 'boundp-function)
88 #'(lambda (object) (declare (ignore object)) nil))
89
90 (let ((getter-function
91 (let ((getter (slot-value slotd 'getter)))
92 (etypecase getter
93 (function getter)
94 (symbol
95 #'(lambda (object)
96 (funcall getter object)))
97 (string
98 (let ((reader nil))
99 (setf (slot-value slotd 'reader-function)
100 #'(lambda (object)
101 (unless reader
b6bf802c 102 (setq reader
103 (mkbinding getter
104 (slot-definition-type slotd) 'pointer)))
7ce0497d 105 (funcall reader (foreign-location object))))))))))
64bce834 106
935a783c 107 (setf
64bce834 108 (slot-value slotd 'boundp-function)
109 (cond
64bce834 110 ((slot-boundp slotd 'unbound)
111 (let ((unbound-value (slot-value slotd 'unbound)))
b6bf802c 112 #'(lambda (object)
113 (not (eq (funcall getter-function object) unbound-value)))))
114 ((slot-boundp slotd 'boundp)
115 (let ((boundp (slot-value slotd 'boundp)))
64bce834 116 (etypecase boundp
117 (function boundp)
118 (symbol #'(lambda (object)
119 (funcall boundp object)))
120 (string (let ((reader ()))
121 #'(lambda (object)
122 (unless reader
123 (setq reader
124 (mkbinding boundp
125 (slot-definition-type slotd) 'pointer)))
7ce0497d 126 (funcall reader (foreign-location object))))))))
4d1fea77 127 ((let ((unbound-value-method
128 (find-applicable-type-method 'unbound-value
129 (slot-definition-type slotd) nil)))
130 (when unbound-value-method
131 (let ((unbound-value
132 (funcall unbound-value-method (slot-definition-type slotd))))
133 #'(lambda (object)
134 (not (eq (funcall getter-function object) unbound-value)))))))
b6bf802c 135 (#'(lambda (object) (declare (ignore object)) t))))
64bce834 136
137 (setf
138 (slot-value slotd 'reader-function)
139 (cond
140 ((slot-boundp slotd 'unbound)
141 (let ((unbound (slot-value slotd 'unbound))
142 (slot-name (slot-definition-name slotd)))
b6bf802c 143 #'(lambda (object)
144 (let ((value (funcall getter-function object)))
145 (if (eq value unbound)
146 (slot-unbound (class-of object) object slot-name)
147 value)))))
64bce834 148 ((slot-boundp slotd 'boundp)
149 (let ((boundp-function (slot-value slotd 'boundp-function)))
b6bf802c 150 #'(lambda (object)
151 (and
152 (funcall boundp-function object)
153 (funcall getter-function object)))))
4d1fea77 154 ((let ((unbound-value-method
155 (find-applicable-type-method 'unbound-value
156 (slot-definition-type slotd) nil)))
157 (when unbound-value-method
158 (let ((unbound-value
159 (funcall unbound-value-method (slot-definition-type slotd)))
160 (slot-name (slot-definition-name slotd)))
b6bf802c 161 #'(lambda (object)
162 (let ((value (funcall getter-function object)))
163 (if (eq value unbound-value)
164 (slot-unbound (class-of object) object slot-name)
165 value)))))))
64bce834 166 (getter-function)))))
167
168 (setf
169 (slot-value slotd 'writer-function)
170 (if (not (slot-boundp slotd 'setter))
adcadd53 171 #'(lambda (value object)
172 (declare (ignore value object))
173 (error "Slot is not writable: ~A" (slot-definition-name slotd)))
64bce834 174 (with-slots (setter) slotd
935a783c 175 (etypecase setter
176 (function setter)
64bce834 177 ((or symbol cons)
178 #'(lambda (value object)
179 (funcall (fdefinition setter) value object)))
0466f75e 180 (string
64bce834 181 (let ((writer ()))
182 (setf
183 (slot-value slotd 'writer-function)
184 #'(lambda (value object)
185 (unless writer
186 (setq writer
187 (mkbinding setter 'nil 'pointer
188 (slot-definition-type slotd))))
7ce0497d 189 (funcall writer (foreign-location object) value)))))))))
64bce834 190
3d2378de 191 #-sbcl>=0.9.8(initialize-internal-slot-gfs (slot-definition-name slotd)))
935a783c 192
193
194
64bce834 195(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
935a783c 196 nil)
197
6baf860c 198(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
c23cc486 199 (typecase (first direct-slotds)
200 (direct-virtual-slot-definition
201 (let ((initargs ()))
202 (let ((getter (most-specific-slot-value direct-slotds 'getter)))
203 (unless (eq getter *unbound-marker*)
204 (setf (getf initargs :getter) getter)))
205 (let ((setter (most-specific-slot-value direct-slotds 'setter)))
206 (unless (eq setter *unbound-marker*)
207 (setf (getf initargs :setter) setter)))
208 (let ((unbound (most-specific-slot-value direct-slotds 'unbound)))
209 (unless (eq unbound *unbound-marker*)
210 (setf (getf initargs :unbound) unbound)))
211 (let ((boundp (most-specific-slot-value direct-slotds 'boundp)))
212 (unless (eq boundp *unbound-marker*)
213 (setf (getf initargs :boundp) boundp)))
f611f15f 214 ;; Need this to prevent type expansion in SBCL >= 0.9.8
215 (let ((type (most-specific-slot-value direct-slotds 'type)))
216 (unless (eq type *unbound-marker*)
217 (setf (getf initargs :type) type)))
c23cc486 218 (nconc initargs (call-next-method))))
219 (direct-special-slot-definition
220 (append '(:special t) (call-next-method)))
221 (t (call-next-method))))
935a783c 222
b44caf77 223
b44caf77 224(defmethod slot-value-using-class
6baf860c 225 ((class virtual-slots-class) (object standard-object)
b44caf77 226 (slotd effective-virtual-slot-definition))
935a783c 227 (if (funcall (slot-value slotd 'boundp-function) object)
228 (funcall (slot-value slotd 'reader-function) object)
229 (slot-unbound class object (slot-definition-name slotd))))
b44caf77 230
b44caf77 231(defmethod slot-boundp-using-class
6baf860c 232 ((class virtual-slots-class) (object standard-object)
b44caf77 233 (slotd effective-virtual-slot-definition))
935a783c 234 (funcall (slot-value slotd 'boundp-function) object))
235
236(defmethod (setf slot-value-using-class)
6baf860c 237 (value (class virtual-slots-class) (object standard-object)
b44caf77 238 (slotd effective-virtual-slot-definition))
935a783c 239 (funcall (slot-value slotd 'writer-function) value object))
240
241
b44caf77 242(defmethod validate-superclass
6baf860c 243 ((class virtual-slots-class) (super standard-class))
b44caf77 244 t)
245
246
c23cc486 247(defmethod slot-definition-special ((slotd standard-direct-slot-definition))
248 (declare (ignore slotd))
249 nil)
250
251(defmethod slot-definition-special ((slotd standard-effective-slot-definition))
252 (declare (ignore slotd))
253 nil)
254
255
b44caf77 256;;;; Proxy cache
257
b44caf77 258(defvar *instance-cache* (make-hash-table :test #'eql))
259
a2bc0f3a 260(defun cache-instance (instance &optional (weak-ref t))
b44caf77 261 (setf
7ce0497d 262 (gethash (sap-int (foreign-location instance)) *instance-cache*)
a2bc0f3a 263 (if weak-ref
264 (make-weak-pointer instance)
265 instance)))
b44caf77 266
267(defun find-cached-instance (location)
3d36c5d6 268 (let ((ref (gethash (sap-int location) *instance-cache*)))
b44caf77 269 (when ref
a2bc0f3a 270 (if (weak-pointer-p ref)
271 (weak-pointer-value ref)
272 ref))))
b44caf77 273
a5c3a597 274(defun instance-cached-p (location)
3d36c5d6 275 (gethash (sap-int location) *instance-cache*))
a5c3a597 276
b44caf77 277(defun remove-cached-instance (location)
3d36c5d6 278 (remhash (sap-int location) *instance-cache*))
b44caf77 279
6baf860c 280;; For debuging
a2bc0f3a 281(defun list-cached-instances ()
6baf860c 282 (let ((instances ()))
283 (maphash #'(lambda (location ref)
284 (declare (ignore location))
a2bc0f3a 285 (push ref instances))
6baf860c 286 *instance-cache*)
287 instances))
288
2a9afe6f 289;; Instances that gets invalidated tend to be short lived, but created
290;; in large numbers. So we're keeping them in a hash table to be able
291;; to reuse them (and thus reduce consing)
292(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
293
294(defun cache-invalidated-instance (instance)
295 (push instance
296 (gethash (class-of instance) *invalidated-instance-cache*)))
297
298(defun find-invalidated-instance (class)
299 (when (gethash class *invalidated-instance-cache*)
300 (pop (gethash class *invalidated-instance-cache*))))
301
302(defun list-invalidated-instances ()
303 (let ((instances ()))
304 (maphash #'(lambda (location ref)
305 (declare (ignore location))
306 (push ref instances))
307 *invalidated-instance-cache*)
308 instances))
309
b44caf77 310
311
312;;;; Proxy for alien instances
313
253c1339 314;; TODO: add a ref-counted-proxy subclass
6baf860c 315(defclass proxy ()
c23cc486 316 ((location :special t :type pointer))
82defe4d 317 (:metaclass virtual-slots-class))
b44caf77 318
6baf860c 319(defgeneric instance-finalizer (object))
320(defgeneric reference-foreign (class location))
321(defgeneric unreference-foreign (class location))
253c1339 322(defgeneric invalidate-instance (object))
adcadd53 323(defgeneric allocate-foreign (object &key &allow-other-keys))
6baf860c 324
cf45719a 325(defun foreign-location (instance)
326 (slot-value instance 'location))
327
328(defun (setf foreign-location) (location instance)
329 (setf (slot-value instance 'location) location))
330
331(defun proxy-valid-p (instance)
332 (slot-boundp instance 'location))
333
c55abd76 334(defmethod reference-foreign ((name symbol) location)
335 (reference-foreign (find-class name) location))
336
337(defmethod unreference-foreign ((name symbol) location)
338 (unreference-foreign (find-class name) location))
339
6baf860c 340(defmethod unreference-foreign :around ((class class) location)
341 (unless (null-pointer-p location)
7ce0497d 342 (call-next-method)))
b44caf77 343
a5c3a597 344(defmethod print-object ((instance proxy) stream)
345 (print-unreadable-object (instance stream :type t :identity nil)
7ce0497d 346 (if (slot-boundp instance 'location)
347 (format stream "at 0x~X" (sap-int (foreign-location instance)))
4d1fea77 348 (write-string "at <unbound>" stream))))
b44caf77 349
adcadd53 350(defmethod initialize-instance :around ((instance proxy) &rest initargs &key &allow-other-keys)
351 (setf
352 (foreign-location instance)
353 (apply #'allocate-foreign instance initargs))
1d06a422 354 (prog1
355 (call-next-method)
356 (cache-instance instance)
357 (finalize instance (instance-finalizer instance))))
b44caf77 358
359(defmethod instance-finalizer ((instance proxy))
7ce0497d 360 (let ((location (foreign-location instance))
6baf860c 361 (class (class-of instance)))
362;; (unless (find-method #'unreference-foreign nil (list (class-of class) t) nil)
363;; (error "No matching method for UNREFERENCE-INSTANCE when called with class ~A" class))
364 #'(lambda ()
29933e83 365 (remove-cached-instance location)
6baf860c 366 (unreference-foreign class location))))
ba25fa44 367
2a9afe6f 368;; Any reference to the foreign object the instance may have held
369;; should be released before this method is invoked
253c1339 370(defmethod invalidate-instance ((instance proxy))
371 (remove-cached-instance (foreign-location instance))
2a9afe6f 372 (slot-makunbound instance 'location)
373 (cancel-finalization instance)
374 (cache-invalidated-instance instance))
253c1339 375
b44caf77 376
377;;;; Metaclass used for subclasses of proxy
378
3d36c5d6 379(defgeneric most-specific-proxy-superclass (class))
380(defgeneric direct-proxy-superclass (class))
381
382
b44caf77 383(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 384 (defclass proxy-class (virtual-slots-class)
7ce0497d 385 ((size :reader foreign-size)))
b44caf77 386
387 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
c23cc486 388 ((offset :reader slot-definition-offset :initarg :offset))
389 (:default-initargs :allocation :alien))
b44caf77 390
391 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
935a783c 392 ((offset :reader slot-definition-offset :initarg :offset)))
ba25fa44 393
b44caf77 394 (defmethod most-specific-proxy-superclass ((class proxy-class))
395 (find-if
396 #'(lambda (class)
397 (subtypep (class-name class) 'proxy))
935a783c 398 (cdr (compute-class-precedence-list class))))
3d36c5d6 399
ba25fa44 400 (defmethod direct-proxy-superclass ((class proxy-class))
401 (find-if
402 #'(lambda (class)
403 (subtypep (class-name class) 'proxy))
935a783c 404 (class-direct-superclasses class)))
405
64bce834 406 (defmethod shared-initialize ((class proxy-class) names &key size)
b44caf77 407 (call-next-method)
ba25fa44 408 (cond
935a783c 409 (size (setf (slot-value class 'size) (first size)))
6baf860c 410 ((slot-boundp class 'size) (slot-makunbound class 'size))))
7ce0497d 411
935a783c 412 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 413 (case (getf initargs :allocation)
82defe4d 414 (:alien (find-class 'direct-alien-slot-definition))
b44caf77 415 (t (call-next-method))))
935a783c 416
417 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 418 (case (getf initargs :allocation)
419 (:alien (find-class 'effective-alien-slot-definition))
b44caf77 420 (t (call-next-method))))
421
935a783c 422
423 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
c23cc486 424 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
935a783c 425 (nconc
426 (list :offset (most-specific-slot-value direct-slotds 'offset))
427 (call-next-method))
428 (call-next-method)))
429
430
431 (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-definition))
432 (with-slots (offset) slotd
6baf860c 433 (let ((type (slot-definition-type slotd)))
64bce834 434 (unless (slot-boundp slotd 'getter)
6baf860c 435 (let ((reader (reader-function type)))
436 (setf
64bce834 437 (slot-value slotd 'getter)
6baf860c 438 #'(lambda (object)
7ce0497d 439 (funcall reader (foreign-location object) offset)))))
935a783c 440
64bce834 441 (unless (slot-boundp slotd 'setter)
6baf860c 442 (let ((writer (writer-function type))
443 (destroy (destroy-function type)))
444 (setf
64bce834 445 (slot-value slotd 'setter)
6baf860c 446 #'(lambda (value object)
7ce0497d 447 (let ((location (foreign-location object)))
6baf860c 448 (funcall destroy location offset) ; destroy old value
64bce834 449 (funcall writer value location offset))))))))
450
935a783c 451 (call-next-method))
452
fb9bc912 453 (defconstant +struct-alignmen+
454 #+sbcl (/ (sb-alien-internals:alien-type-alignment
455 (sb-alien-internals:parse-alien-type
456 'system-area-pointer nil))
457 8)
458 #-sbcl 4)
b44caf77 459
7ce0497d 460 (defun align-offset (size)
461 (if (zerop (mod size +struct-alignmen+))
462 size
463 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
464
b44caf77 465 (defmethod compute-slots ((class proxy-class))
7ce0497d 466 (let ((alien-slots
467 (remove-if-not
468 #'(lambda (slotd)
469 (eq (slot-definition-allocation slotd) :alien))
470 (class-direct-slots class))))
471 (when alien-slots
472 (loop
473 as offset = (align-offset (foreign-size
474 (most-specific-proxy-superclass class)))
475 then (align-offset
476 (+
477 (slot-definition-offset slotd)
478 (size-of (slot-definition-type slotd))))
479 for slotd in alien-slots
480 unless (slot-boundp slotd 'offset)
481 do (setf (slot-value slotd 'offset) offset))))
b44caf77 482 (call-next-method))
8ae7ddc2 483
935a783c 484 (defmethod validate-superclass ((class proxy-class) (super standard-class))
485 (subtypep (class-name super) 'proxy))
486
7ce0497d 487 (defmethod foreign-size ((class-name symbol))
488 (foreign-size (find-class class-name))))
556b4a05 489
7ce0497d 490(defmethod foreign-size ((object proxy))
491 (foreign-size (class-of object)))
935a783c 492
7ce0497d 493
4d1fea77 494(define-type-method alien-type ((class proxy))
495 (declare (ignore class))
6baf860c 496 (alien-type 'pointer))
497
4d1fea77 498(define-type-method size-of ((class proxy))
499 (declare (ignore class))
6baf860c 500 (size-of 'pointer))
501
4d1fea77 502(define-type-method from-alien-form ((type proxy) location)
503 (let ((class (type-expand type)))
504 `(ensure-proxy-instance ',class ,location)))
6baf860c 505
4d1fea77 506(define-type-method from-alien-function ((type proxy))
507 (let ((class (type-expand type)))
508 #'(lambda (location)
509 (ensure-proxy-instance class location))))
b44caf77 510
4d1fea77 511(define-type-method to-alien-form ((type proxy) instance)
512 (declare (ignore type))
7ce0497d 513 `(foreign-location ,instance))
b44caf77 514
4d1fea77 515(define-type-method to-alien-function ((type proxy))
516 (declare (ignore type))
7ce0497d 517 #'foreign-location)
6baf860c 518
4d1fea77 519(define-type-method copy-from-alien-form ((type proxy) location)
520 (let ((class (type-expand type)))
521 `(ensure-proxy-instance ',class (reference-foreign ',class ,location))))
522
523(define-type-method copy-from-alien-function ((type proxy))
524 (let ((class (type-expand type)))
525 #'(lambda (location)
526 (ensure-proxy-instance class (reference-foreign class location)))))
527
528(define-type-method copy-to-alien-form ((type proxy) instance)
529 (let ((class (type-expand type)))
530 `(reference-foreign ',class (foreign-location ,instance))))
531
532(define-type-method copy-to-alien-function ((type proxy))
533 (let ((class (type-expand type)))
534 #'(lambda (instance)
535 (reference-foreign class (foreign-location instance)))))
536
537(define-type-method writer-function ((type proxy))
538 (let ((class (type-expand type)))
539 #'(lambda (instance location &optional (offset 0))
540 (assert (null-pointer-p (sap-ref-sap location offset)))
541 (setf
542 (sap-ref-sap location offset)
543 (reference-foreign class (foreign-location instance))))))
544
545(define-type-method reader-function ((type proxy))
546 (let ((class (type-expand type)))
547 #'(lambda (location &optional (offset 0) weak-p)
548 (declare (ignore weak-p))
549 (let ((instance (sap-ref-sap location offset)))
550 (unless (null-pointer-p instance)
551 (ensure-proxy-instance class (reference-foreign class instance)))))))
552
553(define-type-method destroy-function ((type proxy))
554 (let ((class (type-expand type)))
555 #'(lambda (location &optional (offset 0))
556 (unreference-foreign class (sap-ref-sap location offset)))))
557
558(define-type-method unbound-value ((type proxy))
559 (declare (ignore type))
560 nil)
6baf860c 561
1d06a422 562(defun ensure-proxy-instance (class location &rest initargs)
563 "Returns a proxy object representing the foreign object at the give
564location. If an existing object is not found in the cache
565MAKE-PROXY-INSTANCE is called to create one."
6baf860c 566 (unless (null-pointer-p location)
567 (or
e4a48e09 568 #-debug-ref-counting(find-cached-instance location)
569 #+debug-ref-counting
253c1339 570 (let ((instance (find-cached-instance location)))
571 (when instance
572 (format t "Object found in cache: ~A~%" instance)
573 instance))
1d06a422 574 (let ((instance (apply #'make-proxy-instance class location initargs)))
575 (cache-instance instance)
576 instance))))
577
578(defgeneric make-proxy-instance (class location &key weak)
579 (:documentation "Creates a new proxy object representing the foreign
580object at the give location. If WEAK is non NIL the foreign memory
581will not be released when the proxy is garbage collected."))
582
253c1339 583(defmethod make-proxy-instance ((class symbol) location &rest initargs)
584 (apply #'make-proxy-instance (find-class class) location initargs))
1d06a422 585
586(defmethod make-proxy-instance ((class proxy-class) location &key weak)
2a9afe6f 587 (let ((instance
588 (or
589 (find-invalidated-instance class)
590 (allocate-instance class))))
cf45719a 591 (setf (foreign-location instance) location)
1d06a422 592 (unless weak
593 (finalize instance (instance-finalizer instance)))
594 instance))
b44caf77 595
ba25fa44 596
597;;;; Superclasses for wrapping of C structures
b44caf77 598
6baf860c 599(defclass struct (proxy)
600 ()
7ce0497d 601 (:metaclass proxy-class)
602 (:size 0))
b44caf77 603
adcadd53 604(defmethod allocate-foreign ((struct struct) &rest initargs)
b44caf77 605 (declare (ignore initargs))
adcadd53 606 (let ((size (foreign-size (class-of struct))))
607 (if (zerop size)
608 (error "~A has zero size" (class-of struct))
609 (allocate-memory size))))
b44caf77 610
611
6baf860c 612;;;; Metaclasses used for subclasses of struct
613
4d1fea77 614(eval-when (:compile-toplevel :load-toplevel :execute)
615 (defclass struct-class (proxy-class)
616 ()))
b44caf77 617
82defe4d 618(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
619 (if (not (getf initargs :allocation))
620 (find-class 'direct-alien-slot-definition)
621 (call-next-method)))
622
6baf860c 623(defmethod reference-foreign ((class struct-class) location)
7ce0497d 624 (copy-memory location (foreign-size class)))
6baf860c 625
626(defmethod unreference-foreign ((class struct-class) location)
ba25fa44 627 (deallocate-memory location))
b44caf77 628
3d2378de 629(defmethod compute-slots :around ((class struct-class))
630 (let ((slots (call-next-method)))
631 (when (and
c23cc486 632 #-sbcl>=0.9.8(class-finalized-p class)
3d2378de 633 (not (slot-boundp class 'size)))
634 (let ((size (loop
635 for slotd in slots
636 when (eq (slot-definition-allocation slotd) :alien)
637 maximize (+
638 (slot-definition-offset slotd)
639 (size-of (slot-definition-type slotd))))))
640 (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+)))))
641 slots))
7ce0497d 642
4d1fea77 643(define-type-method callback-from-alien-form ((type struct) form)
644 (let ((class (type-expand type)))
645 `(ensure-proxy-instance ',class ,form :weak t)))
646
647(define-type-method callback-cleanup-form ((type struct) form)
648 (declare (ignore type))
649 `(invalidate-instance ,form))
650
651(define-type-method reader-function ((type struct))
652 (let ((class (type-expand type)))
653 #'(lambda (location &optional (offset 0) weak-p)
654 (let ((instance (sap-ref-sap location offset)))
655 (unless (null-pointer-p instance)
656 (if weak-p
657 (ensure-proxy-instance class instance :weak t)
658 (ensure-proxy-instance class (reference-foreign class instance))))))))
253c1339 659
b44caf77 660
6baf860c 661(defclass static-struct-class (struct-class)
662 ())
b44caf77 663
6baf860c 664(defmethod reference-foreign ((class static-struct-class) location)
665 (declare (ignore class))
ba25fa44 666 location)
b44caf77 667
6baf860c 668(defmethod unreference-foreign ((class static-struct-class) location)
669 (declare (ignore class location))
ba25fa44 670 nil)
b4edcbf0 671
b4edcbf0 672;;; Pseudo type for structs which are inlined in other objects
673
4d1fea77 674(deftype inlined (type) type)
b4edcbf0 675
4d1fea77 676(define-type-method size-of ((type inlined))
677 (let ((class (type-expand (second type))))
678 (foreign-size class)))
679
680(define-type-method reader-function ((type inlined))
681 (let ((class (type-expand (second type))))
0739b019 682 #'(lambda (location &optional (offset 0) weak-p)
683 (declare (ignore weak-p))
b4edcbf0 684 (ensure-proxy-instance class
685 (reference-foreign class (sap+ location offset))))))
686
4d1fea77 687(define-type-method writer-function ((type inlined))
688 (let ((class (type-expand (second type))))
253c1339 689 #'(lambda (instance location &optional (offset 0))
690 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
691
b4edcbf0 692(export 'inlined)