-;; Common Lisp bindings for GTK+ v2.0
-;; Copyright (C) 1999-2001 Espen S. Johnsen <esj@stud.cs.uit.no>
+;; Common Lisp bindings for GTK+ v2.x
+;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
;;
-;; This library is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU Lesser General Public
-;; License as published by the Free Software Foundation; either
-;; version 2 of the License, or (at your option) any later version.
+;; Permission is hereby granted, free of charge, to any person obtaining
+;; a copy of this software and associated documentation files (the
+;; "Software"), to deal in the Software without restriction, including
+;; without limitation the rights to use, copy, modify, merge, publish,
+;; distribute, sublicense, and/or sell copies of the Software, and to
+;; permit persons to whom the Software is furnished to do so, subject to
+;; the following conditions:
;;
-;; This library is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; Lesser General Public License for more details.
+;; The above copyright notice and this permission notice shall be
+;; included in all copies or substantial portions of the Software.
;;
-;; You should have received a copy of the GNU Lesser General Public
-;; License along with this library; if not, write to the Free Software
-;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-;; $Id: ffi.lisp,v 1.13 2005/02/03 23:09:03 espen Exp $
+;; $Id: ffi.lisp,v 1.24 2006/02/19 19:17:45 espen Exp $
(in-package "GLIB")
(alien-parameters `(addr ,var))
(alien-bindings
`(,var ,declaration
- ,@(when (eq style :in-out)
- (list (to-alien-form expr type)))))
+ ,@(cond
+ ((eq style :in-out) (list (to-alien-form expr type)))
+ ((eq declaration 'system-area-pointer)
+ (list '(make-pointer 0))))))
(return-values (from-alien-form var type)))
((eq style :return)
(alien-types declaration)
(%heap-alien
(make-heap-alien-info
:type (parse-alien-type ftype #+sbcl nil)
- :sap-form (foreign-symbol-address name))))
+ :sap-form (let ((address (foreign-symbol-address name)))
+ (etypecase address
+ (integer (int-sap address))
+ (system-area-pointer address))))))
(translate-arguments (mapcar #'to-alien-function arg-types))
(translate-return-value (from-alien-function return-type))
(cleanup-arguments (mapcar #'cleanup-function arg-types)))
(mapc #'funcall cleanup-arguments args)))))
-(defmacro defcallback (name (return-type &rest args) &body body)
- (let ((def-callback #+cmu'alien:def-callback
- #+sbcl'sb-alien:define-alien-function))
- `(,def-callback ,name
- (,(alien-type return-type)
- ,@(mapcar #'(lambda (arg)
- (destructuring-bind (name type) arg
- `(,name ,(alien-type type))))
- args))
- ,(to-alien-form
- `(let (,@(mapcar #'(lambda (arg)
- (destructuring-bind (name type) arg
- `(,name ,(from-alien-form name type))))
- args))
- ,@body)
- return-type))))
+
+;;;; C callbacks
+
+(defmacro define-callback (name return-type args &body body)
+ (let ((define-callback
+ #+cmu'alien:def-callback
+ #+(and sbcl alien-callbacks)'sb-alien::define-alien-callback
+ #+(and sbcl (not alien-callbacks))'sb-alien:define-alien-function))
+ (multiple-value-bind (doc declaration body)
+ (cond
+ ((and (stringp (first body)) (eq (cadr body) 'declare))
+ (values (first body) (second body) (cddr body)))
+ ((stringp (first body))
+ (values (first body) nil (rest body)))
+ ((eq (caar body) 'declare)
+ (values nil (first body) (rest body)))
+ (t (values nil nil body)))
+ `(,define-callback ,name
+ #+(and sbcl alien-callbacks),(alien-type return-type)
+ (#+(or cmu (and sbcl (not alien-callbacks))),(alien-type return-type)
+ ,@(mapcar #'(lambda (arg)
+ (destructuring-bind (name type) arg
+ `(,name ,(alien-type type))))
+ args))
+ ,@(when doc (list doc))
+ ,(to-alien-form
+ `(let (,@(loop
+ for (name type) in args
+ as from-alien-form = (callback-from-alien-form name type)
+ collect `(,name ,from-alien-form)))
+ ,@(when declaration (list declaration))
+ (unwind-protect
+ (progn ,@body)
+ ,@(loop
+ for (name type) in args
+ do (callback-cleanup-form name type))))
+
+ return-type)))))
+
+(defun callback-address (callback)
+ #+cmu(alien::callback-trampoline callback)
+ #+(and sbcl (not alien-callbacks))(sb-alien:alien-function-sap callback)
+ #+(and sbcl alien-callbacks)(sb-alien:alien-sap callback))
#+sbcl
-(defun callback (af)
- (sb-alien:alien-function-sap af))
+(deftype callback ()
+ #-alien-callbacks'sb-alien:alien-function
+ #+alien-callbacks'sb-alien:alien)
+
+
+;;; These are for backward compatibility
+
+(defmacro defcallback (name (return-type &rest args) &body body)
+ `(define-callback ,name ,return-type ,args ,@body))
+
+#-cmu
+(defun callback (callback)
+ (callback-address callback))
+
;;;; Definitons and translations of fundamental types
(def-type-method from-alien-form (form))
(def-type-method cleanup-form (form)
"Creates a form to clean up after the alien call has finished.")
+(def-type-method callback-from-alien-form (form))
+(def-type-method callback-cleanup-form (form))
(def-type-method to-alien-function ())
(def-type-method from-alien-function ())
(declare (ignore type args))
#'identity)
+(defmethod callback-from-alien-form (form (type t) &rest args)
+ (apply #'copy-from-alien-form form type args))
+
+(defmethod callback-cleanup-form (form (type t) &rest args)
+ (declare (ignore form type args))
+ nil)
+
(defmethod destroy-function ((type t) &rest args)
(declare (ignore type args))
#'(lambda (location &optional offset)
(defmethod copy-from-alien-function ((type t) &rest args)
(apply #'from-alien-function type args))
-
(defmethod alien-type ((type (eql 'signed-byte)) &rest args)
(declare (ignore type))
(destructuring-bind (&optional (size '*)) args
(destructuring-bind (&optional (size '*)) args
(let ((size (if (eq size '*) +bits-of-int+ size)))
(ecase size
- (8 #'(lambda (sap &optional (offset 0))
+ (8 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(signed-sap-ref-8 sap offset)))
- (16 #'(lambda (sap &optional (offset 0))
+ (16 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(signed-sap-ref-16 sap offset)))
- (32 #'(lambda (sap &optional (offset 0))
+ (32 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(signed-sap-ref-32 sap offset)))
- (64 #'(lambda (sap &optional (offset 0))
+ (64 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(signed-sap-ref-64 sap offset)))))))
(defmethod alien-type ((type (eql 'unsigned-byte)) &rest args)
(destructuring-bind (&optional (size '*)) args
(let ((size (if (eq size '*) +bits-of-int+ size)))
(ecase size
- (8 #'(lambda (sap &optional (offset 0))
+ (8 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-8 sap offset)))
- (16 #'(lambda (sap &optional (offset 0))
+ (16 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-16 sap offset)))
- (32 #'(lambda (sap &optional (offset 0))
+ (32 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-32 sap offset)))
- (64 #'(lambda (sap &optional (offset 0))
+ (64 #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-64 sap offset)))))))
(declare (ignore type args))
+size-of-float+)
+(defmethod to-alien-form (form (type (eql 'single-float)) &rest args)
+ (declare (ignore type args))
+ `(coerce ,form 'single-float))
+
+(defmethod to-alien-function ((type (eql 'single-float)) &rest args)
+ (declare (ignore type args))
+ #'(lambda (number)
+ (coerce number 'single-float)))
+
(defmethod writer-function ((type (eql 'single-float)) &rest args)
(declare (ignore type args))
#'(lambda (value location &optional (offset 0))
(defmethod reader-function ((type (eql 'single-float)) &rest args)
(declare (ignore type args))
- #'(lambda (sap &optional (offset 0))
+ #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-single sap offset)))
(declare (ignore type args))
+size-of-double+)
+(defmethod to-alien-form (form (type (eql 'double-float)) &rest args)
+ (declare (ignore type args))
+ `(coerce ,form 'double-float))
+
+(defmethod to-alien-function ((type (eql 'double-float)) &rest args)
+ (declare (ignore type args))
+ #'(lambda (number)
+ (coerce number 'double-float)))
+
(defmethod writer-function ((type (eql 'double-float)) &rest args)
(declare (ignore type args))
#'(lambda (value location &optional (offset 0))
(defmethod reader-function ((type (eql 'double-float)) &rest args)
(declare (ignore type args))
- #'(lambda (sap &optional (offset 0))
+ #'(lambda (sap &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-double sap offset)))
(defmethod reader-function ((type (eql 'base-char)) &rest args)
(declare (ignore type args))
- #'(lambda (location &optional (offset 0))
+ #'(lambda (location &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(code-char (sap-ref-8 location offset))))
(declare (ignore type args))
`(let ((string ,string))
;; Always copy strings to prevent seg fault due to GC
+ #+cmu
(copy-memory
(vector-sap (coerce string 'simple-base-string))
- (1+ (length string)))))
+ (1+ (length string)))
+ #+sbcl
+ (let ((utf8 (%deport-utf8-string string)))
+ (copy-memory (vector-sap utf8) (length utf8)))))
(defmethod to-alien-function ((type (eql 'string)) &rest args)
(declare (ignore type args))
#'(lambda (string)
+ #+cmu
(copy-memory
(vector-sap (coerce string 'simple-base-string))
- (1+ (length string)))))
+ (1+ (length string)))
+ #+sbcl
+ (let ((utf8 (%deport-utf8-string string)))
+ (copy-memory (vector-sap utf8) (length utf8)))))
(defmethod from-alien-form (string (type (eql 'string)) &rest args)
(declare (ignore type args))
`(let ((string ,string))
(unless (null-pointer-p string)
(prog1
- (%naturalize-c-string string)
+ #+cmu(%naturalize-c-string string)
+ #+sbcl(%naturalize-utf8-string string)
(deallocate-memory string)))))
(defmethod from-alien-function ((type (eql 'string)) &rest args)
#'(lambda (string)
(unless (null-pointer-p string)
(prog1
- (%naturalize-c-string string)
+ #+cmu(%naturalize-c-string string)
+ #+sbcl(%naturalize-utf8-string string)
(deallocate-memory string)))))
(defmethod cleanup-form (string (type (eql 'string)) &rest args)
(declare (ignore type args))
`(let ((string ,string))
(unless (null-pointer-p string)
- (%naturalize-c-string string))))
-
+ #+cmu(%naturalize-c-string string)
+ #+sbcl(%naturalize-utf8-string string))))
(defmethod copy-from-alien-function ((type (eql 'string)) &rest args)
(declare (ignore type args))
#'(lambda (string)
(unless (null-pointer-p string)
- (%naturalize-c-string string))))
+ #+cmu(%naturalize-c-string string)
+ #+sbcl(%naturalize-utf8-string string))))
(defmethod writer-function ((type (eql 'string)) &rest args)
(declare (ignore type args))
#'(lambda (string location &optional (offset 0))
(assert (null-pointer-p (sap-ref-sap location offset)))
(setf (sap-ref-sap location offset)
+ #+cmu
(copy-memory
(vector-sap (coerce string 'simple-base-string))
- (1+ (length string))))))
+ (1+ (length string)))
+ #+sbcl
+ (let ((utf8 (%deport-utf8-string string)))
+ (copy-memory (vector-sap utf8) (length utf8))))))
(defmethod reader-function ((type (eql 'string)) &rest args)
(declare (ignore type args))
- #'(lambda (location &optional (offset 0))
+ #'(lambda (location &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(unless (null-pointer-p (sap-ref-sap location offset))
- (%naturalize-c-string (sap-ref-sap location offset)))))
+ #+cmu(%naturalize-c-string (sap-ref-sap location offset))
+ #+sbcl(%naturalize-utf8-string (sap-ref-sap location offset)))))
(defmethod destroy-function ((type (eql 'string)) &rest args)
(declare (ignore type args))
(declare (ignore type args))
(values t nil))
+
(defmethod alien-type ((type (eql 'pathname)) &rest args)
(declare (ignore type args))
(alien-type 'string))
(defmethod reader-function ((type (eql 'pathname)) &rest args)
(declare (ignore type args))
(let ((string-reader (reader-function 'string)))
- #'(lambda (location &optional (offset 0))
+ #'(lambda (location &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(let ((string (funcall string-reader location offset)))
(when string
(parse-namestring string))))))
(defmethod reader-function ((type (eql 'boolean)) &rest args)
(declare (ignore type))
(let ((reader (apply #'reader-function 'signed-byte args)))
- #'(lambda (location &optional (offset 0))
+ #'(lambda (location &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(not (zerop (funcall reader location offset))))))
(defmethod reader-function ((type (eql 'system-area-pointer)) &rest args)
(declare (ignore type args))
- #'(lambda (location &optional (offset 0))
+ #'(lambda (location &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
(sap-ref-sap location offset)))
(defmethod writer-function ((type (eql 'copy-of)) &rest args)
(declare (ignore type))
(writer-function (first args)))
+
+
+(defmethod alien-type ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ (alien-type 'pointer))
+
+#+nil
+(defmethod size-of ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ (size-of 'pointer))
+
+(defmethod to-alien-form (callback (type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ `(callback-address ,callback))
+
+(defmethod to-alien-function ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ #'callback-address)
+
+#+nil(
+#+cmu
+(defun find-callback (pointer)
+ (find pointer alien::*callbacks* :key #'callback-trampoline :test #'sap=))
+
+(defmethod from-alien-form (pointer (type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ #+cmu `(find-callback ,pointer)
+ #+sbcl `(sb-alien::%find-alien-function ,pointer))
+
+(defmethod from-alien-function ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ #+cmu #'find-callback
+ #+sbcl #'sb-alien::%find-alien-function)
+
+(defmethod writer-function ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ (let ((writer (writer-function 'pointer))
+ (to-alien (to-alien-function 'callback)))
+ #'(lambda (callback location &optional (offset 0))
+ (funcall writer (funcall to-alien callback) location offset))))
+
+(defmethod reader-function ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ (let ((reader (reader-function 'pointer))
+ (from-alien (from-alien-function 'callback)))
+ #'(lambda (location &optional (offset 0) weak-p)
+ (declare (ignore weak-p))
+ (let ((pointer (funcall reader location offset)))
+ (unless (null-pointer-p pointer)
+ (funcall from-alien pointer))))))
+
+(defmethod unbound-value ((type (eql 'callback)) &rest args)
+ (declare (ignore type args))
+ (values t nil))
+)
\ No newline at end of file