Update of /project/cells-gtk/cvsroot/root/gtk-ffi In directory common-lisp:/tmp/cvs-serv8937/root/gtk-ffi
Modified Files: gtk-ffi.lisp Log Message: Now native CFFI, use CFFI type translation. Reworked macros def-gtk-lib-function, def-gtk-function
--- /project/cells-gtk/cvsroot/root/gtk-ffi/gtk-ffi.lisp 2006/02/11 03:45:55 1.16 +++ /project/cells-gtk/cvsroot/root/gtk-ffi/gtk-ffi.lisp 2006/02/16 18:04:29 1.17 @@ -16,16 +16,56 @@
|#
- -(defpackage :gtk-ffi (:use :common-lisp :uffi)) +(defpackage :gtk-ffi (:use :common-lisp :pod :uffi)) ; pod remove uffi
(in-package :gtk-ffi)
-(defconstant c-null (make-null-pointer '(* :void))) -(defconstant c-null-int (make-null-pointer :int)) +;;; POD throw-away utility +(defun gtk-lib2cffi (body) + "Convert hello-c to uffi to cffi types. Swap order of arguments." + (flet ((convert-type (type) + (case type + (c-string :gtk-string) + (boolean :gtk-boolean) + (t (cffi-uffi-compat::convert-uffi-type (ffi-to-uffi-type type)))))) + (dbind (ignore module &rest funcs) body + (pprint `(,ignore + ,module + ,@(mapcar + #'(lambda (f) + (dbind (name args &optional return-type) f + ` (,name + ,(if return-type + (convert-type return-type) + :void) + ,(mapcar #'(lambda (a) + (list + (car a) + (convert-type (cadr a)))) + args)))) + funcs)) + *standard-output*)))) +
+(defconstant +c-null+ (cffi:null-pointer)) (defvar *gtk-debug* nil)
+;;; ============== Define CFFI types, and their translations.... +(cffi:defctype :gtk-string :pointer :documentation "string type for cffi type translation") +(cffi:defctype :gtk-boolean :pointer :documentation "boolean type for cffi type translation") + +(defmethod cffi:translate-to-foreign (value (type (eql :gtk-boolean))) + (cffi:make-pointer (if value 1 0))) + +(defmethod cffi:translate-from-foreign (value (type (eql :gtk-boolean))) + (not (zerop (cffi::pointer-address value)))) ; pod strange! + +(defmethod cffi:translate-to-foreign (value (type (eql :gtk-string))) + (when (null value) (setf value "")) ; pod ??? + (cffi:foreign-string-alloc value)) + +(defmethod cffi:translate-from-foreign (value (type (eql :gtk-string))) + (cffi:foreign-string-to-lisp value))
(defun int-slot-indexed (obj obj-type slot index) (declare (ignorable obj-type)) @@ -40,53 +80,69 @@ '(:array :int) index) new-value))
+(cffi:define-foreign-library 'gobject + (:linux "libgobject-2.0.so") + (:win32 "libgobject-2.0-0.dll") + (:macosx "libgobject-2.0-0.dylib")) + +(cffi:define-foreign-library :glib + (:linux "libglib-2.0.so") + (:win32 "libglib-2.0-0.dll") + (:macosx "libglib-2.0-0.dylib")) + +(cffi:define-foreign-library :gthread + (:linux "libgthread-2.0.so") + (:win32 "libgthread-2.0-0.dll") + (:macosx "libgthread-2.0-0.dylib")) + +(cffi:define-foreign-library :gdk + (:linux "libgdk-x11-2.0.so") + (:win32 "libgdk-win32-2.0-0.dll") + (:macosx "libgdk-win32-2.0-0.dylib")) ; pod ??? + +(cffi:define-foreign-library :gtk + (:linux "libgtk-x11-2.0.so") + (:win32 "libgtk-win32-2.0-0.dll") + (:macosx "libgtk-win32-2.0-0.dylib")) ; pod ??? + +#+libcellsgtk +(cffi:define-foreign-library :cgtk + (:linux "libcellsgtk.so") + (:win32 "libcellsgtk.dll") + (:macosx "libcellsgtk.dylib")) + +;;; After doing this, should be able to do (g-thread-init c-null) +;;; The above define-foreigh-library appears to be useless (doesn't +;;; work through the symbols) use the names. +(defun load-gtk-libs () + (handler-bind ((style-warning #'muffle-warning)) + (cffi:load-foreign-library #+linux "libgobject-2.0.so" + #+win32 "libgobject-2.0-0.dll" + #+macosx "libgobject-2.0-0.dylib") + (cffi:load-foreign-library #+linux "libglib-2.0.so" + #+win32 "libglib-2.0-0.dll" + #+macosx "libglib-2.0-0.dylib") + (cffi:load-foreign-library #+linux "libgthread-2.0.so" + #+win32 "libgthread-2.0-0.dll" + #+macosx "libgthread-2.0-0.dylib") + (cffi:load-foreign-library #+linux "libgdk-x11-2.0.so" + #+win32 "libgdk-win32-2.0-0.dll" + #+macosx "libgdk-win32-2.0-0.dylib") + (cffi:load-foreign-library #+linux "libgtk-x11-2.0.so" + #+win32 "libgtk-win32-2.0-0.dll" + #+macosx "libgtk-win32-2.0-0.dylib") + #+libcellsgtk + (cffi:load-foreign-library #+linux "libcellsgtk.so" + #+win32 "libcellsgtk.dll" + #+macosx "libcellsgtk.dylib")))
(eval-when (:compile-toplevel :load-toplevel :execute) - (export '(c-null c-null-int int-slot-indexed load-gtk-libs)) + (export '(+c-null+ int-slot-indexed load-gtk-libs)) (defun gtk-function-name (lisp-name) (substitute #_ #- lisp-name)) - (defun libname (lib) - (ecase lib - (:gobject #+win32 "libgobject-2.0-0.dll" - #-win32 "libgobject-2.0.so") - (:glib #+win32 "libglib-2.0-0.dll") - (:gthread #+win32 "libgthread-2.0-0.dll") - (:gdk #+win32 "libgdk-win32-2.0-0.dll") - (:gtk #+win32 "libgtk-win32-2.0-0.dll") - #+libcellsgtk (:cgtk "libcellsgtk.dll"))) - (defun load-gtk-libs () - (macrolet ((loadit (libname module) - `(handler-bind ((style-warning #'muffle-warning)) - (uffi:load-foreign-library - (concatenate 'string cl-user::*gtk-lib-path* ,libname) - :force-load #+lispworks t #-lispworks nil - :module ,(string module))))) - #+(or win32 mswindows) - (progn - (loadit "libgobject-2.0-0.dll" :gobject) - (loadit "libglib-2.0-0.dll" :glib) - (loadit "libgthread-2.0-0.dll" :gthread) - (loadit "libgdk-win32-2.0-0.dll" :gdk) - (loadit "libgtk-win32-2.0-0.dll" :gtk) - #+libcellsgtk(loadit "libcellsgtk.dll" :cgtk)) - #+macosx - (progn - (loadit "libgobject-2.0-0.dynlib" :gobject) - (loadit "libglib-2.0-0.dynlib" :glib) - (loadit "libgthread-2.0-0.dynlib" :gthread) - (loadit "libgdk-win32-2.0-0.dynlib" :gdk) - (loadit "libgtk-win32-2.0-0.dynlib" :gtk) - #+libcellsgtk(loadit "libcellsgtk.dynlib" :cgtk)) - #-(or macosx win32 mswindows) - (progn - (loadit "libgobject-2.0.so" :gobject) - (loadit "libglib-2.0.so" :glib) - (loadit "libgthread-2.0.so" :gthread) - (loadit "libgdk-x11-2.0.so" :gdk) - (loadit "libgtk-x11-2.0.so" :gtk) - #+libcellsgtk(loadit "libcellsgtk.so" :cgtk)))) - #+cmu(load-gtk-libs) - #+clisp(load-gtk-libs) + + #+(or cmu clisp)(load-gtk-libs) + (defun ffi-to-uffi-type (clisp-type)
(if (consp clisp-type) @@ -110,85 +166,41 @@ (single-float :float) (double-float :double) (otherwise clisp-type)))) +) ;eval
- (defun ffi-to-native-type (ffi-type) - (uffi::convert-from-uffi-type - (ffi-to-uffi-type ffi-type) :type))) ;; END eval-when - -(defmacro def-gtk-function (library name &key arguments return-type - (return-type-allocation :none) - (call-direct t)) - (declare (ignore return-type-allocation call-direct)) - +(defmacro def-gtk-function (library name return-type arguments) + (declare (ignore library)) (let* ((gtk-name$ (gtk-function-name (string-downcase (symbol-name name)))) (gtk-name (intern (string-upcase gtk-name$)))) - (let ((arg-info - (loop for arg in arguments - for gsym = (gensym) - if (eql 'c-string (cadr arg)) - collect (car arg) into arg$s - and collect gsym into gsyms - and collect gsym into pass-args - else if (eql 'boolean (cadr arg)) - collect `(if ,(car arg) 1 0) into pass-args - else if (eql 'c-pointer (cadr arg)) - collect `(or ,(car arg) c-null) into pass-args - else collect (car arg) into pass-args - finally (return (list (mapcar 'list gsyms arg$s) - pass-args))))) - `(progn - (uffi:def-function (,gtk-name$ ,gtk-name) - ,(mapcar (lambda (name-type) - (destructuring-bind (name type) name-type - (list name (ffi-to-uffi-type type)))) - arguments) - :module ,(string library) - :returning ,(ffi-to-uffi-type return-type)) - (defun ,name ,(mapcar 'car arguments) - (when *gtk-debug* - ,(unless (or (string= (symbol-name name) "GTK-EVENTS-PENDING") - (string= (symbol-name name) "GTK-MAIN-ITERATION-DO")) - `(print (list ,(symbol-name name) :before ,@(mapcar 'car arguments))))) - (prog1 - ,(let ((bodyform `(with-cstrings - ,(car arg-info) - (,gtk-name ,@(cadr arg-info))))) - (if (eql return-type 'boolean) - `(not (zerop ,bodyform)) - (if (eql return-type 'c-string) - `(convert-from-cstring ,bodyform) - bodyform) - )) - - (when *gtk-debug* - ,(unless (or (string= (symbol-name name) "GTK-EVENTS-PENDING") - (string= (symbol-name name) "GTK-MAIN-ITERATION-DO")) - `(print (list ,(symbol-name name) :after ,@(mapcar 'car arguments))))))) - (eval-when (compile load eval) - (export ',name)))))) + `(progn + (cffi:defcfun (,gtk-name$ ,gtk-name) ,return-type ,@arguments) + (defun ,name ,(mapcar 'car arguments) + (when *gtk-debug* + ,(unless (or (string= (symbol-name name) "GTK-EVENTS-PENDING") + (string= (symbol-name name) "GTK-MAIN-ITERATION-DO")) + `(format *trace-output* "~%before (~A ~{~A~^ ~})" + ,(string-downcase (string name)) (list ,@(mapcar 'car arguments))))) + (prog1 + (,gtk-name ,@(mapcar #'car arguments)) + (when *gtk-debug* + ,(unless (or (string= (symbol-name name) "GTK-EVENTS-PENDING") + (string= (symbol-name name) "GTK-MAIN-ITERATION-DO")) + `(format *trace-output* "~%after (~A ~{~A~^ ~})" + ,(string-downcase (string name)) (list ,@(mapcar 'car arguments))))))) + (eval-when (:compile-toplevel :load-toplevel :execute) + (export ',name)))))
(defmacro def-gtk-lib-functions (library &rest functions) `(progn ,@(loop for function in functions collect - (destructuring-bind (name (&rest args) - &optional return-type - return-type-allocation - (call-direct t)) function - `(def-gtk-function ,library ,name - ,@(when args `(:arguments ,args)) - :return-type ,return-type - ,@(when return-type-allocation - `(:return-type-allocation ,return-type-allocation)) - :call-direct ,call-direct))))) - + (destructuring-bind (name return-type (&rest args)) function + `(def-gtk-function ,library ,name ,return-type ,args)))))
(eval-when (:compile-toplevel :load-toplevel :execute) (defmacro callback-function ((&rest arguments) &optional return-type) (declare (ignore arguments return-type)) `'c-pointer))
- - (defmacro def-c-struct (struct-name &rest fields) (let ((slot-defs (loop for field in fields collecting (destructuring-bind (name type) field @@ -313,7 +325,6 @@ (32 :window_state) (33 :setting)))
- (uffi:def-struct list-boolean (value :unsigned-int) (end :pointer-void)) @@ -363,12 +374,11 @@ (defmacro with-tree-iter ((iter-var) &body body) `(uffi:with-foreign-object (,iter-var 'gtk-tree-iter) (setf (get-slot-value ,iter-var 'gtk-tree-iter 'stamp) 0) - (setf (get-slot-value ,iter-var 'gtk-tree-iter 'user-data) c-null) - (setf (get-slot-value ,iter-var 'gtk-tree-iter 'user-data2) c-null) - (setf (get-slot-value ,iter-var 'gtk-tree-iter 'user-data3) c-null) + (setf (get-slot-value ,iter-var 'gtk-tree-iter 'user-data) +c-null+) + (setf (get-slot-value ,iter-var 'gtk-tree-iter 'user-data2) +c-null+) + (setf (get-slot-value ,iter-var 'gtk-tree-iter 'user-data3) +c-null+) ,@body))
- (eval-when (:compile-toplevel :load-toplevel :execute) (defun as-gtk-type-name (type) (ecase type