Major cleanup of ffi abstraction layer
[clg] / glib / gtype.lisp
CommitLineData
0d07716f 1;; Common Lisp bindings for GTK+ v2.0
3a935dfa 2;; Copyright (C) 2000-2001 Espen S. Johnsen <esj@stud.cs.uit.no>
0d07716f 3;;
4;; This library is free software; you can redistribute it and/or
5;; modify it under the terms of the GNU Lesser General Public
6;; License as published by the Free Software Foundation; either
7;; version 2 of the License, or (at your option) any later version.
8;;
9;; This library is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12;; Lesser General Public License for more details.
13;;
14;; You should have received a copy of the GNU Lesser General Public
15;; License along with this library; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
d1266407 18;; $Id: gtype.lisp,v 1.18 2004/10/31 11:41:06 espen Exp $
0d07716f 19
20(in-package "GLIB")
21
22(use-prefix "g")
23
d1266407 24;; Initialize the glib type system
25(defbinding type-init () nil)
26(type-init)
0d07716f 27
28(deftype type-number () '(unsigned 32))
29
fc47a022 30(eval-when (:compile-toplevel :load-toplevel :execute)
3a935dfa 31 (defclass type-query (struct)
fc47a022 32 ((type-number :allocation :alien :type type-number)
33 (name :allocation :alien :type string)
34 (class-size :allocation :alien :type unsigned-int)
35 (instance-size :allocation :alien :type unsigned-int))
36 (:metaclass proxy-class)))
37
38
fc47a022 39(defbinding %type-query () nil
40 (type type-number)
41 (query type-query))
42
43(defun type-query (type)
44 (let ((query (make-instance 'type-query)))
3a935dfa 45 (%type-query (find-type-number type t) query)
fc47a022 46 query))
47
48(defun type-instance-size (type)
49 (slot-value (type-query type) 'instance-size))
50
51(defun type-class-size (type)
52 (slot-value (type-query type) 'class-size))
0d07716f 53
3a935dfa 54(defbinding type-class-ref (type) pointer
55 ((find-type-number type t) type-number))
0d07716f 56
3a935dfa 57(defbinding type-class-unref (type) nil
58 ((find-type-number type t) type-number))
fc47a022 59
3a935dfa 60(defbinding type-class-peek (type) pointer
61 ((find-type-number type t) type-number))
fc47a022 62
0d07716f 63
3a935dfa 64;;;; Mapping between lisp types and glib types
0d07716f 65
66(defvar *type-to-number-hash* (make-hash-table))
67(defvar *number-to-type-hash* (make-hash-table))
68
3a935dfa 69(defun register-type (type id)
70 (let ((type-number
71 (etypecase id
72 (integer id)
935a783c 73 (string (find-type-number id t))
74 (symbol (gethash id *type-to-number-hash*)))))
3a935dfa 75 (setf (gethash type *type-to-number-hash*) type-number)
935a783c 76 (unless (symbolp id)
77 (setf (gethash type-number *number-to-type-hash*) type))
3a935dfa 78 type-number))
79
80(defbinding %type-from-name () type-number
81 (name string))
82
83(defun find-type-number (type &optional error)
0d07716f 84 (etypecase type
85 (integer type)
3a935dfa 86 (string
87 (let ((type-number (%type-from-name type)))
88 (cond
89 ((and (zerop type-number) error)
90 (error "Invalid alien type name: ~A" type))
91 ((zerop type-number) nil)
92 (t type-number))))
93 (symbol
94 (let ((type-number (gethash type *type-to-number-hash*)))
95 (or
96 type-number
97 (and error (error "Type not registered: ~A" type)))))
98 (pcl::class (find-type-number (class-name type) error))))
0d07716f 99
b011356b 100(defun type-from-number (type-number &optional error)
101 (multiple-value-bind (type found)
102 (gethash type-number *number-to-type-hash*)
103 (when (and error (not found))
104 (let ((name (find-type-name type-number)))
105 (if name
106 (error "Type number not registered: ~A (~A)" type-number name)
107 (error "Invalid type number: ~A" type-number))))
108 type))
0d07716f 109
3a935dfa 110(defun type-from-name (name)
111 (etypecase name
112 (string (type-from-number (find-type-number name t)))))
0d07716f 113
3a935dfa 114(defbinding (find-type-name "g_type_name") (type) string
115 ((find-type-number type t) type-number))
116
117(defun type-number-of (object)
118 (find-type-number (type-of object) t))
119
120(defun init-type (init)
121 (mapc
122 #'(lambda (fname)
123 (funcall (mkbinding fname 'type-number)))
124 (mklist init)))
125
b011356b 126(defun %init-types-in-library (pathname ignore)
3a935dfa 127 (let ((process (ext:run-program
27487b3d 128 "nm" (list "-D" (namestring (truename pathname)))
3a935dfa 129 :output :stream :wait nil))
130 (fnames ()))
131 (labels ((read-symbols ()
132 (let ((line (read-line (ext:process-output process) nil)))
133 (when line
b011356b 134 (let ((symbol (subseq line 11)))
135 (when (and
136 (search "_get_type" symbol)
137 (not (member symbol ignore :test #'string=)))
138 (push symbol fnames)))
3a935dfa 139 (read-symbols)))))
140 (read-symbols)
141 (ext:process-close process)
142 `(init-type ',fnames))))
0d07716f 143
27487b3d 144(defmacro init-types-in-library (filename &key ignore)
145 (%init-types-in-library
74ebfcd1 146 (format nil "~A/~A" *gtk-library-path* filename) ignore))
b011356b 147
148
0d07716f 149
fc47a022 150;;;; Superclass for wrapping types in the glib type system
0d07716f 151
152(eval-when (:compile-toplevel :load-toplevel :execute)
fc47a022 153 (defclass ginstance (proxy)
3a935dfa 154 ((class :allocation :alien :type pointer))
155 (:metaclass proxy-class)))
0d07716f 156
fc47a022 157(defun %type-of-ginstance (location)
158 (let ((class (sap-ref-sap location 0)))
159 (type-from-number (sap-ref-unsigned class 0))))
0d07716f 160
161(deftype-method translate-from-alien
fc47a022 162 ginstance (type-spec location &optional weak-ref)
163 (declare (ignore type-spec))
0d07716f 164 `(let ((location ,location))
165 (unless (null-pointer-p location)
fc47a022 166 (ensure-proxy-instance
167 (%type-of-ginstance location) location ,weak-ref))))
0d07716f 168
0d07716f 169
170
fc47a022 171;;;; Metaclass for subclasses of ginstance
0d07716f 172
173(eval-when (:compile-toplevel :load-toplevel :execute)
935a783c 174 (defclass ginstance-class (proxy-class)
175 ()))
0d07716f 176
177
c9819f3e 178(defmethod shared-initialize ((class ginstance-class) names
3a935dfa 179 &rest initargs &key name alien-name
935a783c 180 ref unref)
0d07716f 181 (declare (ignore initargs names))
fc47a022 182 (let* ((class-name (or name (class-name class)))
183 (type-number
3a935dfa 184 (find-type-number
b011356b 185 (or (first alien-name) (default-alien-type-name class-name)) t)))
3a935dfa 186 (register-type class-name type-number)
935a783c 187 (if (getf initargs :size)
188 (call-next-method)
189 (let ((size (type-instance-size type-number)))
190 (apply #'call-next-method class names :size (list size) initargs))))
3a935dfa 191
192 (when ref
193 (let ((ref (mkbinding (first ref) 'pointer 'pointer)))
fc47a022 194 (setf
3a935dfa 195 (slot-value class 'copy)
196 #'(lambda (type location)
197 (declare (ignore type))
935a783c 198 (funcall ref location)))))
3a935dfa 199 (when unref
200 (let ((unref (mkbinding (first unref) 'nil 'pointer)))
fc47a022 201 (setf
3a935dfa 202 (slot-value class 'free)
203 #'(lambda (type location)
204 (declare (ignore type))
205 (funcall unref location))))))
0d07716f 206
207
208(defmethod validate-superclass
c9819f3e 209 ((class ginstance-class) (super pcl::standard-class))
210 (subtypep (class-name super) 'ginstance))
0d07716f 211
212
3a935dfa 213;;;; Registering fundamental types
214
215(register-type 'pointer "gpointer")
216(register-type 'char "gchar")
217(register-type 'unsigned-char "guchar")
218(register-type 'boolean "gboolean")
219(register-type 'fixnum "gint")
220(register-type 'int "gint")
221(register-type 'unsigned-int "guint")
222(register-type 'long "glong")
223(register-type 'unsigned-long "gulong")
224(register-type 'single-float "gfloat")
225(register-type 'double-float "gdouble")
b011356b 226(register-type 'string "gchararray")
3a935dfa 227
228
229;;;;
230
4812615b 231(defvar *derivable-type-info* (make-hash-table))
3a935dfa 232
4812615b 233(defun register-derivable-type (type id expander)
3a935dfa 234 (register-type type id)
4812615b 235 (let ((type-number (register-type type id)))
236 (setf (gethash type-number *derivable-type-info*) expander)))
3a935dfa 237
b011356b 238(defun find-type-info (type)
239 (dolist (super (cdr (type-hierarchy type)))
4812615b 240 (let ((info (gethash super *derivable-type-info*)))
b011356b 241 (return-if info))))
242
4812615b 243(defun expand-type-definition (type options)
244 (let ((expander (find-type-info type)))
245 (funcall expander (find-type-number type t) options)))
3a935dfa 246
3a935dfa 247(defbinding type-parent (type) type-number
248 ((find-type-number type t) type-number))
249
250(defun supertype (type)
251 (type-from-number (type-parent type)))
252
7858d45e 253(defbinding %type-interfaces (type) pointer
254 ((find-type-number type t) type-number)
255 (n-interfaces unsigned-int :out))
256
257(defun type-interfaces (type)
258 (multiple-value-bind (array length) (%type-interfaces type)
259 (unwind-protect
260 (map-c-array 'list #'identity array 'type-number length)
261 (deallocate-memory array))))
262
263(defun implements (type)
264 (mapcar #'type-from-number (type-interfaces type)))
265
3a935dfa 266(defun type-hierarchy (type)
267 (let ((type-number (find-type-number type t)))
268 (unless (= type-number 0)
269 (cons type-number (type-hierarchy (type-parent type-number))))))
270
271(defbinding (type-is-p "g_type_is_a") (type super) boolean
272 ((find-type-number type) type-number)
273 ((find-type-number super) type-number))
274
275(defbinding %type-children () pointer
276 (type-number type-number)
277 (num-children unsigned-int :out))
278
279(defun map-subtypes (function type &optional prefix)
280 (let ((type-number (find-type-number type t)))
281 (multiple-value-bind (array length) (%type-children type-number)
282 (unwind-protect
283 (map-c-array
284 'nil
285 #'(lambda (type-number)
286 (when (or
287 (not prefix)
288 (string-prefix-p prefix (find-type-name type-number)))
289 (funcall function type-number))
290 (map-subtypes function type-number prefix))
291 array 'type-number length)
292 (deallocate-memory array)))))
293
294(defun find-types (prefix)
295 (let ((type-list nil))
4812615b 296 (maphash
297 #'(lambda (type-number expander)
298 (declare (ignore expander))
299 (map-subtypes
300 #'(lambda (type-number)
301 (pushnew type-number type-list))
302 type-number prefix))
303 *derivable-type-info*)
3a935dfa 304 type-list))
305
306(defun %sort-types-topologicaly (unsorted)
307 (let ((sorted ()))
308 (loop while unsorted do
309 (dolist (type unsorted)
7858d45e 310 (let ((dependencies
311 (append (rest (type-hierarchy type)) (type-interfaces type))))
3a935dfa 312 (cond
313 ((null dependencies)
314 (push type sorted)
315 (setq unsorted (delete type unsorted)))
316 (t
317 (unless (dolist (dep dependencies)
4812615b 318 (when (find type (rest (type-hierarchy dep)))
319 (error "Cyclic type dependencie"))
3a935dfa 320 (return-if (find dep unsorted)))
321 (push type sorted)
322 (setq unsorted (delete type unsorted))))))))
323 (nreverse sorted)))
324
325
326(defun expand-type-definitions (prefix &optional args)
4812615b 327 (flet ((type-options (type-number)
3a935dfa 328 (let ((name (find-type-name type-number)))
b011356b 329 (cdr (assoc name args :test #'string=)))))
3a935dfa 330
4812615b 331 (let ((type-list
332 (delete-if
333 #'(lambda (type-number)
334 (let ((name (find-type-name type-number)))
335 (or
336 (getf (type-options type-number) :ignore)
337 (find-if
338 #'(lambda (options)
339 (and
340 (string-prefix-p (first options) name)
17c607d0 341 (getf (cdr options) :ignore-prefix)
342 (not (some
343 #'(lambda (exception)
344 (string= name exception))
345 (getf (cdr options) :except)))))
4812615b 346 args))))
347 (find-types prefix))))
3a935dfa 348
4812615b 349 (dolist (type-number type-list)
350 (let ((name (find-type-name type-number)))
351 (register-type
352 (getf (type-options type-number) :type (default-type-name name))
353 type-number)))
354
355 `(progn
356 ,@(mapcar
357 #'(lambda (type)
358 (expand-type-definition type (type-options type)))
359 (%sort-types-topologicaly type-list))))))
360
3a935dfa 361(defmacro define-types-by-introspection (prefix &rest args)
b011356b 362 (expand-type-definitions prefix args))
4812615b 363
364
365