chiark / gitweb /
Major cleanup of ffi abstraction layer
[clg] / glib / gtype.lisp
CommitLineData
560af5c5 1;; Common Lisp bindings for GTK+ v2.0
d4b21b08 2;; Copyright (C) 2000-2001 Espen S. Johnsen <esj@stud.cs.uit.no>
560af5c5 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
e0349dbd 18;; $Id: gtype.lisp,v 1.18 2004-10-31 11:41:06 espen Exp $
560af5c5 19
20(in-package "GLIB")
21
22(use-prefix "g")
23
e0349dbd 24;; Initialize the glib type system
25(defbinding type-init () nil)
26(type-init)
560af5c5 27
28(deftype type-number () '(unsigned 32))
29
93aa67db 30(eval-when (:compile-toplevel :load-toplevel :execute)
d4b21b08 31 (defclass type-query (struct)
93aa67db 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
93aa67db 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)))
d4b21b08 45 (%type-query (find-type-number type t) query)
93aa67db 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))
560af5c5 53
d4b21b08 54(defbinding type-class-ref (type) pointer
55 ((find-type-number type t) type-number))
560af5c5 56
d4b21b08 57(defbinding type-class-unref (type) nil
58 ((find-type-number type t) type-number))
93aa67db 59
d4b21b08 60(defbinding type-class-peek (type) pointer
61 ((find-type-number type t) type-number))
93aa67db 62
560af5c5 63
d4b21b08 64;;;; Mapping between lisp types and glib types
560af5c5 65
66(defvar *type-to-number-hash* (make-hash-table))
67(defvar *number-to-type-hash* (make-hash-table))
68
d4b21b08 69(defun register-type (type id)
70 (let ((type-number
71 (etypecase id
72 (integer id)
4d83a8a6 73 (string (find-type-number id t))
74 (symbol (gethash id *type-to-number-hash*)))))
d4b21b08 75 (setf (gethash type *type-to-number-hash*) type-number)
4d83a8a6 76 (unless (symbolp id)
77 (setf (gethash type-number *number-to-type-hash*) type))
d4b21b08 78 type-number))
79
80(defbinding %type-from-name () type-number
81 (name string))
82
83(defun find-type-number (type &optional error)
560af5c5 84 (etypecase type
85 (integer type)
d4b21b08 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))))
560af5c5 99
4de90d10 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))
560af5c5 109
d4b21b08 110(defun type-from-name (name)
111 (etypecase name
112 (string (type-from-number (find-type-number name t)))))
560af5c5 113
d4b21b08 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
4de90d10 126(defun %init-types-in-library (pathname ignore)
d4b21b08 127 (let ((process (ext:run-program
0c0db5e2 128 "nm" (list "-D" (namestring (truename pathname)))
d4b21b08 129 :output :stream :wait nil))
130 (fnames ()))
131 (labels ((read-symbols ()
132 (let ((line (read-line (ext:process-output process) nil)))
133 (when line
4de90d10 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)))
d4b21b08 139 (read-symbols)))))
140 (read-symbols)
141 (ext:process-close process)
142 `(init-type ',fnames))))
560af5c5 143
0c0db5e2 144(defmacro init-types-in-library (filename &key ignore)
145 (%init-types-in-library
b2bea410 146 (format nil "~A/~A" *gtk-library-path* filename) ignore))
4de90d10 147
148
560af5c5 149
93aa67db 150;;;; Superclass for wrapping types in the glib type system
560af5c5 151
152(eval-when (:compile-toplevel :load-toplevel :execute)
93aa67db 153 (defclass ginstance (proxy)
d4b21b08 154 ((class :allocation :alien :type pointer))
155 (:metaclass proxy-class)))
560af5c5 156
93aa67db 157(defun %type-of-ginstance (location)
158 (let ((class (sap-ref-sap location 0)))
159 (type-from-number (sap-ref-unsigned class 0))))
560af5c5 160
161(deftype-method translate-from-alien
93aa67db 162 ginstance (type-spec location &optional weak-ref)
163 (declare (ignore type-spec))
560af5c5 164 `(let ((location ,location))
165 (unless (null-pointer-p location)
93aa67db 166 (ensure-proxy-instance
167 (%type-of-ginstance location) location ,weak-ref))))
560af5c5 168
560af5c5 169
170
93aa67db 171;;;; Metaclass for subclasses of ginstance
560af5c5 172
173(eval-when (:compile-toplevel :load-toplevel :execute)
4d83a8a6 174 (defclass ginstance-class (proxy-class)
175 ()))
560af5c5 176
177
c8c48a4c 178(defmethod shared-initialize ((class ginstance-class) names
d4b21b08 179 &rest initargs &key name alien-name
4d83a8a6 180 ref unref)
560af5c5 181 (declare (ignore initargs names))
93aa67db 182 (let* ((class-name (or name (class-name class)))
183 (type-number
d4b21b08 184 (find-type-number
4de90d10 185 (or (first alien-name) (default-alien-type-name class-name)) t)))
d4b21b08 186 (register-type class-name type-number)
4d83a8a6 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))))
d4b21b08 191
192 (when ref
193 (let ((ref (mkbinding (first ref) 'pointer 'pointer)))
93aa67db 194 (setf
d4b21b08 195 (slot-value class 'copy)
196 #'(lambda (type location)
197 (declare (ignore type))
4d83a8a6 198 (funcall ref location)))))
d4b21b08 199 (when unref
200 (let ((unref (mkbinding (first unref) 'nil 'pointer)))
93aa67db 201 (setf
d4b21b08 202 (slot-value class 'free)
203 #'(lambda (type location)
204 (declare (ignore type))
205 (funcall unref location))))))
560af5c5 206
207
208(defmethod validate-superclass
c8c48a4c 209 ((class ginstance-class) (super pcl::standard-class))
210 (subtypep (class-name super) 'ginstance))
560af5c5 211
212
d4b21b08 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")
4de90d10 226(register-type 'string "gchararray")
d4b21b08 227
228
229;;;;
230
e77e7713 231(defvar *derivable-type-info* (make-hash-table))
d4b21b08 232
e77e7713 233(defun register-derivable-type (type id expander)
d4b21b08 234 (register-type type id)
e77e7713 235 (let ((type-number (register-type type id)))
236 (setf (gethash type-number *derivable-type-info*) expander)))
d4b21b08 237
4de90d10 238(defun find-type-info (type)
239 (dolist (super (cdr (type-hierarchy type)))
e77e7713 240 (let ((info (gethash super *derivable-type-info*)))
4de90d10 241 (return-if info))))
242
e77e7713 243(defun expand-type-definition (type options)
244 (let ((expander (find-type-info type)))
245 (funcall expander (find-type-number type t) options)))
d4b21b08 246
d4b21b08 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
337933d8 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
d4b21b08 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))
e77e7713 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*)
d4b21b08 304 type-list))
305
306(defun %sort-types-topologicaly (unsorted)
307 (let ((sorted ()))
308 (loop while unsorted do
309 (dolist (type unsorted)
337933d8 310 (let ((dependencies
311 (append (rest (type-hierarchy type)) (type-interfaces type))))
d4b21b08 312 (cond
313 ((null dependencies)
314 (push type sorted)
315 (setq unsorted (delete type unsorted)))
316 (t
317 (unless (dolist (dep dependencies)
e77e7713 318 (when (find type (rest (type-hierarchy dep)))
319 (error "Cyclic type dependencie"))
d4b21b08 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)
e77e7713 327 (flet ((type-options (type-number)
d4b21b08 328 (let ((name (find-type-name type-number)))
4de90d10 329 (cdr (assoc name args :test #'string=)))))
d4b21b08 330
e77e7713 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)
80a09c29 341 (getf (cdr options) :ignore-prefix)
342 (not (some
343 #'(lambda (exception)
344 (string= name exception))
345 (getf (cdr options) :except)))))
e77e7713 346 args))))
347 (find-types prefix))))
d4b21b08 348
e77e7713 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
d4b21b08 361(defmacro define-types-by-introspection (prefix &rest args)
4de90d10 362 (expand-type-definitions prefix args))
e77e7713 363
364
365