From 74821f759d3bf3cfdd55aac54a8f0b5bde6289b6 Mon Sep 17 00:00:00 2001 Message-Id: <74821f759d3bf3cfdd55aac54a8f0b5bde6289b6.1714612820.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 25 Apr 2006 22:10:36 +0000 Subject: [PATCH] Various necessary changes Organization: Straylight/Edgeware From: espen --- glib/gobject.lisp | 306 ++++++++++++++++++++++++---------------------- glib/gtype.lisp | 301 ++++++++++++++++++++++++++------------------- 2 files changed, 332 insertions(+), 275 deletions(-) diff --git a/glib/gobject.lisp b/glib/gobject.lisp index 59066da..f908b12 100644 --- a/glib/gobject.lisp +++ b/glib/gobject.lisp @@ -1,5 +1,5 @@ ;; Common Lisp bindings for GTK+ v2.x -;; Copyright 2000-2005 Espen S. Johnsen +;; Copyright 2000-2006 Espen S. Johnsen ;; ;; Permission is hereby granted, free of charge, to any person obtaining ;; a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: gobject.lisp,v 1.51 2006-03-03 10:01:01 espen Exp $ +;; $Id: gobject.lisp,v 1.52 2006-04-25 22:10:36 espen Exp $ (in-package "GLIB") @@ -30,8 +30,15 @@ (in-package "GLIB") (eval-when (:compile-toplevel :load-toplevel :execute) ;; (push :debug-ref-counting *features*) (defclass gobject-class (ginstance-class) - ((instance-slots-p :initform nil + ((instance-slots-p :initform nil :reader instance-slots-p :documentation "Non NIL if the class has slots with instance allocation"))) + (defmethod shared-initialize ((class gobject-class) names &rest initargs) + (declare (ignore names initargs)) + (call-next-method) + (unless (slot-boundp class 'ref) + (setf (slot-value class 'ref) '%object-ref)) + (unless (slot-boundp class 'unref) + (setf (slot-value class 'unref) '%object-unref))) (defmethod validate-superclass ((class gobject-class) (super standard-class)) ; (subtypep (class-name super) 'gobject) @@ -45,9 +52,9 @@ (defclass direct-property-slot-definition (direct-virtual-slot-definition) (defclass effective-property-slot-definition (effective-virtual-slot-definition) ((pname :reader slot-definition-pname :initarg :pname) - (readable :reader slot-readable-p :initarg :readable) - (writable :reader slot-writable-p :initarg :writable) - (construct-only :initarg :construct-only :reader construct-only-property-p))) + (readable :initform t :reader slot-readable-p :initarg :readable) + (writable :initform t :reader slot-writable-p :initarg :writable) + (construct-only :initform nil :initarg :construct-only :reader construct-only-property-p))) (defclass direct-user-data-slot-definition (direct-virtual-slot-definition) ()) @@ -56,21 +63,30 @@ (defclass effective-user-data-slot-definition (effective-virtual-slot-definition ()) +(defmethod slot-readable-p ((slotd standard-effective-slot-definition)) + (declare (ignore slotd)) + t) + +(defmethod slot-writable-p ((slotd standard-effective-slot-definition)) + (declare (ignore slotd)) + t) + + (defbinding %object-ref () pointer (location pointer)) (defbinding %object-unref () nil (location pointer)) -#+glib2.8 +#?(pkg-exists-p "glib-2.0" :atleast-version "2.8.0") (progn (define-callback toggle-ref-callback nil ((data pointer) (location pointer) (last-ref-p boolean)) (declare (ignore data)) #+debug-ref-counting (if last-ref-p - (format t "Object at 0x~8,'0X has no foreign references~%" (sap-int location)) - (format t "Foreign reference added to object at 0x~8,'0X~%" (sap-int location))) + (format t "Object at 0x~8,'0X has no foreign references~%" (pointer-address location)) + (format t "Foreign reference added to object at 0x~8,'0X~%" (pointer-address location))) (if last-ref-p (cache-instance (find-cached-instance location) t) (cache-instance (find-cached-instance location) nil))) @@ -85,18 +101,10 @@ (defbinding %object-remove-toggle-ref (location) pointer (toggle-ref-callback callback) (nil null))) -(defmethod reference-foreign ((class gobject-class) location) - (declare (ignore class)) - (%object-ref location)) - -(defmethod unreference-foreign ((class gobject-class) location) - (declare (ignore class)) - (%object-unref location)) - #+debug-ref-counting (progn (define-callback weak-ref-callback nil ((data pointer) (location pointer)) - (format t "Object at 0x~8,'0X being finalized~%" (sap-int location))) + (format t "Object at 0x~8,'0X (~A) being finalized~%" (pointer-address location) (type-from-number (%type-number-of-ginstance location)))) (defbinding %object-weak-ref (location) pointer (location pointer) @@ -131,14 +139,9 @@ (defmethod effective-slot-definition-class ((class gobject-class) &rest initargs (defmethod compute-effective-slot-definition-initargs ((class gobject-class) direct-slotds) (if (eq (slot-definition-allocation (first direct-slotds)) :property) - (nconc - (list :pname (signal-name-to-string - (most-specific-slot-value direct-slotds 'pname - (slot-definition-name (first direct-slotds)))) - :readable (most-specific-slot-value direct-slotds 'readable t) - :writable (most-specific-slot-value direct-slotds 'writable t) - :construct-only (most-specific-slot-value direct-slotds - 'construct-only nil)) + (nconc + (compute-most-specific-initargs direct-slotds + '(pname construct-only readable writable)) (call-next-method)) (call-next-method))) @@ -146,74 +149,69 @@ (defmethod compute-effective-slot-definition-initargs ((class gobject-class) dir (defvar *ignore-setting-construct-only-property* nil) (declaim (special *ignore-setting-construct-only-property*)) -(defmethod initialize-internal-slot-functions ((slotd effective-property-slot-definition)) - (let ((type (slot-definition-type slotd)) - (pname (slot-definition-pname slotd))) - (when (and (not (slot-boundp slotd 'getter)) (slot-readable-p slotd)) - (setf - (slot-value slotd 'getter) - (let ((reader nil)) - #'(lambda (object) - (unless reader - (setq reader (reader-function type))) - (let ((gvalue (gvalue-new type))) - (%object-get-property object pname gvalue) - (unwind-protect - (funcall reader gvalue +gvalue-value-offset+) - (gvalue-free gvalue t))))))) - - (when (not (slot-boundp slotd 'setter)) - (cond - ((slot-writable-p slotd) - (setf - (slot-value slotd 'setter) - (let ((writer nil)) - #'(lambda (value object) - (unless writer - (setq writer (writer-function type))) - (let ((gvalue (gvalue-new type))) - (funcall writer value gvalue +gvalue-value-offset+) - (%object-set-property object pname gvalue) - (gvalue-free gvalue t) - value))))) - - ((construct-only-property-p slotd) - (setf - (slot-value slotd 'setter) - #'(lambda (value object) - (declare (ignore value object)) - (unless *ignore-setting-construct-only-property* - (error "Slot is not writable: ~A" (slot-definition-name slotd))))))))) +(defmethod compute-slot-reader-function ((slotd effective-property-slot-definition)) + (if (slot-readable-p slotd) + (let* ((type (slot-definition-type slotd)) + (pname (slot-definition-pname slotd)) + (reader (reader-function type :ref :get))) + #'(lambda (object) + (with-memory (gvalue +gvalue-size+) + (%gvalue-init gvalue (find-type-number type)) + (%object-get-property object pname gvalue) + (funcall reader gvalue +gvalue-value-offset+)))) + (call-next-method))) - (call-next-method)) +(defmethod compute-slot-writer-function ((slotd effective-property-slot-definition)) + (cond + ((slot-writable-p slotd) + (let* ((type (slot-definition-type slotd)) + (pname (slot-definition-pname slotd)) + (writer (writer-function type :temp t)) + (destroy (destroy-function type :temp t))) + #'(lambda (value object) + (with-memory (gvalue +gvalue-size+) + (%gvalue-init gvalue (find-type-number type)) + (funcall writer value gvalue +gvalue-value-offset+) + (%object-set-property object pname gvalue) + (funcall destroy gvalue +gvalue-value-offset+)) + value))) + + ((construct-only-property-p slotd) + #'(lambda (value object) + (declare (ignore value object)) + (unless *ignore-setting-construct-only-property* + (error 'unwritable-slot :name (slot-definition-name slotd) :instance object)))) + ((call-next-method)))) + +(defmethod compute-slot-reader-function ((slotd effective-user-data-slot-definition)) + (let ((slot-name (slot-definition-name slotd))) + #'(lambda (object) + (user-data object slot-name)))) -(defmethod initialize-internal-slot-functions ((slotd effective-user-data-slot-definition)) +(defmethod compute-slot-boundp-function ((slotd effective-user-data-slot-definition)) (let ((slot-name (slot-definition-name slotd))) - (unless (slot-boundp slotd 'getter) - (setf - (slot-value slotd 'getter) - #'(lambda (object) - (prog1 (user-data object slot-name))))) - (unless (slot-boundp slotd 'setter) - (setf - (slot-value slotd 'setter) - #'(lambda (value object) - (setf (user-data object slot-name) value)))) - (unless (slot-boundp slotd 'boundp) - (setf - (slot-value slotd 'boundp) - #'(lambda (object) - (user-data-p object slot-name))))) - (call-next-method)) - -(defmethod shared-initialize :after ((class gobject-class) names &rest initargs) - (declare (ignore initargs)) - (when (some #'(lambda (slotd) - (and - (eq (slot-definition-allocation slotd) :instance) - (not (typep slotd 'effective-special-slot-definition)))) - (class-slots class)) - (setf (slot-value class 'instance-slots-p) t))) + #'(lambda (object) + (user-data-p object slot-name)))) + +(defmethod compute-slot-writer-function ((slotd effective-user-data-slot-definition)) + (let ((slot-name (slot-definition-name slotd))) + #'(lambda (value object) + (setf (user-data object slot-name) value)))) + +(defmethod compute-slot-makunbound-function ((slotd effective-user-data-slot-definition)) + (let ((slot-name (slot-definition-name slotd))) + #'(lambda (object) + (unset-user-data object slot-name)))) + +(defmethod compute-slots :around ((class gobject-class)) + (let ((slots (call-next-method))) + (when (some #'(lambda (slotd) + (and + (eq (slot-definition-allocation slotd) :instance) + (not (typep slotd 'effective-special-slot-definition)))) + slots) + (setf (slot-value class 'instance-slots-p) t)) + slots)) ;;;; Super class for all classes in the GObject type hierarchy @@ -225,17 +223,34 @@ (defclass gobject (ginstance) (:metaclass gobject-class) (:gtype "GObject"))) -(define-type-method callback-from-alien-form ((type gobject) form) - (from-alien-form type form)) - #+debug-ref-counting (defmethod print-object ((instance gobject) stream) (print-unreadable-object (instance stream :type t :identity nil) (if (proxy-valid-p instance) - (format stream "at 0x~X (~D)" (sap-int (foreign-location instance)) (ref-count instance)) + (format stream "at 0x~X (~D)" (pointer-address (foreign-location instance)) (ref-count instance)) (write-string "at \"unbound\"" stream)))) +(define-type-method reader-function ((type gobject) &key (ref :read) inlined) + (assert-not-inlined type inlined) + (ecase ref + ((:read :peek) (call-next-method type :ref :read)) + (:get + #'(lambda (location &optional (offset 0)) + (let ((instance (ref-pointer location offset))) + (unless (null-pointer-p instance) + (multiple-value-bind (gobject new-p) + (ensure-proxy-instance 'gobject instance :reference nil) + (unless new-p + (%object-unref instance)) + (setf (ref-pointer location offset) (make-pointer 0)) + gobject))))))) + +(define-type-method callback-wrapper ((type gobject) var arg form) + (let ((class (type-expand type))) + `(let ((,var (ensure-proxy-instance ',class ,arg))) + ,form))) + (defun initial-add (object function initargs key pkey) (loop as (initarg value . rest) = initargs then rest @@ -255,7 +270,7 @@ (defun initial-apply-add (object function initargs key pkey) (defmethod make-proxy-instance ((class gobject-class) location &rest initargs) (declare (ignore location initargs)) (if (slot-value class 'instance-slots-p) - (error "An object of class ~A has instance slots and should only be created with MAKE-INSTANCE" class) + (error "Objects of class ~A has instance slots and should only be created with MAKE-INSTANCE" class) (call-next-method))) @@ -283,17 +298,18 @@ (defmethod allocate-foreign ((object gobject) &rest initargs) (cond (init-slots - (let ((element-size (+ +gvalue-size+ +size-of-pointer+)) - (num-slots (length init-slots))) - (with-allocated-memory (params (* num-slots element-size)) + (let* ((pointer-size (size-of 'pointer)) + (element-size (+ +gvalue-size+ pointer-size)) + (num-slots (length init-slots))) + (with-memory (params (* num-slots element-size)) (loop with string-writer = (writer-function 'string) for (slotd . value) in init-slots - as offset = params then (sap+ offset element-size) + as param = params then (pointer+ param element-size) as type = (slot-definition-type slotd) as pname = (slot-definition-pname slotd) - do (funcall string-writer pname offset) - (gvalue-init (sap+ offset +size-of-pointer+) type value)) + do (funcall string-writer pname param) + (gvalue-init (pointer+ param pointer-size) type value)) (unwind-protect (%gobject-newv (type-number-of object) num-slots params) @@ -301,9 +317,9 @@ (defmethod allocate-foreign ((object gobject) &rest initargs) (loop with string-destroy = (destroy-function 'string) repeat num-slots - as offset = params then (sap+ offset element-size) - do (funcall string-destroy offset) - (gvalue-unset (sap+ offset +size-of-pointer+))))))) + as param = params then (pointer+ param element-size) + do (funcall string-destroy param) + (gvalue-unset (pointer+ param pointer-size))))))) (t (%gobject-new (type-number-of object)))))) @@ -318,31 +334,27 @@ (defmethod initialize-instance :around ((object gobject) &rest initargs) (prog1 (call-next-method) #+debug-ref-counting(%object-weak-ref (foreign-location object)) - #+glib2.8 + #?(pkg-exists-p "glib-2.0" :atleast-version "2.8.0") (when (slot-value (class-of object) 'instance-slots-p) - (with-slots (location) object - (%object-add-toggle-ref location) - (%object-unref location))))) + (%object-add-toggle-ref (foreign-location object)) + (%object-unref (foreign-location object))))) (defmethod instance-finalizer ((instance gobject)) (let ((location (foreign-location instance))) - #+glib2.8 + #?(pkg-exists-p "glib-2.0" :atleast-version "2.8.0") (if (slot-value (class-of instance) 'instance-slots-p) #'(lambda () #+debug-ref-counting - (format t "Finalizing proxy for 0x~8,'0X~%" (sap-int location)) - (remove-cached-instance location) + (format t "Finalizing proxy for 0x~8,'0X~%" (pointer-address location)) (%object-remove-toggle-ref location)) #'(lambda () #+debug-ref-counting - (format t "Finalizing proxy for 0x~8,'0X~%" (sap-int location)) - (remove-cached-instance location) + (format t "Finalizing proxy for 0x~8,'0X~%" (pointer-address location)) (%object-unref location))) - #-glib2.8 + #?-(pkg-exists-p "glib-2.0" :atleast-version "2.8.0") #'(lambda () - (remove-cached-instance location) - (%object-unref location)))) + (%object-unref location)))) (defbinding (%gobject-new "g_object_new") () pointer @@ -395,11 +407,6 @@ (defun (setf user-data) (data object key) (register-user-data data) user-data-destroy-callback) data) -;; deprecated -(defun (setf object-data) (data object key &key (test #'eq)) - (assert (eq test #'eq)) - (setf (user-data object key) data)) - (defbinding %object-get-qdata () unsigned-long (object gobject) (id quark)) @@ -407,11 +414,6 @@ (defbinding %object-get-qdata () unsigned-long (defun user-data (object key) (find-user-data (%object-get-qdata object (quark-intern key)))) -;; deprecated -(defun object-data (object key &key (test #'eq)) - (assert (eq test #'eq)) - (user-data object key)) - (defun user-data-p (object key) (user-data-exists-p (%object-get-qdata object (quark-intern key)))) @@ -456,7 +458,14 @@ (defun query-object-class-properties (type &optional inherited-p) (defun default-slot-name (name) - (intern (substitute #\- #\_ (string-upcase (string-upcase name))))) + (let ((prefix-len (length (package-prefix)))) + (intern (substitute #\- #\_ + (string-upcase + (if (and + (string-prefix-p (package-prefix) name) + (char= #\- (char name prefix-len))) + (subseq name (1+ prefix-len)) + name)))))) (defun default-slot-accessor (class-name slot-name type) (intern @@ -535,20 +544,26 @@ (defun slot-definitions (class properties slots) (defun expand-gobject-type (type forward-p options &optional (metaclass 'gobject-class)) (let ((supers (cons (supertype type) (implements type))) (class (type-from-number type)) - (slots (getf options :slots))) + (slots (getf options :slots))) `(defclass ,class ,supers ,(unless forward-p (slot-definitions class (query-object-class-properties type) slots)) (:metaclass ,metaclass) (:gtype ,(register-type-as type))))) -(defun gobject-dependencies (type) +(defun gobject-dependencies (type options) (delete-duplicates (cons (supertype type) (append (type-interfaces type) - (mapcar #'param-value-type (query-object-class-properties type)))))) + (mapcar #'param-value-type (query-object-class-properties type)) + (getf options :dependencies) + (loop + for slot in (getf options :slots) + as type = (getf (rest slot) :type) + when (and type (symbolp type) (find-type-number type)) + collect (find-type-number type)))))) (register-derivable-type 'gobject "GObject" 'expand-gobject-type 'gobject-dependencies) @@ -559,18 +574,17 @@ (register-derivable-type 'gobject "GObject" 'expand-gobject-type 'gobject-depend (deftype referenced (type) type) -(define-type-method alien-type ((type referenced)) - (declare (ignore type)) - (alien-type 'gobject)) - -(define-type-method from-alien-form ((type referenced) form) - (let ((class (second (type-expand-to 'referenced type)))) - (if (subtypep type 'gobject) - (let ((instance (make-symbol "INSTANCE"))) - `(let ((,instance ,(from-alien-form class form))) - (when ,instance - (%object-unref (foreign-location ,instance))) - ,instance)) - (error "~A is not a subclass of GOBJECT" type)))) - -(export 'referenced) +(define-type-method from-alien-form ((type referenced) form &key (ref :free)) + (cond + ((not (eq ref :free)) + (error "Keyword arg :REF to FROM-ALIEN-FORM should be :FREE for type ~A. It was give ~A" type ref)) + ((subtypep type 'gobject) + (from-alien-form (second (type-expand-to 'referenced type)) form :ref ref)))) + +(define-type-method from-alien-function ((type referenced) &key (ref :free)) + (cond + ((not (eq ref :free)) + (error "Keyword arg :REF to FROM-ALIEN-FUNCTION should be :FREE for type ~A. It was give ~A" type ref)) +; ((subtypep type 'gobject) (call-next-method type ref :free)))) + ((subtypep type 'gobject) + (from-alien-function (second (type-expand-to 'referenced type)) :ref ref)))) diff --git a/glib/gtype.lisp b/glib/gtype.lisp index 77cd094..2ad9498 100644 --- a/glib/gtype.lisp +++ b/glib/gtype.lisp @@ -1,5 +1,5 @@ ;; Common Lisp bindings for GTK+ v2.x -;; Copyright 2000-2005 Espen S. Johnsen +;; Copyright 2000-2006 Espen S. Johnsen ;; ;; Permission is hereby granted, free of charge, to any person obtaining ;; a copy of this software and associated documentation files (the @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: gtype.lisp,v 1.51 2006-04-18 11:42:20 espen Exp $ +;; $Id: gtype.lisp,v 1.52 2006-04-25 22:10:37 espen Exp $ (in-package "GLIB") @@ -38,46 +38,47 @@ (define-type-method alien-type ((type gtype)) (declare (ignore type)) (alien-type 'type-number)) -(define-type-method size-of ((type gtype)) - (declare (ignore type)) +(define-type-method size-of ((type gtype) &key (inlined t)) + (assert-inlined type inlined) (size-of 'type-number)) -(define-type-method to-alien-form ((type gtype) gtype) - (declare (ignore type)) +(define-type-method to-alien-form ((type gtype) gtype &optional copy-p) + (declare (ignore type copy-p)) `(find-type-number ,gtype t)) -(define-type-method to-alien-function ((type gtype)) - (declare (ignore type)) +(define-type-method to-alien-function ((type gtype) &optional copy-p) + (declare (ignore type copy-p)) #'(lambda (gtype) (find-type-number gtype t))) -(define-type-method from-alien-form ((type gtype) type-number) - (declare (ignore type)) - `(type-from-number ,type-number)) +(define-type-method from-alien-form ((type gtype) form &key ref) + (declare (ignore type ref)) + `(type-from-number ,form)) -(define-type-method from-alien-function ((type gtype)) - (declare (ignore type)) +(define-type-method from-alien-function ((type gtype) &key ref) + (declare (ignore type ref)) #'(lambda (type-number) (type-from-number type-number))) -(define-type-method writer-function ((type gtype)) - (declare (ignore type)) +(define-type-method writer-function ((type gtype) &key temp (inlined t)) + (declare (ignore temp)) + (assert-inlined type inlined) (let ((writer (writer-function 'type-number))) #'(lambda (gtype location &optional (offset 0)) (funcall writer (find-type-number gtype t) location offset)))) -(define-type-method reader-function ((type gtype)) - (declare (ignore type)) +(define-type-method reader-function ((type gtype) &key ref (inlined t)) + (declare (ignore ref)) + (assert-inlined type inlined) (let ((reader (reader-function 'type-number))) - #'(lambda (location &optional (offset 0) weak-p) - (declare (ignore weak-p)) + #'(lambda (location &optional (offset 0)) (type-from-number (funcall reader location offset))))) (eval-when (:compile-toplevel :load-toplevel :execute) (defclass type-query (struct) ((type-number :allocation :alien :type type-number) - (name :allocation :alien :type string) + (name :allocation :alien :type (copy-of string)) (class-size :allocation :alien :type unsigned-int) (instance-size :allocation :alien :type unsigned-int)) (:metaclass struct-class))) @@ -85,7 +86,7 @@ (defclass type-query (struct) (defbinding type-query (type) nil ((find-type-number type t) type-number) - ((make-instance 'type-query) type-query :return)) + ((make-instance 'type-query) type-query :in/return)) (defun type-instance-size (type) (slot-value (type-query type) 'instance-size)) @@ -96,13 +97,14 @@ (defun type-class-size (type) (defbinding type-class-ref (type) pointer ((find-type-number type t) type-number)) -(defbinding type-class-unref (type) nil - ((find-type-number type t) type-number)) +(defbinding type-class-unref () nil + (class pointer)) (defbinding type-class-peek (type) pointer ((find-type-number type t) type-number)) + ;;;; Mapping between lisp types and glib types (defvar *registered-types* ()) @@ -121,14 +123,18 @@ (defun type-number-from-glib-name (name &optional (error-p t)) (error-p (error "Invalid gtype name: ~A" name))))) (defun register-type (type id) - (pushnew (cons type id) *registered-types* :key #'car) - (let ((type-number - (typecase id - (string (type-number-from-glib-name id)) - (symbol (funcall id))))) - (setf (gethash type *lisp-type-to-type-number*) type-number) - (setf (gethash type-number *type-number-to-lisp-type*) type) - type-number)) + (cond + ((find-type-number type)) + ((not id) (warn "Can't register type with no foreign id: ~A" type)) + (t + (pushnew (cons type id) *registered-types* :key #'car) + (let ((type-number + (typecase id + (string (type-number-from-glib-name id)) + (symbol (funcall id))))) + (setf (gethash type *lisp-type-to-type-number*) type-number) + (setf (gethash type-number *type-number-to-lisp-type*) type) + type-number)))) (defun register-type-alias (type alias) (pushnew (cons type alias) *registered-type-aliases* :key #'car) @@ -144,7 +150,7 @@ (defun reinitialize-all-types () (register-type (car type) (cdr type))) *registered-types*) (mapc #'(lambda (type) - (apply #'register-new-type type)) + (apply #'register-new-type type)) *registered-static-types*) (mapc #'(lambda (type) (register-type-alias (car type) (cdr type))) @@ -152,7 +158,8 @@ (defun reinitialize-all-types () (pushnew 'reinitialize-all-types #+cmu *after-save-initializations* - #+sbcl *init-hooks*) + #+sbcl *init-hooks* + #+clisp custom:*init-hooks*) #+cmu (pushnew 'system::reinitialize-global-table ; we shouldn't have to do this? @@ -194,12 +201,19 @@ (defun type-number-of (object) (eval-when (:compile-toplevel :load-toplevel :execute) (defvar *type-initializers* ()) (defun %find-types-in-library (pathname prefixes ignore) - (let ((process (run-program - "/usr/bin/nm" (list "--defined-only" "-D" (namestring (truename pathname))) - :output :stream :wait nil))) + (let ((process + (run-program + "/usr/bin/nm" + #+clisp :arguments + (list "--defined-only" "-D" (namestring (truename pathname))) + :output :stream :wait nil))) (unwind-protect (loop - as symbol = (let ((line (read-line (process-output process) nil))) + as symbol = (let ((line (read-line + #+(or cmu sbcl) + (process-output process) + #+clisp process + nil))) (when line (subseq line (1+ (position #\Space line :from-end t))))) while symbol @@ -215,7 +229,9 @@ (defun %find-types-in-library (pathname prefixes ignore) (string= "_get_type" symbol :start2 (- (length symbol) 9)) (not (member symbol ignore :test #'string=))) collect symbol) - (process-close process))))) + (#+(or cmu sbcl)process-close + #+clisp close + process))))) (defmacro init-types-in-library (filename &key prefix ignore) @@ -292,42 +308,44 @@ (defclass ginstance-class (proxy-class) (defun update-size (class) (let ((type-number (find-type-number class))) (cond - ((not (slot-boundp class 'size)) - (setf (slot-value class 'size) (type-instance-size type-number))) + ((not (foreign-size-p class)) + (setf (foreign-size class) (type-instance-size type-number))) ((and - (slot-boundp class 'size) - (not (= (type-instance-size type-number) (slot-value class 'size)))) + (foreign-size-p class) + (not (= (type-instance-size type-number) (foreign-size class)))) (warn "Size mismatch for class ~A" class))))) (defmethod finalize-inheritance ((class ginstance-class)) - (let* ((class-name (class-name class)) - (super (most-specific-proxy-superclass class)) - (gtype (or - (first (ginstance-class-gtype class)) - (default-alien-type-name class-name))) - (type-number - (or - (find-type-number class-name) - (let ((type-number - (if (or - (symbolp gtype) - (type-number-from-glib-name gtype nil)) - (register-type class-name gtype) - (register-new-type class-name (class-name super) gtype)))) - (type-class-ref type-number) - type-number)))) - (when (and - (supertype type-number) - (not (eq (class-name super) (supertype type-number)))) - (warn "Super class mismatch between CLOS and GObject for ~A" - class-name))) - (update-size class) - (call-next-method)) + (prog1 + #+clisp(call-next-method) + (let* ((class-name (class-name class)) + (super (most-specific-proxy-superclass class)) + (gtype (or + (first (ginstance-class-gtype class)) + (default-alien-type-name class-name))) + (type-number + (or + (find-type-number class-name) + (let ((type-number + (if (or + (symbolp gtype) + (type-number-from-glib-name gtype nil)) + (register-type class-name gtype) + (register-new-type class-name (class-name super) gtype)))) + (type-class-ref type-number) + type-number)))) + (when (and + (supertype type-number) + (not (eq (class-name super) (supertype type-number)))) + (warn "Super class mismatch between CLOS and GObject for ~A" + class-name))) + (update-size class)) + #-clisp(call-next-method)) (defmethod shared-initialize ((class ginstance-class) names &rest initargs) - (declare (ignore initargs)) + (declare (ignore names initargs)) (call-next-method) (when (class-finalized-p class) (update-size class))) @@ -346,11 +364,17 @@ (defclass ginstance (proxy) (:metaclass proxy-class) (:size #.(size-of 'pointer)))) +(defun ref-type-number (location &optional offset) + (declare (ignore location offset))) + +(setf (symbol-function 'ref-type-number) (reader-function 'type-number)) + (defun %type-number-of-ginstance (location) - (let ((class (sap-ref-sap location 0))) - (sap-ref-32 class 0))) + (let ((class (ref-pointer location))) + (ref-type-number class))) -(defmethod make-proxy-instance :around ((class ginstance-class) location &rest initargs) +(defmethod make-proxy-instance :around ((class ginstance-class) location + &rest initargs) (declare (ignore class)) (let ((class (labels ((find-known-class (type-number) (or @@ -358,7 +382,7 @@ (defmethod make-proxy-instance :around ((class ginstance-class) location &rest i (unless (zerop type-number) (find-known-class (type-parent type-number)))))) (find-known-class (%type-number-of-ginstance location))))) - ;; Note that chancing the class argument must not alter "the + ;; Note that chancing the class argument should not alter "the ;; ordered set of applicable methods" as specified in the ;; Hyperspec (if class @@ -366,32 +390,11 @@ (defmethod make-proxy-instance :around ((class ginstance-class) location &rest i (error "Object at ~A has an unkown type number: ~A" location (%type-number-of-ginstance location))))) -(defmethod make-proxy-instance ((class ginstance-class) location &rest initargs) - (declare (ignore initargs)) - (reference-foreign class location) - ;; Since we make an explicit reference to the foreign object, we - ;; always have to release it when the proxy is garbage collected - ;; and therefor ignore the weak-p argument. - (call-next-method class location :weak nil)) - -(defmethod invalidate-instance ((instance ginstance)) - (declare (ignore instance)) - ;; A ginstance should never be invalidated since it is ref counted - nil) +(define-type-method from-alien-form ((type ginstance) form &key (ref :copy)) + (call-next-method type form :ref ref)) -(define-type-method copy-from-alien-form ((type ginstance) location) - (declare (ignore location type)) - (error "Doing copy-from-alien on a ref. counted class is most certainly an error, but if it really is what you want you should use REFERENCE-FOREIGN on the returned instance instead.")) - -(define-type-method copy-from-alien-function ((type ginstance)) - (declare (ignore type)) - (error "Doing copy-from-alien on a ref. counted class is most certainly an error, but if it really is what you want you should use REFERENCE-FOREIGN on the returned instance instead.")) - -(define-type-method reader-function ((type ginstance)) - (let ((class (type-expand type))) - #'(lambda (location &optional (offset 0) weak-p) - (declare (ignore weak-p)) - (ensure-proxy-instance class (sap-ref-sap location offset))))) +(define-type-method from-alien-function ((type ginstance) &key (ref :copy)) + (call-next-method type :ref ref)) ;;;; Registering fundamental types @@ -433,6 +436,7 @@ (defun expand-type-definition (type forward-p options) (let ((expander (first (find-type-info type)))) (funcall expander (find-type-number type t) forward-p options))) + (defbinding type-parent (type) type-number ((find-type-number type t) type-number)) @@ -492,39 +496,65 @@ (defun find-types (prefix) *derivable-type-info*) type-list)) -(defun find-type-dependencies (type) - (let ((list-dependencies (second (find-type-info type)))) - (when list-dependencies - (funcall list-dependencies (find-type-number type t))))) - -(defun %sort-types-topologicaly (types) - (let ((partial-sorted - (sort - (mapcar - #'(lambda (type) - (cons type (remove-if #'(lambda (dep) - (not (find dep types))) - (find-type-dependencies type)))) - types) - #'(lambda (type1 type2) (type-is-p type2 type1)) :key #'car)) - (sorted ())) - - (loop - as tmp = partial-sorted then (or (rest tmp) partial-sorted) - while tmp - do (destructuring-bind (type . dependencies) (first tmp) - (cond - ((every #'(lambda (dep) - (assoc dep sorted)) - dependencies) - (push (cons type nil) sorted) ; no forward definition needed - (setq partial-sorted (delete type partial-sorted :key #'first))) - ((some #'(lambda (dep) - (find type (find-type-dependencies dep))) - dependencies) - (push (cons type t) sorted) ; forward definition needed - (setq partial-sorted (delete type partial-sorted :key #'first)))))) - (nreverse sorted))) +(defun find-type-dependencies (type &optional options) + (let ((find-dependencies (second (find-type-info type)))) + (when find-dependencies + (remove-duplicates + (mapcar #'find-type-number + (funcall find-dependencies (find-type-number type t) options)))))) + + +;; The argument is a list where each elements is on the form +;; (type . dependencies) +(defun sort-types-topologicaly (unsorted) + (flet ((depend-p (type1) + (find-if #'(lambda (type2) + (and + ;; If a type depends a subtype it has to be + ;; forward defined + (not (type-is-p (car type2) (car type1))) + (find (car type2) (cdr type1)))) + unsorted))) + (let ((sorted + (loop + while unsorted + nconc (multiple-value-bind (sorted remaining) + (delete-collect-if + #'(lambda (type) + (or (not (cdr type)) (not (depend-p type)))) + unsorted) + (cond + ((not sorted) + ;; We have a circular dependency which have to + ;; be resolved + (let ((selected + (find-if + #'(lambda (type) + (every + #'(lambda (dep) + (or + (not (type-is-p (car type) dep)) + (not (find dep unsorted :key #'car)))) + (cdr type))) + unsorted))) + (unless selected + (error "Couldn't resolve circular dependency")) + (setq unsorted (delete selected unsorted)) + (list selected))) + (t + (setq unsorted remaining) + sorted)))))) + + ;; Mark types which have to be forward defined + (loop + for tmp on sorted + as (type . dependencies) = (first tmp) + collect (cons type (and + dependencies + (find-if #'(lambda (type) + (find (car type) dependencies)) + (rest tmp)) + t)))))) (defun expand-type-definitions (prefix &optional args) @@ -556,7 +586,17 @@ (defun expand-type-definitions (prefix &optional args) (getf (type-options type-number) :type (default-type-name name)) (register-type-as type-number)))) - (let ((sorted-type-list (%sort-types-topologicaly type-list))) + ;; This is needed for some unknown reason to get type numbers right + (mapc #'find-type-dependencies type-list) + + (let ((sorted-type-list + #+clisp (mapcar #'list type-list) + #-clisp + (sort-types-topologicaly + (mapcar + #'(lambda (type) + (cons type (find-type-dependencies type (type-options type)))) + type-list)))) `(progn ,@(mapcar #'(lambda (pair) @@ -573,6 +613,9 @@ (defun expand-type-definitions (prefix &optional args) (defmacro define-types-by-introspection (prefix &rest args) (expand-type-definitions prefix args)) +(defexport define-types-by-introspection (prefix &rest args) + (list-autoexported-symbols (expand-type-definitions prefix args)))) + ;;;; Initialize all non static types in GObject -- [mdw]