chiark / gitweb /
Updated for glib-1.3.4 and moved code to proxy.lisp
[clg] / glib / gtype.lisp
1 ;; Common Lisp bindings for GTK+ v2.0
2 ;; Copyright (C) 2000 Espen S. Johnsen <esj@stud.cs.uit.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
18 ;; $Id: gtype.lisp,v 1.8 2001-04-29 20:17:07 espen Exp $
19
20 (in-package "GLIB")
21
22 (use-prefix "g")
23
24
25 ;;;; 
26
27 (deftype type-number () '(unsigned 32))
28
29 (eval-when (:compile-toplevel :load-toplevel :execute)
30   (defclass type-query (alien-structure)
31     ((type-number :allocation :alien :type type-number)
32      (name :allocation :alien :type string)
33      (class-size :allocation :alien :type unsigned-int)
34      (instance-size :allocation :alien :type unsigned-int))
35     (:metaclass proxy-class)))
36
37
38 (defbinding ("g_type_name" alien-type-name) (type) (static string)
39   ((find-type-number type) type-number))
40
41 (defbinding %type-from-name () type-number
42   (name string))
43
44 (defbinding type-parent () type-number
45   (type type-number))
46
47 (defbinding %type-query () nil
48   (type type-number)
49   (query type-query))
50
51 (defun type-query (type)
52   (let ((query (make-instance 'type-query)))
53     (%type-query (find-type-number type) query)
54     query))
55
56 (defun type-instance-size (type)
57   (slot-value (type-query type) 'instance-size))
58
59 (defun type-class-size (type)
60   (slot-value (type-query type) 'class-size))
61
62 (defbinding type-class-ref () pointer
63   (type type-number))
64
65 (defbinding type-class-unref () nil
66   (type type-number))
67
68 (defbinding type-class-peek () pointer
69   (type type-number))
70
71 (defbinding type-create-instance (type) pointer
72   ((find-type-number type) type-number))
73
74 (defbinding type-free-instance () nil
75   (instance pointer))
76
77
78 (defvar *type-to-number-hash* (make-hash-table))
79 (defvar *number-to-type-hash* (make-hash-table))
80
81 (defun type-number-from-alien-name (name &optional (error t))
82   (if (string= name "invalid")
83       0
84     (let ((type-number (%type-from-name name)))
85       (cond
86        ((and (zerop type-number) error)
87         (error "Invalid alien type name: ~A" name))
88        ((zerop type-number) nil)
89        (t type-number)))))
90
91 (defun (setf alien-type-name) (alien-name type)
92   (let ((type-name (ensure-type-name type))
93         (type-number (type-number-from-alien-name alien-name)))
94     (setf (gethash type-number *number-to-type-hash*) type-name)
95     (setf (gethash type-name *type-to-number-hash*) type-number)))
96
97 (defun (setf find-type-number) (type-number type)
98   (setf (gethash (ensure-type-name type) *type-to-number-hash*) type-number))
99
100 (defun find-type-number (type)
101   (etypecase type
102     (integer type)
103     (symbol (gethash type *type-to-number-hash*))
104     (pcl::class (gethash (class-name type) *type-to-number-hash*))))
105  
106 (defun type-from-number (type-number)
107   (gethash type-number *number-to-type-hash*))
108
109 (defun type-number-of (object)
110   (find-type-number (type-of object)))
111
112 (defun alien-function (name return-type &rest arg-types)
113   (let ((alien
114          (alien::%heap-alien
115           (alien::make-heap-alien-info
116            :type (alien::parse-alien-type
117                   `(function ,@(cons return-type arg-types)))
118            :sap-form (system:foreign-symbol-address name)))))
119     #'(lambda (&rest args)
120         (apply #'alien:alien-funcall alien args))))
121
122
123 (defun type-init (name &optional init-fname)
124   (funcall
125    (alien-function
126     (or
127      init-fname
128      (default-alien-fname (format nil "~A_get_type" name)))
129     '(unsigned 32))))
130
131
132 ;;;; Superclass for wrapping types in the glib type system
133
134 (eval-when (:compile-toplevel :load-toplevel :execute)
135   (defclass ginstance (proxy)
136     ()
137     (:metaclass proxy-class)
138     (:size 4 #|(size-of 'pointer|#)))
139
140 (defmethod initialize-proxy ((instance ginstance) &rest initargs &key location)
141   (declare (ignore initargs))
142   (setf 
143    (slot-value instance 'location)
144    (funcall (ginstance-class-ref (class-of instance)) location))
145   (call-next-method))
146
147 (defmethod instance-finalizer ((instance ginstance))
148   (let ((location (proxy-location instance))
149         (unref (ginstance-class-unref (class-of instance))))
150     (declare (type system-area-pointer location))
151     #'(lambda ()
152         (funcall unref location)
153         (remove-cached-instance location))))
154
155 (defun %type-of-ginstance (location)
156   (let ((class (sap-ref-sap location 0)))
157     (type-from-number (sap-ref-unsigned class 0))))
158
159 (deftype-method translate-from-alien
160     ginstance (type-spec location &optional weak-ref)
161   (declare (ignore type-spec))
162   `(let ((location ,location))
163      (unless (null-pointer-p location)
164        (ensure-proxy-instance
165         (%type-of-ginstance location) location ,weak-ref))))
166
167 (deftype-method translate-to-alien
168     ginstance (type-spec object &optional weak-ref)
169   (declare (ignore type-spec))
170   (if weak-ref
171       `(proxy-location ,object)
172     `(let ((object ,object))
173        (funcall
174         (ginstance-class-ref (class-of object)) (proxy-location object)))))
175
176 (deftype-method unreference-alien ginstance (type-spec location)
177   (declare (ignore type-spec))
178   `(let* ((location ,location)
179           (class (find-class (%type-of-ginstance location))))
180      (funcall (ginstance-class-unref class) location)))
181
182
183
184 ;;;; Metaclass for subclasses of ginstance
185
186 (eval-when (:compile-toplevel :load-toplevel :execute)
187   (defclass ginstance-class (proxy-class)
188     ((ref :reader ginstance-class-ref)
189      (unref :reader ginstance-class-unref))))
190
191
192 (defmethod shared-initialize ((class ginstance-class) names
193                               &rest initargs
194                               &key name alien-name size
195                               ref unref type-init)
196   (declare (ignore initargs names))
197   (call-next-method)
198
199   (let* ((class-name (or name (class-name class)))
200          (type-number
201           (cond
202            ((and alien-name type-init)
203             (error
204              "Specify either :type-init or :alien-name for class ~A"
205              class-name))
206            (alien-name (type-number-from-alien-name (first alien-name)))
207            (type-init (type-init class-name (first type-init)))
208            (t
209             (or
210              (type-number-from-alien-name
211               (default-alien-type-name class-name) nil)
212              (type-init class-name))))))
213     (setf (find-type-number class) type-number)
214     (unless size
215       (setf
216        (slot-value class 'size)
217        (type-instance-size (find-type-number class-name))))
218     (when ref
219       (setf
220        (slot-value class 'ref)
221        (alien-function (first ref) 'system-area-pointer 'system-area-pointer)))
222     (when unref
223       (setf
224        (slot-value class 'unref)
225        (alien-function (first unref) 'void 'system-area-pointer)))))
226
227 (defmethod shared-initialize :after ((class ginstance-class) names
228                                      &rest initargs)
229   (declare (ignore names initargs))
230   (unless (slot-boundp class 'ref)
231     (setf
232      (slot-value class 'ref)
233      (ginstance-class-ref (most-specific-proxy-superclass class))))
234   (unless (slot-boundp class 'unref)
235     (setf
236      (slot-value class 'unref)
237      (ginstance-class-unref (most-specific-proxy-superclass class)))))
238
239
240 (defmethod validate-superclass
241     ((class ginstance-class) (super pcl::standard-class))
242   (subtypep (class-name super) 'ginstance))
243
244
245 ;;;; Initializing type numbers
246
247 (setf (alien-type-name 'invalid) "invalid")
248 (setf (alien-type-name 'char) "gchar")
249 (setf (alien-type-name 'unsigned-char) "guchar")
250 (setf (alien-type-name 'boolean) "gboolean")
251 (setf (alien-type-name 'int) "gint")
252 (setf (alien-type-name 'unsigned-int) "guint")
253 (setf (alien-type-name 'long) "glong")
254 (setf (alien-type-name 'unsigned-long) "gulong")
255 (setf (alien-type-name 'single-float) "gfloat")
256 (setf (alien-type-name 'double-float) "gdouble")
257 (setf (alien-type-name 'string) "GString")
258 (setf (find-type-number 'fixnum) (find-type-number 'int))