Bug fix
[clg] / glib / glib.lisp
CommitLineData
0d07716f 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
3e033db9 18;; $Id: glib.lisp,v 1.24 2005/01/30 14:26:41 espen Exp $
0d07716f 19
20
21(in-package "GLIB")
b467f3d0 22
0d07716f 23(use-prefix "g")
24
25
26;;;; Memory management
27
1c99696e 28(defbinding (allocate-memory "g_malloc0") () pointer
0d07716f 29 (size unsigned-long))
30
1c99696e 31(defbinding (reallocate-memory "g_realloc") () pointer
0d07716f 32 (address pointer)
33 (size unsigned-long))
34
3fa4f6bd 35(defbinding (deallocate-memory "g_free") () nil
36 (address pointer))
6baf860c 37;; (defun deallocate-memory (address)
38;; (declare (ignore address)))
0d07716f 39
40(defun copy-memory (from length &optional (to (allocate-memory length)))
41 (kernel:system-area-copy from 0 to 0 (* 8 length))
42 to)
43
44
b467f3d0 45;;;; User data mechanism
46
47(internal *user-data* *user-data-count*)
48
b467f3d0 49(defvar *user-data* (make-hash-table))
50(defvar *user-data-count* 0)
51
52(defun register-user-data (object &optional destroy-function)
53 (check-type destroy-function (or null symbol function))
54 (incf *user-data-count*)
55 (setf
56 (gethash *user-data-count* *user-data*)
57 (cons object destroy-function))
58 *user-data-count*)
59
60(defun find-user-data (id)
61 (check-type id fixnum)
62 (multiple-value-bind (user-data p) (gethash id *user-data*)
63 (values (car user-data) p)))
64
3e033db9 65(defun user-data-exists-p (id)
66 (nth-value 1 (find-user-data id)))
67
29c05201 68(defun update-user-data (id object)
69 (check-type id fixnum)
70 (multiple-value-bind (user-data exists-p) (gethash id *user-data*)
71 (cond
72 ((not exists-p) (error "User data id ~A does not exist" id))
73 (t
74 (when (cdr user-data)
75 (funcall (cdr user-data) (car user-data)))
76 (setf (car user-data) object)))))
77
b467f3d0 78(defun destroy-user-data (id)
79 (check-type id fixnum)
80 (let ((user-data (gethash id *user-data*)))
81 (when (cdr user-data)
82 (funcall (cdr user-data) (car user-data))))
83 (remhash id *user-data*))
84
0d07716f 85
6755fdad 86;;;; Quarks
87
88(deftype quark () 'unsigned)
89
cb816364 90(defbinding %quark-from-string () quark
e5b6173a 91 (string string))
92
3e033db9 93(defun quark-intern (object)
94 (etypecase object
95 (quark object)
96 (string (%quark-from-string object))
97 (symbol (%quark-from-string (format nil "clg-~A:~A"
98 (package-name (symbol-package object))
99 object)))))
6755fdad 100
3e033db9 101(defbinding quark-to-string () (copy-of string)
102 (quark quark))
6755fdad 103
104
597999f9 105;;;; Linked list (GList)
0d07716f 106
5f2222a9 107(deftype glist (type)
6baf860c 108 `(or (null (cons ,type list))))
0d07716f 109
5f2222a9 110(defbinding (%glist-append "g_list_append") () pointer
597999f9 111 (glist pointer)
5f2222a9 112 (nil null))
597999f9 113
6baf860c 114(defun make-glist (type list)
5f2222a9 115 (loop
116 with writer = (writer-function type)
117 for element in list
118 as glist = (%glist-append (or glist (make-pointer 0)))
119 do (funcall writer element glist)
120 finally (return glist)))
0d07716f 121
0d07716f 122(defun glist-next (glist)
123 (unless (null-pointer-p glist)
6baf860c 124 (sap-ref-sap glist +size-of-pointer+)))
0d07716f 125
6baf860c 126;; Also used for gslists
127(defun map-glist (seqtype function glist element-type)
128 (let ((reader (reader-function element-type)))
129 (case seqtype
130 ((nil)
131 (loop
132 as tmp = glist then (glist-next tmp)
133 until (null-pointer-p tmp)
134 do (funcall function (funcall reader tmp))))
135 (list
136 (loop
137 as tmp = glist then (glist-next tmp)
138 until (null-pointer-p tmp)
139 collect (funcall function (funcall reader tmp))))
140 (t
141 (coerce
142 (loop
143 as tmp = glist then (glist-next tmp)
144 until (null-pointer-p tmp)
145 collect (funcall function (funcall reader tmp)))
146 seqtype)))))
147
1c99696e 148(defbinding (glist-free "g_list_free") () nil
0d07716f 149 (glist pointer))
150
5f2222a9 151(defun destroy-glist (glist element-type)
152 (loop
153 with destroy = (destroy-function element-type)
154 as tmp = glist then (glist-next tmp)
155 until (null-pointer-p tmp)
156 do (funcall destroy tmp 0))
157 (glist-free glist))
e5b6173a 158
6baf860c 159(defmethod alien-type ((type (eql 'glist)) &rest args)
160 (declare (ignore type args))
161 (alien-type 'pointer))
162
163(defmethod size-of ((type (eql 'glist)) &rest args)
164 (declare (ignore type args))
e5b6173a 165 (size-of 'pointer))
0d07716f 166
6baf860c 167(defmethod to-alien-form (list (type (eql 'glist)) &rest args)
168 (declare (ignore type))
169 (destructuring-bind (element-type) args
170 `(make-glist ',element-type ,list)))
171
172(defmethod to-alien-function ((type (eql 'glist)) &rest args)
7bde5a67 173 (declare (ignore type))
6baf860c 174 (destructuring-bind (element-type) args
175 #'(lambda (list)
176 (make-glist element-type list))))
177
178(defmethod from-alien-form (glist (type (eql 'glist)) &rest args)
179 (declare (ignore type))
180 (destructuring-bind (element-type) args
0d07716f 181 `(let ((glist ,glist))
6baf860c 182 (unwind-protect
183 (map-glist 'list #'identity glist ',element-type)
5f2222a9 184 (destroy-glist glist ',element-type)))))
6baf860c 185
186(defmethod from-alien-function ((type (eql 'glist)) &rest args)
187 (declare (ignore type))
188 (destructuring-bind (element-type) args
189 #'(lambda (glist)
190 (unwind-protect
191 (map-glist 'list #'identity glist element-type)
5f2222a9 192 (destroy-glist glist element-type)))))
193
194(defmethod copy-from-alien-form (glist (type (eql 'glist)) &rest args)
195 (declare (ignore type))
196 (destructuring-bind (element-type) args
197 `(map-glist 'list #'identity ,glist ',element-type)))
198
199(defmethod copy-from-alien-function ((type (eql 'glist)) &rest args)
200 (declare (ignore type))
201 (destructuring-bind (element-type) args
202 #'(lambda (glist)
203 (map-glist 'list #'identity glist element-type))))
6baf860c 204
205(defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
5f2222a9 206 (declare (ignore type))
207 (destructuring-bind (element-type) args
208 `(destroy-glist ,glist ',element-type)))
6baf860c 209
210(defmethod cleanup-function ((type (eql 'glist)) &rest args)
02b6647e 211 (declare (ignore type))
5f2222a9 212 (destructuring-bind (element-type) args
213 #'(lambda (glist)
214 (destroy-glist glist element-type))))
0d07716f 215
02b6647e 216(defmethod writer-function ((type (eql 'glist)) &rest args)
217 (declare (ignore type))
218 (destructuring-bind (element-type) args
219 #'(lambda (list location &optional (offset 0))
220 (setf
221 (sap-ref-sap location offset)
222 (make-glist element-type list)))))
223
224(defmethod reader-function ((type (eql 'glist)) &rest args)
225 (declare (ignore type))
226 (destructuring-bind (element-type) args
227 #'(lambda (location &optional (offset 0))
228 (unless (null-pointer-p (sap-ref-sap location offset))
229 (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
230
231(defmethod destroy-function ((type (eql 'glist)) &rest args)
232 (declare (ignore type))
233 (destructuring-bind (element-type) args
234 #'(lambda (location &optional (offset 0))
235 (unless (null-pointer-p (sap-ref-sap location offset))
236 (destroy-glist (sap-ref-sap location offset) element-type)
237 (setf (sap-ref-sap location offset) (make-pointer 0))))))
238
239
0d07716f 240
597999f9 241;;;; Single linked list (GSList)
242
243(deftype gslist (type) `(or (null (cons ,type list))))
244
5f2222a9 245(defbinding (%gslist-prepend "g_slist_prepend") () pointer
597999f9 246 (gslist pointer)
5f2222a9 247 (nil null))
597999f9 248
6baf860c 249(defun make-gslist (type list)
5f2222a9 250 (loop
251 with writer = (writer-function type)
252 for element in (reverse list)
253 as gslist = (%gslist-prepend (or gslist (make-pointer 0)))
254 do (funcall writer element gslist)
255 finally (return gslist)))
6baf860c 256
1c99696e 257(defbinding (gslist-free "g_slist_free") () nil
597999f9 258 (gslist pointer))
259
5f2222a9 260(defun destroy-gslist (gslist element-type)
261 (loop
262 with destroy = (destroy-function element-type)
263 as tmp = gslist then (glist-next tmp)
264 until (null-pointer-p tmp)
265 do (funcall destroy tmp 0))
266 (gslist-free gslist))
597999f9 267
6baf860c 268(defmethod alien-type ((type (eql 'gslist)) &rest args)
269 (declare (ignore type args))
270 (alien-type 'pointer))
271
272(defmethod size-of ((type (eql 'gslist)) &rest args)
273 (declare (ignore type args))
597999f9 274 (size-of 'pointer))
275
6baf860c 276(defmethod to-alien-form (list (type (eql 'gslist)) &rest args)
277 (declare (ignore type))
278 (destructuring-bind (element-type) args
279 `(make-sglist ',element-type ,list)))
280
281(defmethod to-alien-function ((type (eql 'gslist)) &rest args)
7bde5a67 282 (declare (ignore type))
6baf860c 283 (destructuring-bind (element-type) args
284 #'(lambda (list)
285 (make-gslist element-type list))))
286
287(defmethod from-alien-form (gslist (type (eql 'gslist)) &rest args)
288 (declare (ignore type))
289 (destructuring-bind (element-type) args
597999f9 290 `(let ((gslist ,gslist))
6baf860c 291 (unwind-protect
292 (map-glist 'list #'identity gslist ',element-type)
5f2222a9 293 (destroy-gslist gslist ',element-type)))))
597999f9 294
6baf860c 295(defmethod from-alien-function ((type (eql 'gslist)) &rest args)
296 (declare (ignore type))
297 (destructuring-bind (element-type) args
298 #'(lambda (gslist)
299 (unwind-protect
300 (map-glist 'list #'identity gslist element-type)
5f2222a9 301 (destroy-gslist gslist element-type)))))
302
303(defmethod copy-from-alien-form (gslist (type (eql 'gslist)) &rest args)
304 (declare (ignore type))
305 (destructuring-bind (element-type) args
306 `(map-glist 'list #'identity ,gslist ',element-type)))
307
308(defmethod from-alien-function ((type (eql 'gslist)) &rest args)
309 (declare (ignore type))
310 (destructuring-bind (element-type) args
311 #'(lambda (gslist)
312 (map-glist 'list #'identity gslist element-type))))
597999f9 313
5f2222a9 314(defmethod cleanup-form (gslist (type (eql 'gslist)) &rest args)
02b6647e 315 (declare (ignore type))
5f2222a9 316 (destructuring-bind (element-type) args
317 `(destroy-gslist ,gslist ',element-type)))
597999f9 318
6baf860c 319(defmethod cleanup-function ((type (eql 'gslist)) &rest args)
02b6647e 320 (declare (ignore type))
5f2222a9 321 (destructuring-bind (element-type) args
322 #'(lambda (gslist)
323 (destroy-gslist gslist element-type))))
e5b6173a 324
02b6647e 325(defmethod writer-function ((type (eql 'gslist)) &rest args)
326 (declare (ignore type))
327 (destructuring-bind (element-type) args
328 #'(lambda (list location &optional (offset 0))
329 (setf
330 (sap-ref-sap location offset)
331 (make-gslist element-type list)))))
332
333(defmethod reader-function ((type (eql 'gslist)) &rest args)
334 (declare (ignore type))
335 (destructuring-bind (element-type) args
336 #'(lambda (location &optional (offset 0))
337 (unless (null-pointer-p (sap-ref-sap location offset))
338 (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
339
340(defmethod destroy-function ((type (eql 'gslist)) &rest args)
341 (declare (ignore type))
342 (destructuring-bind (element-type) args
343 #'(lambda (location &optional (offset 0))
344 (unless (null-pointer-p (sap-ref-sap location offset))
345 (destroy-gslist (sap-ref-sap location offset) element-type)
346 (setf (sap-ref-sap location offset) (make-pointer 0))))))
cb816364 347
e5b6173a 348
6baf860c 349;;; Vector
e5b6173a 350
6baf860c 351(defun make-c-vector (type length &optional content location)
352 (let* ((size-of-type (size-of type))
353 (location (or location (allocate-memory (* size-of-type length))))
354 (writer (writer-function type)))
e5a69a73 355 (etypecase content
356 (vector
357 (loop
358 for element across content
359 for i from 0 below length
360 as offset = 0 then (+ offset size-of-type)
361 do (funcall writer element location offset)))
362 (list
363 (loop
364 for element in content
365 for i from 0 below length
366 as offset = 0 then (+ offset size-of-type)
367 do (funcall writer element location offset))))
6baf860c 368 location))
369
370
371(defun map-c-vector (seqtype function location element-type length)
372 (let ((reader (reader-function element-type))
373 (size-of-element (size-of element-type)))
1c99696e 374 (case seqtype
375 ((nil)
6baf860c 376 (loop
377 for i from 0 below length
378 as offset = 0 then (+ offset size-of-element)
379 do (funcall function (funcall reader location offset))))
1c99696e 380 (list
6baf860c 381 (loop
382 for i from 0 below length
383 as offset = 0 then (+ offset size-of-element)
384 collect (funcall function (funcall reader location offset))))
1c99696e 385 (t
6baf860c 386 (loop
387 with sequence = (make-sequence seqtype length)
388 for i from 0 below length
389 as offset = 0 then (+ offset size-of-element)
390 do (setf
1c99696e 391 (elt sequence i)
6baf860c 392 (funcall function (funcall reader location offset)))
393 finally (return sequence))))))
394
395
5f2222a9 396(defun destroy-c-vector (location element-type length)
397 (loop
398 with destroy = (destroy-function element-type)
399 with element-size = (size-of element-type)
400 for i from 0 below length
401 as offset = 0 then (+ offset element-size)
402 do (funcall destroy location offset))
403 (deallocate-memory location))
404
405
6baf860c 406(defmethod alien-type ((type (eql 'vector)) &rest args)
407 (declare (ignore type args))
408 (alien-type 'pointer))
409
410(defmethod size-of ((type (eql 'vector)) &rest args)
411 (declare (ignore type args))
412 (size-of 'pointer))
413
414(defmethod to-alien-form (vector (type (eql 'vector)) &rest args)
415 (declare (ignore type))
416 (destructuring-bind (element-type &optional (length '*)) args
417 (if (eq length '*)
418 `(let* ((vector ,vector)
419 (location (sap+
420 (allocate-memory (+ ,+size-of-int+
421 (* ,(size-of element-type)
422 (length vector))))
423 ,+size-of-int+)))
424 (make-c-vector ',element-type (length vector) vector location)
425 (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
426 location)
427 `(make-c-vector ',element-type ,length ,vector))))
428
5f2222a9 429(defmethod from-alien-form (c-vector (type (eql 'vector)) &rest args)
430 (declare (ignore type))
431 (destructuring-bind (element-type &optional (length '*)) args
432 (if (eq length '*)
433 (error "Can't use vector of variable size as return type")
434 `(let ((c-vector ,c-vector))
435 (prog1
29c05201 436 (map-c-vector 'vector #'identity c-vector ',element-type ,length)
5f2222a9 437 (destroy-c-vector c-vector ',element-type ,length))))))
438
439(defmethod copy-from-alien-form (c-vector (type (eql 'vector)) &rest args)
6baf860c 440 (declare (ignore type))
441 (destructuring-bind (element-type &optional (length '*)) args
442 (if (eq length '*)
443 (error "Can't use vector of variable size as return type")
29c05201 444 `(map-c-vector 'vector #'identity ,c-vector ',element-type ',length))))
6baf860c 445
446(defmethod cleanup-form (location (type (eql 'vector)) &rest args)
447 (declare (ignore type))
448 (destructuring-bind (element-type &optional (length '*)) args
449 `(let* ((location ,location)
450 (length ,(if (eq length '*)
451 `(sap-ref-32 location ,(- +size-of-int+))
452 length)))
453 (loop
454 with destroy = (destroy-function ',element-type)
455 for i from 0 below length
456 as offset = 0 then (+ offset ,(size-of element-type))
457 do (funcall destroy location offset))
458 (deallocate-memory ,(if (eq length '*)
459 `(sap+ location ,(- +size-of-int+))
460 'location)))))
318deb1b 461
462(defmethod writer-function ((type (eql 'vector)) &rest args)
463 (declare (ignore type))
464 (destructuring-bind (element-type &optional (length '*)) args
465 #'(lambda (vector location &optional (offset 0))
466 (setf
467 (sap-ref-sap location offset)
468 (make-c-vector element-type length vector)))))
469
470(defmethod reader-function ((type (eql 'vector)) &rest args)
471 (declare (ignore type))
472 (destructuring-bind (element-type &optional (length '*)) args
473 (if (eq length '*)
474 (error "Can't create reader function for vector of variable size")
475 #'(lambda (location &optional (offset 0))
476 (unless (null-pointer-p (sap-ref-sap location offset))
477 (map-c-vector 'vector #'identity (sap-ref-sap location offset)
478 element-type length))))))
479
480(defmethod destroy-function ((type (eql 'vector)) &rest args)
481 (declare (ignore type))
482 (destructuring-bind (element-type &optional (length '*)) args
483 (if (eq length '*)
484 (error "Can't create destroy function for vector of variable size")
485 #'(lambda (location &optional (offset 0))
486 (unless (null-pointer-p (sap-ref-sap location offset))
487 (destroy-c-vector
488 (sap-ref-sap location offset) element-type length)
489 (setf (sap-ref-sap location offset) (make-pointer 0)))))))