e2e56e3d67579dc08bfcf0de28a5566d4e221542
[cl-gtk2.git] / gboxed.test.lisp
1 (in-package :gobject)
2
3 (define-foreign-type g-boxed-foreign-type ()
4   ((info :initarg :info
5          :accessor g-boxed-foreign-info
6          :initform (error "info must be specified"))
7    (free-from-foreign :initarg :free-from-foreign
8                       :initform nil
9                       :accessor g-boxed-foreign-free-from-foreign)
10    (free-to-foreign :initarg :free-to-foreign
11                     :initform nil
12                     :accessor g-boxed-foreign-free-to-foreign)
13    (for-callback :initarg :for-callback
14                  :initform nil
15                  :accessor g-boxed-foreign-for-callback))
16   (:actual-type :pointer))
17
18 (eval-when (:compile-toplevel :load-toplevel :execute)
19   (defstruct g-boxed-info
20     name
21     g-type))
22
23 (eval-when (:compile-toplevel :load-toplevel :execute)
24  (defun get-g-boxed-foreign-info (name)
25    (get name 'g-boxed-foreign-info)))
26
27 (define-parse-method g-boxed-foreign (name &key free-from-foreign free-to-foreign for-callback)
28   (let ((info (get-g-boxed-foreign-info name)))
29     (assert info nil "Unknown foreign GBoxed type ~A" name)
30     (make-instance 'g-boxed-foreign-type
31                    :info info
32                    :free-from-foreign free-from-foreign
33                    :free-to-foreign free-to-foreign
34                    :for-callback for-callback)))
35
36 (eval-when (:load-toplevel :compile-toplevel :execute)
37   (defstruct (g-boxed-cstruct-wrapper-info (:include g-boxed-info))
38     cstruct
39     slots))
40
41 (defmacro define-g-boxed-cstruct (name cstruct-name g-type-name &body slots)
42   `(progn
43      (defstruct ,name
44        ,@(iter (for (name type &key initarg) in slots)
45                (collect (list name initarg))))
46      (defcstruct ,cstruct-name
47        ,@(iter (for (name type &key initarg) in slots)
48                (collect `(,name ,type))))
49      (eval-when (:compile-toplevel :load-toplevel :execute)
50        (setf (get ',name 'g-boxed-foreign-info)
51              (make-g-boxed-cstruct-wrapper-info :name ',name
52                                                 :g-type ,g-type-name
53                                                 :cstruct ',cstruct-name
54                                                 :slots ',(iter (for (name type &key initarg) in slots)
55                                                                (collect name)))))))
56
57 (define-g-boxed-cstruct gdk-rectangle gdk-rectangle-cstruct "GdkRectangle"
58   (x :int :initarg 0)
59   (y :int :initarg 0)
60   (width :int :initarg 0)
61   (height :int :initarg 0))
62
63 (defgeneric create-temporary-native (type proxy)
64   (:documentation "Creates a native structure (or passes a pointer to copy contained in PROXY)
65 that contains the same data that the PROXY contains and returns a pointer to it.
66
67 This call is always paired by call to FREE-TEMPORARY-NATIVE and calls may be nested."))
68
69 (defgeneric free-temporary-native (type proxy native-ptr)
70   (:documentation "Frees the native structure that was previously created
71 by CREATE-TEMPORARY-NATIVE for the same PROXY.
72
73 Also reads data from native structure pointer to by NATIVE-PTR
74 and sets the PROXY to contain the same data.
75
76 This call is always paired by call to CREATE-TEMPORARY-NATIVE and calls may be nested."))
77
78 (defgeneric create-proxy-for-native (type native-ptr)
79   (:documentation "Creates a proxy that is initialized by data contained in native
80 structured pointed to by NATIVE-PTR.
81
82 Created proxy should not be linked to NATIVE-PTR and should have
83 indefinite lifetime (until garbage collector collects it). Specifically,
84 if proxy need a pointer to native structure, it should make a copy of
85 a structure.
86
87 If proxy requires finalization, finalizers should be added."))
88
89 (defgeneric create-reference-proxy (type native-ptr)
90   (:documentation "Creates a reference proxy for a native structure pointed to by NATIVE-PTR.
91
92 Reference proxy's lifetime is bound to duration of a callback. When the
93 callback returns the reference proxy is declared invalid and operations on it are errors.
94
95 This call is always paired by call to FREE-REFERENCE-PROXY and calls will not nest."))
96
97 (defgeneric free-reference-proxy (type proxy native-ptr)
98   (:documentation "Frees a reference proxy PROXY previously created by call to
99 CREATE-REFERENCE-PROXY. This call should ensure that all changes on PROXY are
100 reflected in native structure pointed to by NATIVE-PTR.
101
102 After a call to FREE-REFERENCE-PROXY, PROXY is declared invalid and using it is an error,
103 operations on it should signal erros.
104
105 This call is always paired by call to CREATE-REFERENCE-PROXY."))
106
107 (defmethod create-temporary-native ((type g-boxed-cstruct-wrapper-info) proxy)
108   (format t "create-temporary-native~%")
109   (let* ((native-structure-type (g-boxed-cstruct-wrapper-info-cstruct type))
110          (native-structure (foreign-alloc native-structure-type)))
111     (iter (for slot in (g-boxed-cstruct-wrapper-info-slots type))
112           (setf (foreign-slot-value native-structure native-structure-type slot)
113                 (slot-value proxy slot)))
114     native-structure))
115
116 (defmethod free-temporary-native ((type g-boxed-cstruct-wrapper-info) proxy native-structure)
117   (format t "free-temporary-native~%")
118   (let ((native-structure-type (g-boxed-cstruct-wrapper-info-cstruct type)))
119     (iter (for slot in (g-boxed-cstruct-wrapper-info-slots type))
120           (setf (slot-value proxy slot)
121                 (foreign-slot-value native-structure native-structure-type slot))))
122   (foreign-free native-structure))
123
124 (defmethod create-proxy-for-native ((type g-boxed-cstruct-wrapper-info) native-structure)
125   (format t "create-proxy-for-native~%")
126   (let* ((native-structure-type (g-boxed-cstruct-wrapper-info-cstruct type))
127          (proxy (make-instance (g-boxed-info-name type))))
128     (iter (for slot in (g-boxed-cstruct-wrapper-info-slots type))
129           (setf (slot-value proxy slot)
130                 (foreign-slot-value native-structure native-structure-type slot)))
131     proxy))
132
133 (defmethod create-reference-proxy ((type g-boxed-cstruct-wrapper-info) native-structure)
134   (format t "create-reference-proxy~%")
135   (create-proxy-for-native type native-structure))
136
137 (defmethod free-reference-proxy ((type g-boxed-cstruct-wrapper-info) proxy native-structure)
138   (format t "free-reference-proxy~%")
139   (let ((native-structure-type (g-boxed-cstruct-wrapper-info-cstruct type)))
140     (iter (for slot in (g-boxed-cstruct-wrapper-info-slots type))
141           (setf (foreign-slot-value native-structure native-structure-type slot)
142                 (slot-value proxy slot)))))
143
144 (defmethod translate-to-foreign (proxy (type g-boxed-foreign-type))
145   (if proxy
146       (let* ((info (g-boxed-foreign-info type)))
147         (values (create-temporary-native info proxy) proxy))
148       (null-pointer)))
149
150 (defmethod free-translated-object (native-structure (type g-boxed-foreign-type) proxy)
151   (when proxy
152     (free-temporary-native (g-boxed-foreign-info type) proxy native-structure)))
153
154 (defmethod translate-from-foreign (native-structure (type g-boxed-foreign-type))
155   (unless (null-pointer-p native-structure)
156     (let* ((info (g-boxed-foreign-info type)))
157       (cond
158         ((g-boxed-foreign-for-callback type)
159          (create-reference-proxy info native-structure))
160         ((or (g-boxed-foreign-free-to-foreign type)
161              (g-boxed-foreign-free-from-foreign type))
162          (error "Feature not yet handled"))
163         (t (create-proxy-for-native info native-structure))))))
164
165 (defmethod cleanup-translated-object-for-callback ((type g-boxed-foreign-type) proxy native-structure)
166   (unless (null-pointer-p native-structure)
167     (free-reference-proxy (g-boxed-foreign-info type) proxy native-structure)))
168
169 (defmethod has-callback-cleanup ((type g-boxed-foreign-type))
170   t)
171
172 (defcallback incf-rectangle :void ((rectangle (g-boxed-foreign gdk-rectangle :for-callback t))
173                                    (delta :int))
174   (incf (gdk-rectangle-x rectangle) delta)
175   (incf (gdk-rectangle-y rectangle) delta)
176   (incf (gdk-rectangle-width rectangle) delta)
177   (incf (gdk-rectangle-height rectangle) delta)
178   (format t "~A~%" rectangle))
179
180 (defun do-incf-rect (r &optional (delta 1))
181   (foreign-funcall-pointer (callback incf-rectangle) ()
182                            (g-boxed-foreign gdk-rectangle) r
183                            :int delta
184                            :void)
185   r)
186
187 (eval-when (:compile-toplevel :load-toplevel :execute)
188   (defstruct (g-boxed-opaque-wrapper-info (:include g-boxed-info))
189     alloc free))
190
191 (defclass g-boxed-opaque ()
192   ((pointer :initarg :pointer
193             :initform nil
194             :accessor g-boxed-opaque-pointer)))
195
196 (defmethod create-temporary-native ((type g-boxed-opaque-wrapper-info) proxy)
197   (declare (ignore type))
198   (g-boxed-opaque-pointer proxy))
199
200 (defmethod free-temporary-native ((type g-boxed-opaque-wrapper-info) proxy native-structure)
201   (declare (ignore type proxy native-structure)))
202
203 (defmethod create-reference-proxy ((type g-boxed-opaque-wrapper-info) native-structure)
204   (make-instance (g-boxed-info-g-type type) :pointer native-structure))
205
206 (defmethod free-reference-proxy ((type g-boxed-opaque-wrapper-info) proxy native-structure)
207   (declare (ignore type native-structure))
208   (setf (g-boxed-opaque-pointer proxy) nil))
209
210 (defmethod create-proxy-for-native ((type g-boxed-opaque-wrapper-info) native-structure)
211   (let* ((g-type (g-boxed-info-g-type type))
212          (native-copy (g-boxed-copy g-type native-structure)))
213     (flet ((finalizer () (g-boxed-free g-type native-copy)))
214       (let ((proxy (make-instance (g-boxed-opaque-wrapper-info-g-type type) :pointer native-copy)))
215         (tg:finalize proxy #'finalizer)
216         proxy))))
217
218 (defmacro define-g-boxed-opaque (name g-type-name &key
219                                  (alloc (error "Alloc must be specified")))
220   (let ((native-copy (gensym "NATIVE-COPY-"))
221         (instance (gensym "INSTANCE-"))
222         (finalizer (gensym "FINALIZER-")))
223     `(progn (defclass ,name (g-boxed-opaque) ())
224             (defmethod initialize-instance :after ((,instance ,name) &key &allow-other-keys)
225               (unless (g-boxed-opaque-pointer ,instance)
226                 (let ((,native-copy ,alloc))
227                   (flet ((,finalizer () (g-boxed-free ,g-type-name ,native-copy)))
228                     (setf (g-boxed-opaque-pointer ,instance) ,native-copy)
229                     (finalize ,instance #',finalizer)))))
230             (eval-when (:compile-toplevel :load-toplevel :execute)
231               (setf (get ',name 'g-boxed-foreign-info)
232                     (make-g-boxed-opaque-wrapper-info :name ',name
233                                                       :g-type ,g-type-name))))))
234
235 (define-g-boxed-opaque gtk-tree-path "GtkTreePath"
236   :alloc (let* ((native-structure (gtk-tree-path-new))
237                 (native-copy (g-boxed-copy "GtkTreePath" native-structure)))
238            (gtk-tree-path-free native-structure)
239            native-copy))
240
241 (defcfun gtk-tree-path-new :pointer)
242
243 (defcfun gtk-tree-path-free :void
244   (gtk-tree-path :pointer))
245
246 (defcfun gtk-tree-path-copy :pointer
247   (gtk-tree-path :pointer))
248
249 (defcfun (%gtk-tree-path-get-depth "gtk_tree_path_get_depth") :int
250   (path (g-boxed-foreign gtk-tree-path)))
251
252 (defcfun (%gtk-tree-path-get-indices "gtk_tree_path_get_indices") (:pointer :int)
253   (path (g-boxed-foreign gtk-tree-path)))
254
255 (defcfun gtk-tree-path-append-index :void
256   (path (g-boxed-foreign gtk-tree-path))
257   (index :int))
258
259 (defun tree-path-get-indices (path)
260   (let ((n (%gtk-tree-path-get-depth path))
261         (indices (%gtk-tree-path-get-indices path)))
262     (loop
263        for i from 0 below n
264        collect (mem-aref indices :int i))))