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