chiark / gitweb /
Bug fix
[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
7e531ed5 18;; $Id: glib.lisp,v 1.24 2005-01-30 14:26:41 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)))
41 (kernel:system-area-copy from 0 to 0 (* 8 length))
42 to)
43
44
c4e9d221 45;;;; User data mechanism
46
47(internal *user-data* *user-data-count*)
48
c4e9d221 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
7e531ed5 65(defun user-data-exists-p (id)
66 (nth-value 1 (find-user-data id)))
67
c9219df2 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
c4e9d221 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
560af5c5 85
0aef1da8 86;;;; Quarks
87
88(deftype quark () 'unsigned)
89
5cae32e1 90(defbinding %quark-from-string () quark
415444ae 91 (string string))
92
7e531ed5 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)))))
0aef1da8 100
7e531ed5 101(defbinding quark-to-string () (copy-of string)
102 (quark quark))
0aef1da8 103
104
3846c0b6 105;;;; Linked list (GList)
560af5c5 106
72e5ffec 107(deftype glist (type)
9adccb27 108 `(or (null (cons ,type list))))
560af5c5 109
72e5ffec 110(defbinding (%glist-append "g_list_append") () pointer
3846c0b6 111 (glist pointer)
72e5ffec 112 (nil null))
3846c0b6 113
9adccb27 114(defun make-glist (type list)
72e5ffec 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)))
560af5c5 121
560af5c5 122(defun glist-next (glist)
123 (unless (null-pointer-p glist)
9adccb27 124 (sap-ref-sap glist +size-of-pointer+)))
560af5c5 125
9adccb27 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
dba0c446 148(defbinding (glist-free "g_list_free") () nil
560af5c5 149 (glist pointer))
150
72e5ffec 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))
415444ae 158
9adccb27 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))
415444ae 165 (size-of 'pointer))
560af5c5 166
9adccb27 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)
8755b1a5 173 (declare (ignore type))
9adccb27 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
560af5c5 181 `(let ((glist ,glist))
9adccb27 182 (unwind-protect
183 (map-glist 'list #'identity glist ',element-type)
72e5ffec 184 (destroy-glist glist ',element-type)))))
9adccb27 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)
72e5ffec 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))))
9adccb27 204
205(defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
72e5ffec 206 (declare (ignore type))
207 (destructuring-bind (element-type) args
208 `(destroy-glist ,glist ',element-type)))
9adccb27 209
210(defmethod cleanup-function ((type (eql 'glist)) &rest args)
e8caa25a 211 (declare (ignore type))
72e5ffec 212 (destructuring-bind (element-type) args
213 #'(lambda (glist)
214 (destroy-glist glist element-type))))
560af5c5 215
e8caa25a 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
560af5c5 240
3846c0b6 241;;;; Single linked list (GSList)
242
243(deftype gslist (type) `(or (null (cons ,type list))))
244
72e5ffec 245(defbinding (%gslist-prepend "g_slist_prepend") () pointer
3846c0b6 246 (gslist pointer)
72e5ffec 247 (nil null))
3846c0b6 248
9adccb27 249(defun make-gslist (type list)
72e5ffec 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)))
9adccb27 256
dba0c446 257(defbinding (gslist-free "g_slist_free") () nil
3846c0b6 258 (gslist pointer))
259
72e5ffec 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))
3846c0b6 267
9adccb27 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))
3846c0b6 274 (size-of 'pointer))
275
9adccb27 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)
8755b1a5 282 (declare (ignore type))
9adccb27 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
3846c0b6 290 `(let ((gslist ,gslist))
9adccb27 291 (unwind-protect
292 (map-glist 'list #'identity gslist ',element-type)
72e5ffec 293 (destroy-gslist gslist ',element-type)))))
3846c0b6 294
9adccb27 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)
72e5ffec 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))))
3846c0b6 313
72e5ffec 314(defmethod cleanup-form (gslist (type (eql 'gslist)) &rest args)
e8caa25a 315 (declare (ignore type))
72e5ffec 316 (destructuring-bind (element-type) args
317 `(destroy-gslist ,gslist ',element-type)))
3846c0b6 318
9adccb27 319(defmethod cleanup-function ((type (eql 'gslist)) &rest args)
e8caa25a 320 (declare (ignore type))
72e5ffec 321 (destructuring-bind (element-type) args
322 #'(lambda (gslist)
323 (destroy-gslist gslist element-type))))
415444ae 324
e8caa25a 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))))))
5cae32e1 347
415444ae 348
9adccb27 349;;; Vector
415444ae 350
9adccb27 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)))
814ccf77 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))))
9adccb27 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)))
dba0c446 374 (case seqtype
375 ((nil)
9adccb27 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))))
dba0c446 380 (list
9adccb27 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))))
dba0c446 385 (t
9adccb27 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
dba0c446 391 (elt sequence i)
9adccb27 392 (funcall function (funcall reader location offset)))
393 finally (return sequence))))))
394
395
72e5ffec 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
9adccb27 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
72e5ffec 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
c9219df2 436 (map-c-vector 'vector #'identity c-vector ',element-type ,length)
72e5ffec 437 (destroy-c-vector c-vector ',element-type ,length))))))
438
439(defmethod copy-from-alien-form (c-vector (type (eql 'vector)) &rest args)
9adccb27 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")
c9219df2 444 `(map-c-vector 'vector #'identity ,c-vector ',element-type ',length))))
9adccb27 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)))))
16bf1149 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)))))))