+(defun slot-definition-from-property (class property)
+ (with-slots (name flags value-type documentation) property
+ (let* ((slot-name (default-slot-name name))
+ (slot-type (or (type-from-number value-type) value-type))
+ (accessor (default-slot-accessor class slot-name slot-type)))
+
+ `(,slot-name
+ :allocation :property :pname ,name
+
+ ;; accessors
+ ,@(cond
+ ((and
+ (member :writable flags) (member :readable flags)
+ (not (member :construct-only flags)))
+ (list :accessor accessor))
+ ((and (member :writable flags) (not (member :construct-only flags)))
+ (list :writer `(setf ,accessor)))
+ ((member :readable flags)
+ (list :reader accessor)))
+
+ ;; readable/writable/construct
+ ,@(when (or (not (member :writable flags))
+ (member :construct-only flags))
+ '(:writable nil))
+ ,@(when (not (member :readable flags))
+ '(:readable nil))
+ ,@(when (or (member :construct flags)
+ (member :construct-only flags))
+ '(:construct t))
+
+ ;; initargs
+ ,@(when (or (member :construct flags)
+ (member :construct-only flags)
+ (member :writable flags))
+ (list :initarg (intern (string slot-name) "KEYWORD")))
+
+ :type ,slot-type
+ :documentation ,documentation))))
+
+
+(defun slot-definitions (class properties slots)
+ (loop
+ with manual-slots = slots
+ for property in properties
+ unless (find-if
+ #'(lambda (slot)
+ (destructuring-bind (name &rest args) slot
+ (or
+ (equal (param-name property) (getf args :pname))
+ (eq (default-slot-name (param-name property)) name))))
+ manual-slots)
+ do (push (slot-definition-from-property class property) slots))
+ (delete-if #'(lambda (slot) (getf (rest slot) :ignore)) slots))
+
+
+(defun expand-gobject-type (type &optional options (metaclass 'gobject-class))
+ (let ((supers (cons (supertype type) (implements type)))
+ (class (type-from-number type))
+ (slots (getf options :slots)))
+ `(defclass ,class ,supers
+ ,(slot-definitions class (query-object-class-properties type) slots)
+ (:metaclass ,metaclass)
+ (:alien-name ,(find-type-name type)))))