#_ reader macro enum calls & cleanup
Annotate for file src/commonqt.lisp
2009-07-02 tobias 1 (in-package :cl-smoke.commonqt)
17:34:07 ' 2
' 3 ;;; calling methods
' 4 ;;;
' 5 (eval-when (:load-toplevel :compile-toplevel :execute)
2009-07-24 tobias 6 (defun read-perserving-case (stream)
13:39:55 ' 7 (let ((*readtable* (copy-readtable nil)))
' 8 (setf (readtable-case *readtable*) :preserve)
' 9 (read stream)))
2009-07-02 tobias 10
2009-07-24 tobias 11 (defun cl-smoke-funcall-form (stream subchar arg)
13:39:55 ' 12 (declare (ignore subchar arg))
' 13 (let ((method (read-perserving-case stream)))
' 14 (if (string= "new" (symbol-name method))
' 15 `(lambda (&rest args)
' 16 (make-instance
' 17 ',(smoke::lispify (symbol-name (read-perserving-case stream)) :cl-smoke.qt)
' 18 :args args))
' 19 (let ((object (read stream)))
' 20 (if (stringp object)
2009-07-02 tobias 21 (if (upper-case-p (char (symbol-name method) 0))
20:48:38 ' 22 `(lambda ()
' 23 ,(smoke::lispify
' 24 (concatenate 'string
' 25 (if (string= "Qt" object)
' 26 "+"
' 27 (concatenate 'string
' 28 object
' 29 ".+"))
' 30 (symbol-name method) "+")
' 31 :cl-smoke.qt))
' 32 `(lambda (&rest args)
' 33 (apply (symbol-function ',(smoke::lispify (symbol-name method) :cxx))
' 34 (find-class ',(smoke::lispify object :cl-smoke.qt))
' 35 args)))
2009-07-24 tobias 36 `(lambda (&rest args)
13:39:55 ' 37 (apply (symbol-function ',(smoke::lispify (symbol-name method) :cxx))
' 38 ,object
' 39 args))))))))
2009-07-02 tobias 40
17:34:07 ' 41 (eval-when (:load-toplevel :compile-toplevel)
' 42 (set-dispatch-macro-character #\# #\_ #'cl-smoke-funcall-form))
' 43
' 44 ;;; Instantiating
' 45 ;;;
' 46 (defun new (instance &rest arguments)
' 47 "Calls the C++ construor for INSTANCE with ARGUMENTS."
2009-07-24 tobias 48 (assert (null-pointer-p (smoke:pointer instance)))
2009-07-02 tobias 49 (setf (slot-value instance 'smoke:pointer)
2010-01-10 tobias 50 (smoke::call-constructor instance arguments))
2009-07-24 tobias 51 (assert (not (null-pointer-p (smoke:pointer instance))))
2009-07-02 tobias 52 (smoke::set-binding instance)
17:34:07 ' 53 (smoke::take-ownership instance)
' 54 (smoke::add-object instance)
' 55 instance)
' 56
' 57 ;;; Connecting signals and slots
' 58 ;;;
' 59 (defun qsignal (name)
' 60 (cl-smoke.qt:qsignal name))
' 61 (defun qslot (name)
' 62 (cl-smoke.qt:qslot name))
' 63
' 64 ;;; QApplication
' 65 ;;;
' 66 (defun make-qapplication (&rest arguments)
' 67 "Returns a new QApplication instance with ARGUMENTS as command line
' 68 arguments argv. argv[0] is set to (LISP-IMPLEMNTATION-TYPE)."
2009-07-02 tobias 69 (let* ((argc ;(smoke::make-auto-pointer
2009-07-02 tobias 70 (cffi:foreign-alloc :int
2009-07-02 tobias 71 :initial-element (1+ (length arguments))))
21:49:43 ' 72 (argv ;(smoke::make-auto-pointer
2009-07-02 tobias 73 (cffi:foreign-alloc :string
17:34:07 ' 74 :initial-contents
' 75 (cons (lisp-implementation-type) ;; arg0
2009-07-02 tobias 76 arguments)))
2009-07-02 tobias 77 (application (make-instance 'cl-smoke.qt:application :args
17:34:07 ' 78 (list argc argv))))
' 79 ;; argc & argv must remain valid during the lifetime of application.
' 80 (setf (cl-smoke.qt:property application 'arguments)
' 81 (cl-smoke.qt:make-lisp-variant (cons argc argv)))
' 82 application))
' 83
' 84 ;;; Overriding C++ methods
' 85 (defclass override-gf (standard-generic-function)
' 86 ((cxx-gf :initarg :cxx-gf
' 87 :reader cxx-gf))
' 88 (:metaclass closer-mop:funcallable-standard-class)
' 89 (:documentation "Redirects its methods to CXX-GF."))
' 90
' 91 (defmethod add-method ((gf override-gf) method)
' 92 (add-method (cxx-gf gf) method))
' 93
' 94 (defmethod remove-method ((gf override-gf) method)
' 95 (remove-method (cxx-gf gf) method))
' 96
' 97 ;;; Subclassing C++ & defining signals and slots
' 98 ;;;
' 99 (defclass qt-class (cxx:class)
2009-07-24 tobias 100 ((qt-slots :initarg :slots :initform nil) ;; FIXME remove this
13:39:55 ' 101 (signals :initarg :signals :initform nil) ;; FIXME remove this
' 102 (method-functions :documentation "The signals and slots.")
' 103 (meta-object)))
2009-07-02 tobias 104
2009-07-02 tobias 105 (defclass signal-slot-mixin ()
20:48:38 ' 106 ())
' 107
2009-07-24 tobias 108 (defun setup-meta-object (class qt-superclass)
13:39:55 ' 109 (let ((methods (make-array (+ (length (slot-value class 'signals))
' 110 (length (slot-value class 'qt-slots)))
2009-07-02 tobias 111 :element-type 'function
17:34:07 ' 112 :initial-element #'identity))
' 113 (index 0))
2009-07-24 tobias 114 (dolist (signal-name (slot-value class 'signals))
2009-07-02 tobias 115 (setf (aref methods index)
2009-07-02 tobias 116 #'(lambda (this &rest args)
2009-07-02 tobias 117 (apply #'emit-signal this signal-name args)))
20:48:38 ' 118 (incf index))
2009-07-24 tobias 119 (dolist (slot (slot-value class 'qt-slots))
2009-07-02 tobias 120 (setf (aref methods index)
17:34:07 ' 121 (if (symbolp (second slot))
' 122 (second slot)
' 123 (eval `(function ,(second slot)))))
' 124 (incf index))
2009-07-24 tobias 125 (setf (slot-value class 'method-functions) methods))
2009-07-02 tobias 126 (let ((signals (mapcar #'(lambda (s) (make-slot-or-signal (first s)))
2009-07-24 tobias 127 (slot-value class 'signals)))
2009-07-02 tobias 128 (slots (mapcar #'(lambda (s) (make-slot-or-signal (first s)))
2009-07-24 tobias 129 (slot-value class 'qt-slots)))
2009-07-02 tobias 130 (class-name (class-name class)))
17:34:07 ' 131 (setf (slot-value class 'meta-object)
' 132 (make-metaobject qt-superclass
' 133 (format nil "~A::~A"
' 134 (package-name (symbol-package class-name))
' 135 (symbol-name class-name))
' 136 nil
' 137 signals
' 138 slots))))
' 139
' 140 (defun setup-qt-class (qt-class next-method &rest args &key qt-superclass
' 141 direct-superclasses direct-default-initargs
' 142 override &allow-other-keys)
2009-07-24 tobias 143 (assert (null direct-superclasses))
2009-07-02 tobias 144 (dolist (method override)
17:34:07 ' 145 (ensure-generic-function
' 146 (second method)
' 147 :generic-function-class (find-class 'override-gf)
' 148 :lambda-list '(this &rest args)
' 149 :cxx-gf (fdefinition (smoke::lispify (first method) :cxx))))
' 150 (apply next-method qt-class
' 151 :direct-default-initargs ;; the C++ instance is constructed with #'NEW
' 152 (cons `(:pointer (null-pointer) ,#'null-pointer)
' 153 direct-default-initargs)
' 154 :direct-superclasses
2009-07-02 tobias 155 (list (find-qclass (first qt-superclass))
20:48:38 ' 156 (find-class 'signal-slot-mixin))
2009-07-02 tobias 157 args)
2009-07-24 tobias 158 (setup-meta-object qt-class (find-qclass (first qt-superclass))))
2009-07-02 tobias 159
2009-07-02 tobias 160 (defmethod cxx:meta-object ((this signal-slot-mixin))
20:48:38 ' 161 (slot-value (class-of this) 'meta-object))
' 162
' 163 (defmethod cxx:qt-metacall ((this signal-slot-mixin) call id arguments)
' 164 (let ((m-id (call-next-method)))
' 165 (if (< m-id 0)
' 166 m-id
' 167 (if (enum= call cl-smoke.qt:meta-object.+invoke-meta-method+)
' 168 (progn
' 169 (when (< m-id (length (slot-value (class-of this)
' 170 'method-functions)))
' 171 (with-simple-restart
' 172 (continue "Skip the method ~A of ~A."
' 173 (cxx:signature
' 174 (cxx:method (cxx:meta-object this) id))
' 175 this)
' 176 (apply (aref (slot-value (class-of this) 'method-functions)
' 177 m-id)
' 178 this
' 179 (cl-smoke.qt-impl::arguments-to-lisp
' 180 arguments
' 181 (cl-smoke.qt-impl::method-arguments-type
' 182 (cxx:meta-object this) id)))))
' 183 (- m-id
' 184 (length (slot-value (class-of this) 'method-functions))))
' 185 m-id))))
' 186
2009-07-02 tobias 187 (defmethod initialize-instance :around ((class qt-class)
2009-08-27 tobias 188 &rest args)
2009-07-02 tobias 189 (apply #'setup-qt-class class #'call-next-method args))
2009-07-02 tobias 190
2009-08-27 tobias 191 (defmethod reinitialize-instance :around ((qt-class qt-class) &rest args)
2009-07-02 tobias 192 (apply #'setup-qt-class qt-class #'call-next-method args))
17:34:07 ' 193
' 194 (defun emit-signal (object signal-name &rest arguments)
' 195 "Emits the signal SIGNAL-NAME of OBJECT using ARGUMENTS."
2009-07-24 tobias 196 (let* ((meta-object (slot-value (class-of object) 'meta-object))
13:39:55 ' 197 (id (#_indexOfSignal meta-object signal-name)))
2009-07-02 tobias 198 (assert (>= id 0)
17:34:07 ' 199 ()
' 200 "No signal ~A of ~A." signal-name object)
2010-01-10 tobias 201 (cl-smoke.qt-impl::activate
08:53:29 ' 202 object id (cl-smoke.qt-impl::method-arguments-type meta-object id)
2009-07-02 tobias 203 arguments)))
17:34:07 ' 204
' 205 (defmacro call-next-qmethod ()
' 206 "Calls the next method."
' 207 '(call-next-method))
' 208
2009-07-24 tobias 209
2009-07-02 tobias 210 ;;; Enum values
17:34:07 ' 211 ;;;
' 212 (defun primitive-value (enum)
' 213 "Returns the integer value of ENUM."
' 214 (cxx-support:value enum))
' 215
' 216 ;;; Type disambiguation
' 217 ;;;
' 218 ;; No-op since we have overload resolution.
' 219 (setf (fdefinition 'uint) #'identity
2009-07-02 tobias 220 (fdefinition 'int) #'identity
20:48:38 ' 221 (fdefinition 'bool) #'identity
' 222 (fdefinition 'qstring) #'identity)
2009-07-02 tobias 223
17:34:07 ' 224 (defun find-qclass (class-name)
' 225 "Returns the CLOS class for the C++ CLASS-NAME string."
' 226 (find-class (smoke::lispify class-name :cl-smoke.qt)))