(defvar *additional-properties* nil)
(defun name->supplied-p (name)
- (intern (format nil "~A-SUPPLIED-P" (symbol-name name))
- *lisp-name-package*))
+ (make-symbol (format nil "~A-SUPPLIED-P" (symbol-name name))))
(defstruct property name accessor-name readable writable)
:reader ',(cffi-property-reader object)
:writer ',(cffi-property-writer object)))
-(defun parse-accessor (spec)
- (ecase (first spec)
- (:cffi (destructuring-bind (&key reader writer) (rest spec)
- (make-cffi-property-accessor :reader reader :writer writer)))
- (:gobject (destructuring-bind (property-name) (rest spec)
- (make-gobject-property-accessor :property-name property-name)))))
-
(defun parse-gobject-property (spec)
(destructuring-bind (name accessor-name gname type readable writable) spec
(make-gobject-property :name name
(lispify-name property-name))
*lisp-name-package*))
-(defgeneric property->reader (property))
-(defgeneric property->writer (property))
+(defgeneric property->reader (class property))
+(defgeneric property->writer (class property))
-(defmethod property->reader ((property gobject-property))
+(defmethod property->reader (class (property gobject-property))
(with-slots (accessor-name type gname) property
- `(defun ,accessor-name (object)
+ `(defmethod ,accessor-name ((object ,class))
(g-object-call-get-property object ,gname ,type))))
-(defmethod property->reader ((property cffi-property))
+(defmethod property->reader (class (property cffi-property))
(with-slots (accessor-name type reader) property
- `(defun ,accessor-name (object)
- (foreign-funcall ,reader g-object object ,type))))
+ (etypecase reader
+ (string `(defmethod ,accessor-name ((object ,class))
+ (foreign-funcall ,reader g-object object ,type)))
+ (symbol `(defmethod ,accessor-name ((object ,class))
+ (funcall ',reader object))))))
-(defmethod property->writer ((property gobject-property))
+(defmethod property->writer (class (property gobject-property))
(with-slots (accessor-name type gname) property
- `(defun (setf ,accessor-name) (new-value object)
- (g-object-call-set-property object ,gname new-value ,type))))
-
-(defmethod property->writer ((property cffi-property))
- (with-slots (accessor-name type writer) property
- `(defun (setf ,accessor-name) (new-value object)
- (foreign-funcall ,writer g-object object ,type new-value :void))))
-
-(defun property->writer (property)
- (let ((name (nth 1 property))
- (prop-name (nth 2 property))
- (prop-type (nth 3 property)))
- `(defun (setf ,name) (new-value object)
- (g-object-call-set-property object ,prop-name new-value ,prop-type)
+ `(defmethod (setf ,accessor-name) (new-value (object ,class))
+ (g-object-call-set-property object ,gname new-value ,type)
new-value)))
-(defun property->accessors (property export)
+(defmethod property->writer (class (property cffi-property))
+ (with-slots (accessor-name type writer) property
+ (etypecase writer
+ (string `(defmethod (setf ,accessor-name) (new-value (object ,class))
+ (foreign-funcall ,writer g-object object ,type new-value :void)
+ new-value))
+ (symbol `(defmethod (setf ,accessor-name) (new-value (object ,class))
+ (funcall ',writer object new-value)
+ new-value)))))
+
+(defun property->accessors (class property export)
(append (when (property-readable property)
- (list (property->reader property)))
+ (list (property->reader class property)))
(when (property-writable property)
- (list (property->writer property)))
+ (list (property->writer class property)))
(when export
(list `(export ',(property-accessor-name property)
(find-package ,(package-name (symbol-package (property-accessor-name property)))))))))
(string `(foreign-funcall ,type-initializer g-type))
(symbol `(funcall ',type-initializer))))
+(defun meta-property->slot (class-name property)
+ `(,(property-name property)
+ :allocation ,(if (gobject-property-p property) :gobject-property :gobject-fn)
+ :g-property-type ,(if (gobject-property-p property) (gobject-property-type property) (cffi-property-type property))
+ :accessor ,(intern (format nil "~A-~A" (symbol-name class-name) (property-name property)) (symbol-package class-name))
+ :initarg ,(intern (string-upcase (property-name property)) (find-package :keyword))
+ ,@(if (gobject-property-p property)
+ `(:g-property-name ,(gobject-property-gname property))
+ `(:g-getter ,(cffi-property-reader property)
+ :g-setter ,(cffi-property-writer property)))))
+
(defmacro define-g-object-class (g-type-name name
(&key (superclass 'g-object)
(export t)
type-initializer)
(&rest properties))
(setf properties (mapcar #'parse-property properties))
- (let* ((superclass-properties (get superclass 'properties))
- (combined-properties (append superclass-properties properties)))
- `(progn
- (defclass ,name (,superclass ,@(mapcar #'interface->lisp-class-name interfaces)) ())
- (register-object-type ,g-type-name ',name)
+ `(progn
+ (defclass ,name (,superclass ,@(mapcar #'interface->lisp-class-name interfaces))
+ (,@(mapcar (lambda (property) (meta-property->slot name property)) properties))
+ (:metaclass gobject-class)
+ (:g-type-name . ,g-type-name)
,@(when type-initializer
- (list (type-initializer-call type-initializer)))
- ,@(when export
- (list `(export ',name (find-package ,(package-name (symbol-package name))))))
- (defmethod initialize-instance :before
- ((object ,name) &key pointer
- ,@(remove nil (mapcar #'property->method-arg
- combined-properties)))
- (unless (or pointer (and (slot-boundp object 'pointer)
- (not (null-pointer-p (pointer object)))))
- (let (arg-names arg-values arg-types)
- ,@(mapcar #'gobject-property->arg-push (remove-if-not #'gobject-property-p combined-properties))
- (setf (pointer object)
- (g-object-call-constructor ,g-type-name
- arg-names
- arg-values
- arg-types)
- (g-object-has-reference object) t)
- ,@(mapcar #'cffi-property->initarg (remove-if-not #'cffi-property-p combined-properties)))))
- ,@(loop
- for property in properties
- append (property->accessors property export))
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (setf (get ',name 'superclass) ',superclass
- (get ',name 'properties) ',combined-properties)))))
-
-(defmacro define-g-interface (g-name name (&key (export t) type-initializer) &body properties)
+ (list `(:g-type-initializer . ,type-initializer))))
+ ,@(when export
+ (cons `(export ',name (find-package ,(package-name (symbol-package name))))
+ (mapcar (lambda (property)
+ `(export ',(intern (format nil "~A-~A" (symbol-name name) (property-name property)) (symbol-package name))
+ (find-package ,(package-name (symbol-package name)))))
+ properties)))))
+
+(defmacro define-g-interface (g-type-name name (&key (export t) type-initializer) &body properties)
(setf properties (mapcar #'parse-property properties))
`(progn
- (defclass ,name () ())
+ (defclass ,name ()
+ (,@(mapcar (lambda (property) (meta-property->slot name property)) properties))
+ (:metaclass gobject-class)
+ (:g-type-name . ,g-type-name)
+ (:g-interface-p . t)
+ ,@(when type-initializer
+ (list `(:g-type-initializer . ,type-initializer))))
,@(when export
- (list `(export ',name (find-package ,(package-name (symbol-package name))))))
- ,@(when type-initializer
- (list (type-initializer-call type-initializer)))
- ,@(loop
- for property in properties
- append (property->accessors property export))
+ (cons `(export ',name (find-package ,(package-name (symbol-package name))))
+ (mapcar (lambda (property)
+ `(export ',(intern (format nil "~A-~A" (symbol-name name) (property-name property)) (symbol-package name))
+ (find-package ,(package-name (symbol-package name)))))
+ properties)))
(eval-when (:compile-toplevel :load-toplevel :execute)
- (setf (get ',name 'properties) ',properties)
- (setf (gethash ,g-name *known-interfaces*) ',name))))
+ (setf (gethash ,g-type-name *known-interfaces*) ',name))))
(defun starts-with (name prefix)
(and prefix (> (length name) (length prefix)) (string= (subseq name 0 (length prefix)) prefix)))
`(define-g-object-class ,g-name ,name
(:superclass ,superclass-name
:export t
- :interfaces (,@(mapcar #'g-type-name interfaces))
+ :interfaces (,@(sort (mapcar #'g-type-name interfaces) 'string<))
,@(when (and (foreign-symbol-pointer type-init-name)
(not (null-pointer-p (foreign-symbol-pointer type-init-name))))
`(:type-initializer ,type-init-name)))
(:export t
,@(when (foreign-symbol-pointer probable-type-initializer)
`(:type-initializer ,probable-type-initializer)))
- ,@(mapcar (lambda (property)
- (property->property-definition name property))
- properties))))
+ ,@(append (mapcar (lambda (property)
+ (property->property-definition name property))
+ properties)
+ (cdr (find g-name *additional-properties* :key 'car :test 'string=))))))
(defun get-g-class-definitions-for-root-1 (type)
(unless (member (ensure-g-type type) *generation-exclusions* :test '=)
(defmacro define-g-flags (g-name name (&key (export t) type-initializer) &body values)
`(progn
(defbitfield ,name ,@values)
- (register-enum-type ,g-name ',name)
+ (register-flags-type ,g-name ',name)
,@(when export
(list `(export ',name (find-package ,(package-name (symbol-package name))))))
,@(when type-initializer