chiark / gitweb /
Updated for SBCL 0.8.21
[clg] / glib / glib.lisp
CommitLineData
560af5c5 1;; Common Lisp bindings for GTK+ v1.2.x
2;; Copyright (C) 1999 Espen S. Johnsen <espejohn@online.no>
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
4f805161 18;; $Id: glib.lisp,v 1.28 2005-04-17 21:44:27 espen Exp $
560af5c5 19
20
21(in-package "GLIB")
c4e9d221 22
560af5c5 23(use-prefix "g")
24
25
26;;;; Memory management
27
dba0c446 28(defbinding (allocate-memory "g_malloc0") () pointer
560af5c5 29 (size unsigned-long))
30
dba0c446 31(defbinding (reallocate-memory "g_realloc") () pointer
560af5c5 32 (address pointer)
33 (size unsigned-long))
34
3c657c71 35(defbinding (deallocate-memory "g_free") () nil
36 (address pointer))
9adccb27 37;; (defun deallocate-memory (address)
38;; (declare (ignore address)))
560af5c5 39
40(defun copy-memory (from length &optional (to (allocate-memory length)))
4f805161 41 #+cmu(system-area-copy from 0 to 0 (* 8 length))
42 #+sbcl(system-area-ub8-copy from 0 to 0 length)
560af5c5 43 to)
44
45
c4e9d221 46;;;; User data mechanism
47
48(internal *user-data* *user-data-count*)
49
c4e9d221 50(defvar *user-data* (make-hash-table))
51(defvar *user-data-count* 0)
52
53(defun register-user-data (object &optional destroy-function)
54 (check-type destroy-function (or null symbol function))
55 (incf *user-data-count*)
56 (setf
57 (gethash *user-data-count* *user-data*)
58 (cons object destroy-function))
59 *user-data-count*)
60
61(defun find-user-data (id)
62 (check-type id fixnum)
63 (multiple-value-bind (user-data p) (gethash id *user-data*)
64 (values (car user-data) p)))
65
7e531ed5 66(defun user-data-exists-p (id)
67 (nth-value 1 (find-user-data id)))
68
c9219df2 69(defun update-user-data (id object)
70 (check-type id fixnum)
71 (multiple-value-bind (user-data exists-p) (gethash id *user-data*)
72 (cond
73 ((not exists-p) (error "User data id ~A does not exist" id))
74 (t
75 (when (cdr user-data)
76 (funcall (cdr user-data) (car user-data)))
77 (setf (car user-data) object)))))
78
c4e9d221 79(defun destroy-user-data (id)
80 (check-type id fixnum)
81 (let ((user-data (gethash id *user-data*)))
82 (when (cdr user-data)
83 (funcall (cdr user-data) (car user-data))))
84 (remhash id *user-data*))
85
560af5c5 86
0aef1da8 87;;;; Quarks
88
89(deftype quark () 'unsigned)
90
5cae32e1 91(defbinding %quark-from-string () quark
415444ae 92 (string string))
93
7e531ed5 94(defun quark-intern (object)
95 (etypecase object
96 (quark object)
97 (string (%quark-from-string object))
98 (symbol (%quark-from-string (format nil "clg-~A:~A"
99 (package-name (symbol-package object))
100 object)))))
0aef1da8 101
7e531ed5 102(defbinding quark-to-string () (copy-of string)
103 (quark quark))
0aef1da8 104
105
3846c0b6 106;;;; Linked list (GList)
560af5c5 107
72e5ffec 108(deftype glist (type)
9adccb27 109 `(or (null (cons ,type list))))
560af5c5 110
72e5ffec 111(defbinding (%glist-append "g_list_append") () pointer
3846c0b6 112 (glist pointer)
72e5ffec 113 (nil null))
3846c0b6 114
9adccb27 115(defun make-glist (type list)
72e5ffec 116 (loop
117 with writer = (writer-function type)
118 for element in list
119 as glist = (%glist-append (or glist (make-pointer 0)))
120 do (funcall writer element glist)
121 finally (return glist)))
560af5c5 122
560af5c5 123(defun glist-next (glist)
124 (unless (null-pointer-p glist)
9adccb27 125 (sap-ref-sap glist +size-of-pointer+)))
560af5c5 126
9adccb27 127;; Also used for gslists
128(defun map-glist (seqtype function glist element-type)
129 (let ((reader (reader-function element-type)))
130 (case seqtype
131 ((nil)
132 (loop
133 as tmp = glist then (glist-next tmp)
134 until (null-pointer-p tmp)
135 do (funcall function (funcall reader tmp))))
136 (list
137 (loop
138 as tmp = glist then (glist-next tmp)
139 until (null-pointer-p tmp)
140 collect (funcall function (funcall reader tmp))))
141 (t
142 (coerce
143 (loop
144 as tmp = glist then (glist-next tmp)
145 until (null-pointer-p tmp)
146 collect (funcall function (funcall reader tmp)))
147 seqtype)))))
148
dba0c446 149(defbinding (glist-free "g_list_free") () nil
560af5c5 150 (glist pointer))
151
72e5ffec 152(defun destroy-glist (glist element-type)
153 (loop
154 with destroy = (destroy-function element-type)
155 as tmp = glist then (glist-next tmp)
156 until (null-pointer-p tmp)
157 do (funcall destroy tmp 0))
158 (glist-free glist))
415444ae 159
9adccb27 160(defmethod alien-type ((type (eql 'glist)) &rest args)
161 (declare (ignore type args))
162 (alien-type 'pointer))
163
164(defmethod size-of ((type (eql 'glist)) &rest args)
165 (declare (ignore type args))
415444ae 166 (size-of 'pointer))
560af5c5 167
9adccb27 168(defmethod to-alien-form (list (type (eql 'glist)) &rest args)
169 (declare (ignore type))
170 (destructuring-bind (element-type) args
171 `(make-glist ',element-type ,list)))
172
173(defmethod to-alien-function ((type (eql 'glist)) &rest args)
8755b1a5 174 (declare (ignore type))
9adccb27 175 (destructuring-bind (element-type) args
176 #'(lambda (list)
177 (make-glist element-type list))))
178
179(defmethod from-alien-form (glist (type (eql 'glist)) &rest args)
180 (declare (ignore type))
181 (destructuring-bind (element-type) args
560af5c5 182 `(let ((glist ,glist))
9adccb27 183 (unwind-protect
184 (map-glist 'list #'identity glist ',element-type)
72e5ffec 185 (destroy-glist glist ',element-type)))))
9adccb27 186
187(defmethod from-alien-function ((type (eql 'glist)) &rest args)
188 (declare (ignore type))
189 (destructuring-bind (element-type) args
190 #'(lambda (glist)
191 (unwind-protect
192 (map-glist 'list #'identity glist element-type)
72e5ffec 193 (destroy-glist glist element-type)))))
194
195(defmethod copy-from-alien-form (glist (type (eql 'glist)) &rest args)
196 (declare (ignore type))
197 (destructuring-bind (element-type) args
198 `(map-glist 'list #'identity ,glist ',element-type)))
199
200(defmethod copy-from-alien-function ((type (eql 'glist)) &rest args)
201 (declare (ignore type))
202 (destructuring-bind (element-type) args
203 #'(lambda (glist)
204 (map-glist 'list #'identity glist element-type))))
9adccb27 205
206(defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
72e5ffec 207 (declare (ignore type))
208 (destructuring-bind (element-type) args
209 `(destroy-glist ,glist ',element-type)))
9adccb27 210
211(defmethod cleanup-function ((type (eql 'glist)) &rest args)
e8caa25a 212 (declare (ignore type))
72e5ffec 213 (destructuring-bind (element-type) args
214 #'(lambda (glist)
215 (destroy-glist glist element-type))))
560af5c5 216
e8caa25a 217(defmethod writer-function ((type (eql 'glist)) &rest args)
218 (declare (ignore type))
219 (destructuring-bind (element-type) args
220 #'(lambda (list location &optional (offset 0))
221 (setf
222 (sap-ref-sap location offset)
223 (make-glist element-type list)))))
224
225(defmethod reader-function ((type (eql 'glist)) &rest args)
226 (declare (ignore type))
227 (destructuring-bind (element-type) args
228 #'(lambda (location &optional (offset 0))
229 (unless (null-pointer-p (sap-ref-sap location offset))
230 (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
231
232(defmethod destroy-function ((type (eql 'glist)) &rest args)
233 (declare (ignore type))
234 (destructuring-bind (element-type) args
235 #'(lambda (location &optional (offset 0))
236 (unless (null-pointer-p (sap-ref-sap location offset))
237 (destroy-glist (sap-ref-sap location offset) element-type)
238 (setf (sap-ref-sap location offset) (make-pointer 0))))))
239
240
560af5c5 241
3846c0b6 242;;;; Single linked list (GSList)
243
244(deftype gslist (type) `(or (null (cons ,type list))))
245
72e5ffec 246(defbinding (%gslist-prepend "g_slist_prepend") () pointer
3846c0b6 247 (gslist pointer)
72e5ffec 248 (nil null))
3846c0b6 249
9adccb27 250(defun make-gslist (type list)
72e5ffec 251 (loop
252 with writer = (writer-function type)
253 for element in (reverse list)
254 as gslist = (%gslist-prepend (or gslist (make-pointer 0)))
255 do (funcall writer element gslist)
256 finally (return gslist)))
9adccb27 257
dba0c446 258(defbinding (gslist-free "g_slist_free") () nil
3846c0b6 259 (gslist pointer))
260
72e5ffec 261(defun destroy-gslist (gslist element-type)
262 (loop
263 with destroy = (destroy-function element-type)
264 as tmp = gslist then (glist-next tmp)
265 until (null-pointer-p tmp)
266 do (funcall destroy tmp 0))
267 (gslist-free gslist))
3846c0b6 268
9adccb27 269(defmethod alien-type ((type (eql 'gslist)) &rest args)
270 (declare (ignore type args))
271 (alien-type 'pointer))
272
273(defmethod size-of ((type (eql 'gslist)) &rest args)
274 (declare (ignore type args))
3846c0b6 275 (size-of 'pointer))
276
9adccb27 277(defmethod to-alien-form (list (type (eql 'gslist)) &rest args)
278 (declare (ignore type))
279 (destructuring-bind (element-type) args
280 `(make-sglist ',element-type ,list)))
281
282(defmethod to-alien-function ((type (eql 'gslist)) &rest args)
8755b1a5 283 (declare (ignore type))
9adccb27 284 (destructuring-bind (element-type) args
285 #'(lambda (list)
286 (make-gslist element-type list))))
287
288(defmethod from-alien-form (gslist (type (eql 'gslist)) &rest args)
289 (declare (ignore type))
290 (destructuring-bind (element-type) args
3846c0b6 291 `(let ((gslist ,gslist))
9adccb27 292 (unwind-protect
293 (map-glist 'list #'identity gslist ',element-type)
72e5ffec 294 (destroy-gslist gslist ',element-type)))))
3846c0b6 295
9adccb27 296(defmethod from-alien-function ((type (eql 'gslist)) &rest args)
297 (declare (ignore type))
298 (destructuring-bind (element-type) args
299 #'(lambda (gslist)
300 (unwind-protect
301 (map-glist 'list #'identity gslist element-type)
72e5ffec 302 (destroy-gslist gslist element-type)))))
303
304(defmethod copy-from-alien-form (gslist (type (eql 'gslist)) &rest args)
305 (declare (ignore type))
306 (destructuring-bind (element-type) args
307 `(map-glist 'list #'identity ,gslist ',element-type)))
308
73572c12 309(defmethod copy-from-alien-function ((type (eql 'gslist)) &rest args)
72e5ffec 310 (declare (ignore type))
311 (destructuring-bind (element-type) args
312 #'(lambda (gslist)
313 (map-glist 'list #'identity gslist element-type))))
3846c0b6 314
72e5ffec 315(defmethod cleanup-form (gslist (type (eql 'gslist)) &rest args)
e8caa25a 316 (declare (ignore type))
72e5ffec 317 (destructuring-bind (element-type) args
318 `(destroy-gslist ,gslist ',element-type)))
3846c0b6 319
9adccb27 320(defmethod cleanup-function ((type (eql 'gslist)) &rest args)
e8caa25a 321 (declare (ignore type))
72e5ffec 322 (destructuring-bind (element-type) args
323 #'(lambda (gslist)
324 (destroy-gslist gslist element-type))))
415444ae 325
e8caa25a 326(defmethod writer-function ((type (eql 'gslist)) &rest args)
327 (declare (ignore type))
328 (destructuring-bind (element-type) args
329 #'(lambda (list location &optional (offset 0))
330 (setf
331 (sap-ref-sap location offset)
332 (make-gslist element-type list)))))
333
334(defmethod reader-function ((type (eql 'gslist)) &rest args)
335 (declare (ignore type))
336 (destructuring-bind (element-type) args
337 #'(lambda (location &optional (offset 0))
338 (unless (null-pointer-p (sap-ref-sap location offset))
339 (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
340
341(defmethod destroy-function ((type (eql 'gslist)) &rest args)
342 (declare (ignore type))
343 (destructuring-bind (element-type) args
344 #'(lambda (location &optional (offset 0))
345 (unless (null-pointer-p (sap-ref-sap location offset))
346 (destroy-gslist (sap-ref-sap location offset) element-type)
347 (setf (sap-ref-sap location offset) (make-pointer 0))))))
5cae32e1 348
415444ae 349
9adccb27 350;;; Vector
415444ae 351
9adccb27 352(defun make-c-vector (type length &optional content location)
353 (let* ((size-of-type (size-of type))
354 (location (or location (allocate-memory (* size-of-type length))))
355 (writer (writer-function type)))
814ccf77 356 (etypecase content
357 (vector
358 (loop
359 for element across content
360 for i from 0 below length
361 as offset = 0 then (+ offset size-of-type)
362 do (funcall writer element location offset)))
363 (list
364 (loop
365 for element in content
366 for i from 0 below length
367 as offset = 0 then (+ offset size-of-type)
368 do (funcall writer element location offset))))
9adccb27 369 location))
370
371
372(defun map-c-vector (seqtype function location element-type length)
373 (let ((reader (reader-function element-type))
374 (size-of-element (size-of element-type)))
dba0c446 375 (case seqtype
376 ((nil)
9adccb27 377 (loop
378 for i from 0 below length
379 as offset = 0 then (+ offset size-of-element)
380 do (funcall function (funcall reader location offset))))
dba0c446 381 (list
9adccb27 382 (loop
383 for i from 0 below length
384 as offset = 0 then (+ offset size-of-element)
385 collect (funcall function (funcall reader location offset))))
dba0c446 386 (t
9adccb27 387 (loop
388 with sequence = (make-sequence seqtype length)
389 for i from 0 below length
390 as offset = 0 then (+ offset size-of-element)
391 do (setf
dba0c446 392 (elt sequence i)
9adccb27 393 (funcall function (funcall reader location offset)))
394 finally (return sequence))))))
395
396
72e5ffec 397(defun destroy-c-vector (location element-type length)
398 (loop
399 with destroy = (destroy-function element-type)
400 with element-size = (size-of element-type)
401 for i from 0 below length
402 as offset = 0 then (+ offset element-size)
403 do (funcall destroy location offset))
404 (deallocate-memory location))
405
406
9adccb27 407(defmethod alien-type ((type (eql 'vector)) &rest args)
408 (declare (ignore type args))
409 (alien-type 'pointer))
410
411(defmethod size-of ((type (eql 'vector)) &rest args)
412 (declare (ignore type args))
413 (size-of 'pointer))
414
415(defmethod to-alien-form (vector (type (eql 'vector)) &rest args)
416 (declare (ignore type))
417 (destructuring-bind (element-type &optional (length '*)) args
418 (if (eq length '*)
419 `(let* ((vector ,vector)
420 (location (sap+
421 (allocate-memory (+ ,+size-of-int+
422 (* ,(size-of element-type)
423 (length vector))))
424 ,+size-of-int+)))
425 (make-c-vector ',element-type (length vector) vector location)
426 (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
427 location)
428 `(make-c-vector ',element-type ,length ,vector))))
429
72e5ffec 430(defmethod from-alien-form (c-vector (type (eql 'vector)) &rest args)
431 (declare (ignore type))
432 (destructuring-bind (element-type &optional (length '*)) args
433 (if (eq length '*)
434 (error "Can't use vector of variable size as return type")
435 `(let ((c-vector ,c-vector))
436 (prog1
c9219df2 437 (map-c-vector 'vector #'identity c-vector ',element-type ,length)
72e5ffec 438 (destroy-c-vector c-vector ',element-type ,length))))))
439
440(defmethod copy-from-alien-form (c-vector (type (eql 'vector)) &rest args)
9adccb27 441 (declare (ignore type))
442 (destructuring-bind (element-type &optional (length '*)) args
443 (if (eq length '*)
444 (error "Can't use vector of variable size as return type")
c9219df2 445 `(map-c-vector 'vector #'identity ,c-vector ',element-type ',length))))
9adccb27 446
447(defmethod cleanup-form (location (type (eql 'vector)) &rest args)
448 (declare (ignore type))
449 (destructuring-bind (element-type &optional (length '*)) args
450 `(let* ((location ,location)
451 (length ,(if (eq length '*)
452 `(sap-ref-32 location ,(- +size-of-int+))
453 length)))
454 (loop
455 with destroy = (destroy-function ',element-type)
456 for i from 0 below length
457 as offset = 0 then (+ offset ,(size-of element-type))
458 do (funcall destroy location offset))
459 (deallocate-memory ,(if (eq length '*)
460 `(sap+ location ,(- +size-of-int+))
461 'location)))))
16bf1149 462
463(defmethod writer-function ((type (eql 'vector)) &rest args)
464 (declare (ignore type))
465 (destructuring-bind (element-type &optional (length '*)) args
466 #'(lambda (vector location &optional (offset 0))
467 (setf
468 (sap-ref-sap location offset)
469 (make-c-vector element-type length vector)))))
470
471(defmethod reader-function ((type (eql 'vector)) &rest args)
472 (declare (ignore type))
473 (destructuring-bind (element-type &optional (length '*)) args
474 (if (eq length '*)
475 (error "Can't create reader function for vector of variable size")
476 #'(lambda (location &optional (offset 0))
477 (unless (null-pointer-p (sap-ref-sap location offset))
478 (map-c-vector 'vector #'identity (sap-ref-sap location offset)
479 element-type length))))))
480
481(defmethod destroy-function ((type (eql 'vector)) &rest args)
482 (declare (ignore type))
483 (destructuring-bind (element-type &optional (length '*)) args
484 (if (eq length '*)
485 (error "Can't create destroy function for vector of variable size")
486 #'(lambda (location &optional (offset 0))
487 (unless (null-pointer-p (sap-ref-sap location offset))
488 (destroy-c-vector
489 (sap-ref-sap location offset) element-type length)
490 (setf (sap-ref-sap location offset) (make-pointer 0)))))))
463fe62f 491
492
493;;;; Null terminated vector
494
495(defun make-0-vector (type content &optional location)
496 (let* ((size-of-type (size-of type))
497 (location (or
498 location
499 (allocate-memory (* size-of-type (1+ (length content))))))
500 (writer (writer-function type)))
501 (etypecase content
502 (vector
503 (loop
504 for element across content
505 as offset = 0 then (+ offset size-of-type)
506 do (funcall writer element location offset)
507 finally (setf (sap-ref-sap location offset) (make-pointer 0))))
508 (list
509 (loop
510 for element in content
511 as offset = 0 then (+ offset size-of-type)
512 do (funcall writer element location offset)
513 finally (setf (sap-ref-sap location (+ offset size-of-type)) (make-pointer 0)))))
514 location))
515
516
517(defun map-0-vector (seqtype function location element-type)
518 (let ((reader (reader-function element-type))
519 (size-of-element (size-of element-type)))
520 (case seqtype
521 ((nil)
522 (loop
523 as offset = 0 then (+ offset size-of-element)
524 until (null-pointer-p (sap-ref-sap location offset))
525 do (funcall function (funcall reader location offset))))
526 (list
527 (loop
528 as offset = 0 then (+ offset size-of-element)
529 until (null-pointer-p (sap-ref-sap location offset))
530 collect (funcall function (funcall reader location offset))))
531 (t
532 (coerce
533 (loop
534 as offset = 0 then (+ offset size-of-element)
535 until (null-pointer-p (sap-ref-sap location offset))
536 collect (funcall function (funcall reader location offset)))
537 seqtype)))))
538
539
540(defun destroy-0-vector (location element-type)
541 (loop
542 with destroy = (destroy-function element-type)
543 with element-size = (size-of element-type)
544 as offset = 0 then (+ offset element-size)
545 until (null-pointer-p (sap-ref-sap location offset))
546 do (funcall destroy location offset))
547 (deallocate-memory location))
548
549
545712f4 550(defmethod alien-type ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 551 (declare (ignore type args))
552 (alien-type 'pointer))
553
545712f4 554(defmethod size-of ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 555 (declare (ignore type args))
556 (alien-type 'pointer))
557
545712f4 558(defmethod writer-function ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 559 (declare (ignore type))
545712f4 560 (destructuring-bind (element-type) args
463fe62f 561 (unless (eq (alien-type element-type) (alien-type 'pointer))
562 (error "Elements in null-terminated vectors need to be of pointer types"))
563 #'(lambda (vector location &optional (offset 0))
564 (setf
565 (sap-ref-sap location offset)
566 (make-0-vector element-type vector)))))
567
545712f4 568(defmethod reader-function ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 569 (declare (ignore type))
545712f4 570 (destructuring-bind (element-type) args
463fe62f 571 (unless (eq (alien-type element-type) (alien-type 'pointer))
572 (error "Elements in null-terminated vectors need to be of pointer types"))
573 #'(lambda (location &optional (offset 0))
574 (unless (null-pointer-p (sap-ref-sap location offset))
575 (map-0-vector 'vector #'identity (sap-ref-sap location offset)
576 element-type)))))
577
545712f4 578(defmethod destroy-function ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 579 (declare (ignore type))
545712f4 580 (destructuring-bind (element-type) args
463fe62f 581 (unless (eq (alien-type element-type) (alien-type 'pointer))
582 (error "Elements in null-terminated vectors need to be of pointer types"))
583 #'(lambda (location &optional (offset 0))
584 (unless (null-pointer-p (sap-ref-sap location offset))
545712f4 585 (destroy-0-vector
463fe62f 586 (sap-ref-sap location offset) element-type)
587 (setf (sap-ref-sap location offset) (make-pointer 0))))))
588
545712f4 589(defmethod unbound-value ((type (eql 'null-terminated-vector)) &rest args)
590 (declare (ignore type args))
463fe62f 591 (values t nil))