1 ;; Common Lisp bindings for GTK+ v2.0
2 ;; Copyright (C) 1999-2000 Espen S. Johnsen <espejohn@online.no>
4 ;; This library is free software; you can redistribute it and/or
5 ;; modify it under the terms of the GNU Lesser General Public
6 ;; License as published by the Free Software Foundation; either
7 ;; version 2 of the License, or (at your option) any later version.
9 ;; This library is distributed in the hope that it will be useful,
10 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ;; Lesser General Public License for more details.
14 ;; You should have received a copy of the GNU Lesser General Public
15 ;; License along with this library; if not, write to the Free Software
16 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ;; $Id: gforeign.lisp,v 1.5 2000-10-01 17:19:11 espen Exp $
24 (defvar *type-methods* (make-hash-table))
26 (defun ensure-type-method-fun (fname)
27 (unless (fboundp fname)
29 (symbol-function fname)
30 #'(lambda (type-spec &rest args)
32 (find-applicable-type-method type-spec fname) type-spec args)))))
34 (defmacro define-type-method-fun (fname lambda-list)
35 (declare (ignore lambda-list))
36 `(defun ,fname (type-spec &rest args)
38 (find-applicable-type-method type-spec ',fname) type-spec args)))
41 (defun ensure-type-name (type)
44 (pcl::class (class-name type))))
46 (defun add-type-method (type fname function)
49 (gethash (ensure-type-name type) *type-methods*)))
51 (defun find-type-method (type fname)
52 (cdr (assoc fname (gethash (ensure-type-name type) *type-methods*))))
54 (defun find-applicable-type-method (type-spec fname &optional (error t))
55 (flet ((find-superclass-method (class)
57 (dolist (super (cdr (pcl::class-precedence-list class)))
58 (return-if (find-type-method super fname)))))
59 (find-expanded-type-method (type-spec)
60 (multiple-value-bind (expanded-type-spec expanded-p)
61 (type-expand-1 type-spec)
64 (find-applicable-type-method expanded-type-spec fname nil))
66 (find-applicable-type-method t fname nil))))))
72 (find-type-method type-spec fname)
73 (find-superclass-method type-spec)))
76 (find-type-method type-spec fname)
77 (find-expanded-type-method type-spec)
78 (find-superclass-method (find-class type-spec nil))))
81 (find-type-method (first type-spec) fname)
82 (find-expanded-type-method type-spec)))
84 (error "Invalid type specifier ~A" type-spec)))
88 "No applicable method for ~A when called with type specifier ~A"
91 (defmacro deftype-method (fname type lambda-list &body body)
93 (ensure-type-method-fun ',fname)
94 (add-type-method ',type ',fname #'(lambda ,lambda-list ,@body))
97 (defmacro deftype (name parameters &body body)
98 (destructuring-bind (lisp-name &optional alien-name) (mklist name)
101 `(setf (alien-type-name ',lisp-name) ,alien-name))
102 (lisp:deftype ,lisp-name ,parameters ,@body))))
104 ;; To make the compiler shut up
105 (eval-when (:compile-toplevel :load-toplevel :execute)
106 (define-type-method-fun translate-type-spec (type-spec))
107 (define-type-method-fun size-of (type-spec))
108 (define-type-method-fun translate-to-alien (type-spec expr &optional copy))
109 (define-type-method-fun translate-from-alien (type-spec expr &optional alloc))
110 (define-type-method-fun cleanup-alien (type-spec alien &optional copied)))
115 (defvar *type-function-cache* (make-hash-table :test #'equal))
117 (defun get-cached-function (type-spec fname)
118 (cdr (assoc fname (gethash type-spec *type-function-cache*))))
120 (defun set-cached-function (type-spec fname function)
121 (push (cons fname function) (gethash type-spec *type-function-cache*))
125 ;; Creates a function to translate an object of the specified type
126 ;; from lisp to alien representation.
127 (defun get-to-alien-function (type-spec)
129 (get-cached-function type-spec 'to-alien-function)
130 (set-cached-function type-spec 'to-alien-function
134 (declare (ignorable object))
135 ,(translate-to-alien type-spec 'object))))))
138 (defun get-from-alien-function (type-spec)
140 (get-cached-function type-spec 'from-alien-function)
141 (set-cached-function type-spec 'from-alien-function
145 (declare (ignorable alien))
146 ,(translate-from-alien type-spec 'alien))))))
148 ;; and for cleaning up
149 (defun get-cleanup-function (type-spec)
151 (get-cached-function type-spec 'cleanup-function)
152 (set-cached-function type-spec 'cleanup-function
156 (declare (ignorable alien))
157 ,(cleanup-alien type-spec 'alien))))))
161 ;; Creates a function to write an object of the specified type
162 ;; to the given memory location
163 (defun get-writer-function (type-spec)
165 (get-cached-function type-spec 'writer-function)
166 (set-cached-function type-spec 'writer-function
169 `(lambda (value sap offset)
170 (declare (ignorable value sap offset))
172 (,(sap-ref-fname type-spec) sap offset)
173 ,(translate-to-alien type-spec 'value :copy)))))))
175 ;; Creates a function to read an object of the specified type
176 ;; from the given memory location
177 (defun get-reader-function (type-spec)
179 (get-cached-function type-spec 'reader-function)
180 (set-cached-function type-spec 'reader-function
183 `(lambda (sap offset)
184 (declare (ignorable sap offset))
185 ,(translate-from-alien
186 type-spec `(,(sap-ref-fname type-spec) sap offset) :reference))))))
189 (defun get-destroy-function (type-spec)
191 (get-cached-function type-spec 'destroy-function)
192 (set-cached-function type-spec 'destroy-function
195 `(lambda (sap offset)
196 (declare (ignorable sap offset))
198 type-spec `(,(sap-ref-fname type-spec) sap offset) :copied))))))
204 (defconstant +bits-per-unit+ 8
205 "Number of bits in an addressable unit (byte)")
207 ;; Sizes of fundamental C types in addressable units
208 (defconstant +size-of-short+ 2)
209 (defconstant +size-of-int+ 4)
210 (defconstant +size-of-long+ 4)
211 (defconstant +size-of-sap+ 4)
212 (defconstant +size-of-float+ 4)
213 (defconstant +size-of-double+ 8)
215 (defun sap-ref-unsigned (sap offset)
216 (sap-ref-32 sap offset))
218 (defun sap-ref-signed (sap offset)
219 (signed-sap-ref-32 sap offset))
221 (defun sap-ref-fname (type-spec)
222 (let ((alien-type-spec (mklist (translate-type-spec type-spec))))
223 (ecase (first alien-type-spec)
225 (ecase (second alien-type-spec)
231 (ecase (second alien-type-spec)
232 (8 'signed-sap-ref-8)
233 (16 'signed-sap-ref-16)
234 (32 'signed-sap-ref-32)
235 (64 'signed-sap-ref-64)))
236 (system-area-pointer 'sap-ref-sap)
237 (single-float 'sap-ref-single)
238 (double-float 'sap-ref-double))))
241 ;;;; Foreign function call interface
243 (defvar *package-prefix* nil)
245 (defun set-package-prefix (prefix &optional (package *package*))
246 (let ((package (find-package package)))
247 (delete-if #'(lambda (assoc) (eq (car assoc) package)) *package-prefix*)
248 (push (cons package prefix) *package-prefix*))
251 (defun package-prefix (&optional (package *package*))
252 (let ((package (find-package package)))
254 (cdr (assoc package *package-prefix*))
255 (substitute #\_ #\- (string-downcase (package-name package))))))
257 (defmacro use-prefix (prefix &optional (package *package*))
258 `(eval-when (:compile-toplevel :load-toplevel :execute)
259 (set-package-prefix ,prefix ,package)))
262 (defun default-alien-func-name (lisp-name)
263 (let* ((lisp-name-string
264 (if (char= (char (the simple-string (string lisp-name)) 0) #\%)
265 (subseq (the simple-string (string lisp-name)) 1)
267 (prefix (package-prefix *package*))
268 (name (substitute #\_ #\- (string-downcase lisp-name-string))))
269 (if (or (not prefix) (string= prefix ""))
271 (format nil "~A_~A" prefix name))))
274 (defmacro define-foreign (name lambda-list return-type-spec &rest docs/args)
275 (multiple-value-bind (c-name lisp-name)
277 (values (default-alien-func-name name) name)
279 (let ((supplied-lambda-list lambda-list)
282 (dolist (doc/arg docs/args)
283 (if (stringp doc/arg)
286 (destructuring-bind (expr type &optional (style :in)) doc/arg
287 (unless (member style '(:in :out :in-out))
288 (error "Bogus argument style ~S in ~S." style doc/arg))
290 (not supplied-lambda-list)
291 (namep expr) (member style '(:in :in-out)))
292 (push expr lambda-list))
294 (list (if (namep expr) expr (gensym)) expr type style) args)))))
297 c-name lisp-name (or supplied-lambda-list (nreverse lambda-list))
298 return-type-spec (reverse docs) (reverse args)))))
302 (defun %define-foreign (foreign-name lisp-name lambda-list
303 return-type-spec docs args)
304 (ext:collect ((alien-types) (alien-bindings) (alien-parameters)
305 (alien-values) (alien-deallocators))
307 (destructuring-bind (var expr type-spec style) arg
308 (let ((declaration (translate-type-spec type-spec))
309 (deallocation (cleanup-alien type-spec expr)))
311 ((member style '(:out :in-out))
312 (alien-types `(* ,declaration))
313 (alien-parameters `(addr ,var))
316 ,@(when (eq style :in-out)
317 (list (translate-to-alien type-spec expr)))))
318 (alien-values (translate-from-alien type-spec var)))
320 (alien-types declaration)
322 `(,var ,declaration ,(translate-to-alien type-spec expr)))
323 (alien-parameters var)
324 (alien-deallocators deallocation))
326 (alien-types declaration)
327 (alien-parameters (translate-to-alien type-spec expr)))))))
329 (let ((alien-funcall `(alien-funcall ,lisp-name ,@(alien-parameters))))
330 `(defun ,lisp-name ,lambda-list
332 (with-alien ((,lisp-name
334 ,(translate-type-spec return-type-spec)
336 :extern ,foreign-name)
338 ,(if return-type-spec
340 ,(translate-from-alien return-type-spec alien-funcall)))
341 ,@(alien-deallocators)
342 (values result ,@(alien-values)))
345 ,@(alien-deallocators)
346 (values ,@(alien-values)))))))))
351 ;;;; Definitons and translations of fundamental types
353 (lisp:deftype long (&optional (min '*) (max '*)) `(integer ,min ,max))
354 (lisp:deftype unsigned-long (&optional (min '*) (max '*)) `(integer ,min ,max))
355 (lisp:deftype int (&optional (min '*) (max '*)) `(long ,min ,max))
356 (lisp:deftype unsigned-int (&optional (min '*) (max '*)) `(unsigned-long ,min ,max))
357 (lisp:deftype short (&optional (min '*) (max '*)) `(int ,min ,max))
358 (lisp:deftype unsigned-short (&optional (min '*) (max '*)) `(unsigned-int ,min ,max))
359 (lisp:deftype signed (&optional (size '*)) `(signed-byte ,size))
360 (lisp:deftype unsigned (&optional (size '*)) `(signed-byte ,size))
361 (lisp:deftype char () 'base-char)
362 (lisp:deftype pointer () 'system-area-pointer)
363 (lisp:deftype boolean (&optional (size '*))
364 (declare (ignore size))
366 (lisp:deftype static (type) type)
367 (lisp:deftype invalid () nil)
371 (deftype-method cleanup-alien t (type-spec alien &optional copied)
372 (declare (ignore type-spec alien copied))
376 (deftype-method translate-to-alien integer (type-spec number &optional copy)
377 (declare (ignore type-spec copy))
380 (deftype-method translate-from-alien integer (type-spec number &optional alloc)
381 (declare (ignore type-spec alloc))
385 (deftype-method translate-type-spec fixnum (type-spec)
386 (declare (ignore type-spec))
387 (translate-type-spec 'signed))
389 (deftype-method size-of fixnum (type-spec)
390 (declare (ignore type-spec))
393 (deftype-method translate-to-alien fixnum (type-spec number &optional copy)
394 (declare (ignore type-spec copy))
397 (deftype-method translate-from-alien fixnum (type-spec number &optional alloc)
398 (declare (ignore type-spec alloc))
402 (deftype-method translate-type-spec long (type-spec)
403 (declare (ignore type-spec))
404 `(signed ,(* +bits-per-unit+ +size-of-long+)))
406 (deftype-method size-of long (type-spec)
407 (declare (ignore type-spec))
411 (deftype-method translate-type-spec unsigned-long (type-spec)
412 (declare (ignore type-spec))
413 `(unsigned ,(* +bits-per-unit+ +size-of-long+)))
415 (deftype-method size-of unsigned-long (type-spec)
416 (declare (ignore type-spec))
420 (deftype-method translate-type-spec int (type-spec)
421 (declare (ignore type-spec))
422 `(signed ,(* +bits-per-unit+ +size-of-int+)))
424 (deftype-method size-of int (type-spec)
425 (declare (ignore type-spec))
429 (deftype-method translate-type-spec unsigned-int (type-spec)
430 (declare (ignore type-spec))
431 `(signed ,(* +bits-per-unit+ +size-of-int+)))
433 (deftype-method size-of unsigned-int (type-spec)
434 (declare (ignore type-spec))
438 (deftype-method translate-type-spec short (type-spec)
439 (declare (ignore type-spec))
440 `(signed ,(* +bits-per-unit+ +size-of-short+)))
442 (deftype-method size-of short (type-spec)
443 (declare (ignore type-spec))
447 (deftype-method translate-type-spec unsigned-short (type-spec)
448 (declare (ignore type-spec))
449 `(unsigned ,(* +bits-per-unit+ +size-of-short+)))
451 (deftype-method size-of unsigned-short (type-spec)
452 (declare (ignore type-spec))
456 (deftype-method translate-type-spec signed-byte (type-spec)
457 (let ((size (second (mklist (type-expand-to 'signed-byte type-spec)))))
460 ((member size '(nil *)) (* +bits-per-unit+ +size-of-int+))
463 (deftype-method size-of signed-byte (type-spec)
464 (let ((size (second (mklist (type-expand-to 'signed-byte type-spec)))))
466 ((member size '(nil *)) +size-of-int+)
467 (t (/ size +bits-per-unit+)))))
469 (deftype-method translate-to-alien signed-byte (type-spec number &optional copy)
470 (declare (ignore type-spec copy))
473 (deftype-method translate-from-alien signed-byte
474 (type-spec number &optional alloc)
475 (declare (ignore type-spec alloc))
479 (deftype-method translate-type-spec unsigned-byte (type-spec)
480 (let ((size (second (mklist (type-expand-to 'unsigned-byte type-spec)))))
483 ((member size '(nil *)) (* +bits-per-unit+ +size-of-int+))
486 (deftype-method size-of unsigned-byte (type-spec)
487 (let ((size (second (mklist (type-expand-to 'unsigned-byte type-spec)))))
489 ((member size '(nil *)) +size-of-int+)
490 (t (/ size +bits-per-unit+)))))
492 (deftype-method translate-to-alien unsigned-byte
493 (type-spec number &optional copy)
494 (declare (ignore type-spec copy))
497 (deftype-method translate-from-alien unsigned-byte
498 (type-spec number &optional alloc)
499 (declare (ignore type-spec alloc))
503 (deftype-method translate-type-spec single-float (type-spec)
504 (declare (ignore type-spec))
507 (deftype-method size-of single-float (type-spec)
508 (declare (ignore type-spec))
511 (deftype-method translate-to-alien single-float
512 (type-spec number &optional copy)
513 (declare (ignore type-spec copy))
516 (deftype-method translate-from-alien single-float
517 (type-spec number &optional alloc)
518 (declare (ignore type-spec alloc))
522 (deftype-method translate-type-spec double-float (type-spec)
523 (declare (ignore type-spec))
526 (deftype-method size-of double-float (type-spec)
527 (declare (ignore type-spec))
530 (deftype-method translate-to-alien double-float
531 (type-spec number &optional copy)
532 (declare (ignore type-spec copy))
535 (deftype-method translate-from-alien double-float
536 (type-spec number &optional alloc)
537 (declare (ignore type-spec alloc))
541 (deftype-method translate-type-spec base-char (type-spec)
542 (declare (ignore type-spec))
543 '(unsigned +bits-per-unit+))
545 (deftype-method size-of base-char (type-spec)
546 (declare (ignore type-spec))
549 (deftype-method translate-to-alien base-char (type-spec char &optional copy)
550 (declare (ignore type-spec copy))
553 (deftype-method translate-from-alien base-char (type-spec code &optional alloc)
554 (declare (ignore type-spec alloc))
558 (deftype-method translate-type-spec string (type-spec)
559 (declare (ignore type-spec))
560 'system-area-pointer)
562 (deftype-method size-of string (type-spec)
563 (declare (ignore type-spec))
566 (deftype-method translate-to-alien string (type-spec string &optional copy)
567 (declare (ignore type-spec))
569 `(let ((string ,string))
571 (make-pointer (1+ (kernel:get-lisp-obj-address string)))
572 (1+ (length string))))
573 `(make-pointer (1+ (kernel:get-lisp-obj-address ,string)))))
575 (deftype-method translate-from-alien string
576 (type-spec sap &optional (alloc :copy))
577 (declare (ignore type-spec))
579 (unless (null-pointer-p sap)
581 (c-call::%naturalize-c-string sap)
582 ;,(when (eq alloc :copy) `(deallocate-memory ,sap))
585 (deftype-method cleanup-alien string (type-spec sap &optional copied)
586 (declare (ignore type-spec))
589 (unless (null-pointer-p sap)
590 (deallocate-memory sap)))))
593 (deftype-method translate-type-spec boolean (type-spec)
595 (cons 'unsigned (cdr (mklist (type-expand-to 'boolean type-spec))))))
597 (deftype-method size-of boolean (type-spec)
599 (cons 'unsigned (cdr (mklist (type-expand-to 'boolean type-spec))))))
601 (deftype-method translate-to-alien boolean (type-spec boolean &optional copy)
602 (declare (ignore type-spec copy))
605 (deftype-method translate-from-alien boolean (type-spec int &optional alloc)
606 (declare (ignore type-spec alloc))
610 (deftype-method translate-type-spec or (union-type)
611 (let* ((member-types (cdr (type-expand-to 'or union-type)))
612 (alien-type (translate-type-spec (first member-types))))
613 (dolist (type (cdr member-types))
614 (unless (eq alien-type (translate-type-spec type))
615 (error "No common alien type specifier for union type: ~A" union-type)))
618 (deftype-method size-of or (union-type)
619 (size-of (first (cdr (type-expand-to 'or union-type)))))
621 (deftype-method translate-to-alien or (union-type-spec expr &optional copy)
622 (destructuring-bind (name &rest type-specs)
623 (type-expand-to 'or union-type-spec)
624 (declare (ignore name))
625 `(let ((value ,expr))
629 #'(lambda (type-spec)
630 (list type-spec (translate-to-alien type-spec 'value copy)))
634 (deftype-method translate-type-spec system-area-pointer (type-spec)
635 (declare (ignore type-spec))
636 'system-area-pointer)
638 (deftype-method size-of system-area-pointer (type-spec)
639 (declare (ignore type-spec))
642 (deftype-method translate-to-alien system-area-pointer
643 (type-spec sap &optional copy)
644 (declare (ignore type-spec copy))
647 (deftype-method translate-from-alien system-area-pointer
648 (type-spec sap &optional alloc)
649 (declare (ignore type-spec alloc))
653 (deftype-method translate-type-spec null (type-spec)
654 (declare (ignore type-spec))
655 'system-area-pointer)
657 (deftype-method translate-to-alien null (type-spec expr &optional copy)
658 (declare (ignore type-spec expr copy))
662 (deftype-method translate-type-spec nil (type-spec)
663 (declare (ignore type-spec))
667 (deftype-method transalte-type-spec static (type-spec)
668 (translate-type-spec (second type-spec)))
670 (deftype-method size-of static (type-spec)
673 (deftype-method translate-to-alien static (type-spec expr &optional copy)
674 (declare (ignore copy))
675 (translate-to-alien (second type-spec) expr nil))
677 (deftype-method translate-from-alien static (type-spec alien &optional alloc)
678 (declare (ignore alloc))
679 (translate-from-alien (second type-spec) alien nil))
681 (deftype-method cleanup-alien static (type-spec alien &optional copied)
682 (declare (ignore copied))
683 (cleanup-alien type-spec alien nil))
687 ;;;; Enum and flags type
689 (defun map-mappings (args op)
690 (let ((current-value 0))
694 (destructuring-bind (symbol &optional (value current-value))
696 (setf current-value (1+ value))
698 (:enum-int (list symbol value))
699 (:flags-int (list symbol (ash 1 value)))
700 (:int-enum (list value symbol))
701 (:int-flags (list (ash 1 value) symbol))
703 (if (integerp (first args))
708 (lisp:deftype enum (&rest args)
709 `(member ,@(map-mappings args :symbols)))
711 (deftype-method translate-type-spec enum (type-spec)
712 (let ((args (cdr (type-expand-to 'enum type-spec))))
713 (if (integerp (first args))
714 (translate-type-spec `(signed ,(first args)))
715 (translate-type-spec 'signed))))
717 (deftype-method size-of enum (type-spec)
718 (let ((args (cdr (type-expand-to 'enum type-spec))))
719 (if (integerp (first args))
720 (size-of `(signed ,(first args)))
723 (deftype-method translate-to-alien enum (type-spec expr &optional copy)
724 (declare (ignore copy))
725 (let ((args (cdr (type-expand-to 'enum type-spec))))
727 ,@(map-mappings args :enum-int))))
729 (deftype-method translate-from-alien enum (type-spec expr &optional alloc)
730 (declare (ignore alloc))
731 (destructuring-bind (name &rest args) (type-expand-to 'enum type-spec)
732 (declare (ignore name))
734 ,@(map-mappings args :int-enum))))
737 (lisp:deftype flags (&rest args)
741 (member ,@(map-mappings args :symbols))
744 (deftype-method translate-type-spec flags (type-spec)
745 (let ((args (cdr (type-expand-to 'flags type-spec))))
746 (if (integerp (first args))
747 (translate-type-spec `(signed ,(first args)))
748 (translate-type-spec 'signed))))
750 (deftype-method size-of flags (type-spec)
751 (let ((args (cdr (type-expand-to 'flags type-spec))))
752 (if (integerp (first args))
753 (size-of `(signed ,(first args)))
756 (deftype-method translate-to-alien flags (type-spec expr &optional copy)
757 (declare (ignore copy))
758 (destructuring-bind (name &rest args) (type-expand-to 'flags type-spec)
759 (declare (ignore name))
760 (let ((mappings (map-mappings args :flags-int))
761 (value (make-symbol "VALUE")))
763 (dolist (flag ,expr ,value)
764 (setq ,value (logior ,value (second (assoc flag ',mappings)))))))))
766 (deftype-method translate-from-alien flags (type-spec expr &optional alloc)
767 (declare (ignore alloc))
768 (destructuring-bind (name &rest args) (type-expand-to 'flags type-spec)
769 (declare (ignore name))
770 (let ((mappings (map-mappings args :int-flags))
771 (result (make-symbol "RESULT")))
772 `(let ((,result nil))
773 (dolist (mapping ',mappings ,result)
774 (unless (zerop (logand ,expr (first mapping)))
775 (push (second mapping) ,result)))))))