1 ;; Common Lisp bindings for GTK+ v1.2.x
2 ;; Copyright (C) 1999 Espen S. Johnsen <espejohn@online.no>
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.
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.
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
18 ;; $Id: glib.lisp,v 1.17 2004-11-07 01:23:38 espen Exp $
26 ;;;; Memory management
28 (defbinding (allocate-memory "g_malloc0") () pointer
31 (defbinding (reallocate-memory "g_realloc") () pointer
35 (defbinding (deallocate-memory "g_free") () nil
37 ;; (defun deallocate-memory (address)
38 ;; (declare (ignore address)))
40 (defun copy-memory (from length &optional (to (allocate-memory length)))
41 (kernel:system-area-copy from 0 to 0 (* 8 length))
45 ;;;; User data mechanism
47 (internal *user-data* *user-data-count*)
49 (declaim (fixnum *user-data-count*))
51 (defvar *user-data* (make-hash-table))
52 (defvar *user-data-count* 0)
54 (defun register-user-data (object &optional destroy-function)
55 (check-type destroy-function (or null symbol function))
56 (incf *user-data-count*)
58 (gethash *user-data-count* *user-data*)
59 (cons object destroy-function))
62 (defun find-user-data (id)
63 (check-type id fixnum)
64 (multiple-value-bind (user-data p) (gethash id *user-data*)
65 (values (car user-data) p)))
67 (defun destroy-user-data (id)
68 (check-type id fixnum)
69 (let ((user-data (gethash id *user-data*)))
71 (funcall (cdr user-data) (car user-data))))
72 (remhash id *user-data*))
74 (defmacro def-callback-marshal (name (return-type &rest args))
77 collect (if (atom arg) (gensym) (first arg))))
80 collect (if (atom arg) arg (second arg)))))
81 `(defcallback ,name (,return-type ,@(mapcar #'list names types)
82 (callback-id unsigned-int))
83 (invoke-callback callback-id ',return-type ,@names))))
88 (internal *quark-counter* *quark-from-object* *quark-to-object*)
90 (deftype quark () 'unsigned)
92 ;(defbinding %quark-get-reserved () quark)
94 (defbinding %quark-from-string () quark
97 (defvar *quark-counter* 0)
99 (defun %quark-get-reserved ()
100 ;; The string is just a dummy
101 (%quark-from-string (format nil "#@£$%&-quark-~D" (incf *quark-counter*))))
103 (defvar *quark-from-object* (make-hash-table))
104 (defvar *quark-to-object* (make-hash-table))
106 (defun quark-from-object (object &key (test #'eq))
107 (let ((hash-code (sxhash object)))
109 (assoc-ref object (gethash hash-code *quark-from-object*) :test test)
110 (let ((quark (%quark-get-reserved)))
112 (gethash hash-code *quark-from-object*)
114 (gethash hash-code *quark-from-object*)
115 (list (cons object quark))))
116 (setf (gethash quark *quark-to-object*) object)
119 (defun quark-to-object (quark)
120 (gethash quark *quark-to-object*))
122 (defun remove-quark (quark)
123 (let* ((object (gethash quark *quark-to-object*))
124 (hash-code (sxhash object)))
125 (remhash quark *quark-to-object*)
127 (gethash hash-code *quark-from-object*)
128 (assoc-delete object (gethash hash-code *quark-from-object*)))
129 (remhash hash-code *quark-from-object*))))
133 ;;;; Linked list (GList)
135 (deftype glist (type &key copy)
136 (declare (ignore copy))
137 `(or (null (cons ,type list))))
139 (defbinding (%glist-append-unsigned "g_list_append") () pointer
143 (defbinding (%glist-append-signed "g_list_append") () pointer
147 (defbinding (%glist-append-sap "g_list_append") () pointer
151 (defun make-glist (type list)
152 (let ((new-element (ecase (alien-type type)
153 (system-area-pointer #'%glist-append-sap)
154 ((signed-byte c-call:short c-call:int c-call:long)
155 #'%glist-append-signed)
156 ((unsigned-byte c-call:unsigned-short
157 c-call:unsigned-int c-call:unsigned-long)
158 #'%glist-append-unsigned)))
159 (to-alien (to-alien-function type)))
162 as glist = (funcall new-element (or glist (make-pointer 0))
163 (funcall to-alien element))
164 finally (return glist))))
166 (defun glist-next (glist)
167 (unless (null-pointer-p glist)
168 (sap-ref-sap glist +size-of-pointer+)))
170 ;; Also used for gslists
171 (defun map-glist (seqtype function glist element-type)
172 (let ((reader (reader-function element-type)))
176 as tmp = glist then (glist-next tmp)
177 until (null-pointer-p tmp)
178 do (funcall function (funcall reader tmp))))
181 as tmp = glist then (glist-next tmp)
182 until (null-pointer-p tmp)
183 collect (funcall function (funcall reader tmp))))
187 as tmp = glist then (glist-next tmp)
188 until (null-pointer-p tmp)
189 collect (funcall function (funcall reader tmp)))
192 (defbinding (glist-free "g_list_free") () nil
196 (defmethod alien-type ((type (eql 'glist)) &rest args)
197 (declare (ignore type args))
198 (alien-type 'pointer))
200 (defmethod size-of ((type (eql 'glist)) &rest args)
201 (declare (ignore type args))
204 (defmethod to-alien-form (list (type (eql 'glist)) &rest args)
205 (declare (ignore type))
206 (destructuring-bind (element-type) args
207 `(make-glist ',element-type ,list)))
209 (defmethod to-alien-function ((type (eql 'glist)) &rest args)
210 (declare (ignore type))
211 (destructuring-bind (element-type) args
213 (make-glist element-type list))))
215 (defmethod from-alien-form (glist (type (eql 'glist)) &rest args)
216 (declare (ignore type))
217 (destructuring-bind (element-type) args
218 `(let ((glist ,glist))
220 (map-glist 'list #'identity glist ',element-type)
221 (glist-free glist)))))
223 (defmethod from-alien-function ((type (eql 'glist)) &rest args)
224 (declare (ignore type))
225 (destructuring-bind (element-type) args
228 (map-glist 'list #'identity glist element-type)
229 (glist-free glist)))))
231 (defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
232 (declare (ignore type args))
233 `(glist-free ,glist))
235 (defmethod cleanup-function ((type (eql 'glist)) &rest args)
236 (declare (ignore type args))
241 ;;;; Single linked list (GSList)
243 (deftype gslist (type) `(or (null (cons ,type list))))
245 (defbinding (%gslist-prepend-unsigned "g_slist_prepend") () pointer
249 (defbinding (%gslist-prepend-signed "g_slist_prepend") () pointer
253 (defbinding (%gslist-prepend-sap "g_slist_prepend") () pointer
257 (defun make-gslist (type list)
258 (let ((new-element (ecase (alien-type type)
259 (system-area-pointer #'%gslist-prepend-sap)
260 ((signed-byte c-call:short c-call:int c-call:long)
261 #'%gslist-prepend-signed)
262 ((unsigned-byte c-call:unsigned-short
263 c-call:unsigned-int c-call:unsigned-long)
264 #'%gslist-prepend-unsigned)))
265 (to-alien (to-alien-function type)))
267 for element in (reverse list)
268 as gslist = (funcall new-element (or gslist (make-pointer 0))
269 (funcall to-alien element))
270 finally (return gslist))))
272 (defbinding (gslist-free "g_slist_free") () nil
276 (defmethod alien-type ((type (eql 'gslist)) &rest args)
277 (declare (ignore type args))
278 (alien-type 'pointer))
280 (defmethod size-of ((type (eql 'gslist)) &rest args)
281 (declare (ignore type args))
284 (defmethod to-alien-form (list (type (eql 'gslist)) &rest args)
285 (declare (ignore type))
286 (destructuring-bind (element-type) args
287 `(make-sglist ',element-type ,list)))
289 (defmethod to-alien-function ((type (eql 'gslist)) &rest args)
290 (declare (ignore type))
291 (destructuring-bind (element-type) args
293 (make-gslist element-type list))))
295 (defmethod from-alien-form (gslist (type (eql 'gslist)) &rest args)
296 (declare (ignore type))
297 (destructuring-bind (element-type) args
298 `(let ((gslist ,gslist))
300 (map-glist 'list #'identity gslist ',element-type)
301 (gslist-free gslist)))))
303 (defmethod from-alien-function ((type (eql 'gslist)) &rest args)
304 (declare (ignore type))
305 (destructuring-bind (element-type) args
308 (map-glist 'list #'identity gslist element-type)
309 (gslist-free gslist)))))
311 (defmethod cleanup-form (list (type (eql 'gslist)) &rest args)
312 (declare (ignore type args))
313 `(gslist-free ,list))
315 (defmethod cleanup-function ((type (eql 'gslist)) &rest args)
316 (declare (ignore type args))
323 (defun make-c-vector (type length &optional content location)
324 (let* ((size-of-type (size-of type))
325 (location (or location (allocate-memory (* size-of-type length))))
326 (writer (writer-function type)))
328 for element across content
329 for i from 0 below length
330 as offset = 0 then (+ offset size-of-type)
331 do (funcall writer element location offset))
335 (defun map-c-vector (seqtype function location element-type length)
336 (let ((reader (reader-function element-type))
337 (size-of-element (size-of element-type)))
341 for i from 0 below length
342 as offset = 0 then (+ offset size-of-element)
343 do (funcall function (funcall reader location offset))))
346 for i from 0 below length
347 as offset = 0 then (+ offset size-of-element)
348 collect (funcall function (funcall reader location offset))))
351 with sequence = (make-sequence seqtype length)
352 for i from 0 below length
353 as offset = 0 then (+ offset size-of-element)
356 (funcall function (funcall reader location offset)))
357 finally (return sequence))))))
360 (defmethod alien-type ((type (eql 'vector)) &rest args)
361 (declare (ignore type args))
362 (alien-type 'pointer))
364 (defmethod size-of ((type (eql 'vector)) &rest args)
365 (declare (ignore type args))
368 (defmethod to-alien-form (vector (type (eql 'vector)) &rest args)
369 (declare (ignore type))
370 (destructuring-bind (element-type &optional (length '*)) args
372 `(let* ((vector ,vector)
374 (allocate-memory (+ ,+size-of-int+
375 (* ,(size-of element-type)
378 (make-c-vector ',element-type (length vector) vector location)
379 (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
381 `(make-c-vector ',element-type ,length ,vector))))
383 (defmethod from-alien-form (location (type (eql 'vector)) &rest args)
384 (declare (ignore type))
385 (destructuring-bind (element-type &optional (length '*)) args
387 (error "Can't use vector of variable size as return type")
388 `(map-c-vector 'vector #'identity ',element-type ',length ,location))))
390 (defmethod cleanup-form (location (type (eql 'vector)) &rest args)
391 (declare (ignore type))
392 (destructuring-bind (element-type &optional (length '*)) args
393 `(let* ((location ,location)
394 (length ,(if (eq length '*)
395 `(sap-ref-32 location ,(- +size-of-int+))
398 with destroy = (destroy-function ',element-type)
399 for i from 0 below length
400 as offset = 0 then (+ offset ,(size-of element-type))
401 do (funcall destroy location offset))
402 (deallocate-memory ,(if (eq length '*)
403 `(sap+ location ,(- +size-of-int+))