-(defcstruct tree-iter
- (stamp :int)
- (user-data :pointer)
- (user-data-2 :pointer)
- (user-data-3 :pointer))
-
-(defun tree-iter-get-stamp (i) (foreign-slot-value (pointer i) 'tree-iter 'stamp))
-(defun tree-iter-set-stamp (value i) (setf (foreign-slot-value (pointer i) 'tree-iter 'stamp) value))
-(defun tree-iter-get-user-data (i) (pointer-address (foreign-slot-value (pointer i) 'tree-iter 'user-data)))
-(defun tree-iter-set-user-data (value i) (setf (foreign-slot-value (pointer i) 'tree-iter 'user-data) (make-pointer value)))
-
-(defun tree-iter-alloc () (glib:g-malloc (foreign-type-size 'tree-iter)))
-(defun tree-iter-free (v) (glib:g-free v))
-
-(define-g-boxed-ref "GtkTreeIter" tree-iter
- (:slots (stamp :reader tree-iter-get-stamp :writer tree-iter-set-stamp :accessor tree-iter-stamp)
- (user-data :reader tree-iter-get-user-data :writer tree-iter-set-user-data :accessor tree-iter-user-data))
- (:alloc-function tree-iter-alloc)
- (:free-function tree-iter-free))
-@end lisp
-
-Another example:
-@lisp
-(define-foreign-type unichar ()
- ()
- (:actual-type :uint32)
- (:simple-parser unichar))
-
-(defmethod translate-from-foreign (value (type unichar))
- (code-char value))
-
-(defmethod translate-to-foreign (value (type unichar))
- (char-code value))
-
-(define-g-boxed-ref "GtkTextIter" text-iter
- (:free-function gtk-text-iter-free)
- (:alloc-function gtk-text-iter-alloc)
- (:slots (text-iter-buffer :reader "gtk_text_iter_get_buffer" :type (g-object text-buffer))
- (text-iter-offset :reader "gtk_text_iter_get_offset" :writer "gtk_text_iter_set_offset" :type :int)
- (text-iter-line :reader "gtk_text_iter_get_line" :writer "gtk_text_iter_set_line" :type :int)
- (text-iter-line-offset :reader "gtk_text_iter_get_line_offset" :writer "gtk_text_iter_set_line_offset" :type :int)
- (text-iter-visible-line-offset :reader "gtk_text_iter_get_visible_line_offset" :writer "gtk_text_iter_set_visible_line_offset" :type :int)
- (text-iter-char :reader "gtk_text_iter_get_char" :type unichar)
- (text-iter-pixbuf :reader "gtk_text_iter_get_pixbuf" :type (g-object pixbuf))
- (text-iter-marks :reader "gtk_text_iter_get_marks" :type (gslist (g-object text-mark) :free-from-foreign t))
- (text-iter-child-anchor :reader "gtk_text_iter_get_child_anchor" :type (g-object text-child-anchor))
- (text-iter-tags :reader "gtk_text_iter_get_tags" :type (gslist (g-object text-tag) :free-from-foreign t))
- (text-iter-chars-in-line :reader "gtk_text_iter_get_chars_in_line" :type :int)
- (text-iter-language :reader "gtk_text_iter_get_language" :type :pointer)
- (text-iter-is-end :reader "gtk_text_iter_is_end" :type :boolean)
- (text-iter-is-start :reader "gtk_text_iter_is_start" :type :boolean)
- (text-iter-can-insert :reader "gtk_text_iter_can_insert" :type :boolean)
- (text-iter-starts-word :reader "gtk_text_iter_starts_word" :type :boolean)
- (text-iter-ends-word :reader "gtk_text_iter_ends_word" :type :boolean)
- (text-iter-inside-word :reader "gtk_text_iter_inside_word" :type :boolean)
- (text-iter-starts-line :reader "gtk_text_iter_starts_line" :type :boolean)
- (text-iter-ends-line :reader "gtk_text_iter_ends_line" :type :boolean)
- (text-iter-starts-sentence :reader "gtk_text_iter_starts_sentence" :type :boolean)
- (text-iter-ends-sentence :reader "gtk_text_iter_ends_sentence" :type :boolean)
- (text-iter-inside-sentence :reader "gtk_text_iter_inside_sentence" :type :boolean)
- (text-iter-is-cursor-position :reader "gtk_text_iter_is_cursor_position" :type :boolean)))
-
-(defcstruct %text-iter
- (dummy1 :pointer)
- (dummy2 :pointer)
- (dummy3 :int)
- (dummy4 :int)
- (dummy5 :int)
- (dummy6 :int)
- (dummy7 :int)
- (dummy8 :int)
- (dummy9 :pointer)
- (dummy10 :pointer)
- (dummy11 :int)
- (dummy12 :int)
- (dummy13 :int)
- (dummy14 :pointer))
-
-(defcfun gtk-text-iter-copy :pointer
- (iter :pointer))
-
-(defcfun gtk-text-iter-free :void
- (iter :pointer))
-
-(defun gtk-text-iter-alloc ()
- (with-foreign-object (iter '%text-iter)
- (gtk-text-iter-copy iter)))
+(define-g-boxed-cstruct rectangle "GdkRectangle"
+ (x :int :initform 0)
+ (y :int :initform 0)
+ (width :int :initform 0)
+ (height :int :initform 0))
+
+(boxed-related-symbols 'rectangle)
+@result{}
+(RECTANGLE MAKE-RECTANGLE COPY-RECTANGLE RECTANGLE-X RECTANGLE-Y
+ RECTANGLE-WIDTH RECTANGLE-HEIGHT)
+@end lisp
+
+@node GBoxed foreign type
+@section GBoxed foreign type
+
+@lisp
+(g-boxed-foreign name &rest option*)
+
+option ::= :return
+@end lisp
+
+@table @var
+@item @var{name}
+Name of GBoxed type
+@item @var{option}
+Option of foreign type
+@item @code{:return}
+An option that identifies the foreign type which is used at return position (as foreign function return type or as a callback return type)
+@end table
+
+@code{g-boxed-foreign} type deals with marshaling data between Lisp code and foreign code. The marshaling follows the following principles:
+@itemize
+@item All operations on Lisp objects corresponding to GBoxed types are type-safe and should never lead to any form of memory corruption (if some operation is impossible due to e.g., pointer in opaque pointer wrapper being invalidated, error should be signalled)
+@item Lisp objects should not be manually managed and are properly reclaimed by garbage collector, leaving no memory leaks
+@item Foreign code can change objects that are passed to them as arguments. This is required for functions that operate by modifying their arguments
+@item Lisp code in callbacks can change objects that are passed as arguments. This is required to be able to implement interfaces that have functions that operate by modifying their arguments
+@end itemize
+
+The @code{:return} option is required to be able to properly manage memory of opaque pointer wrappers and propagate changes to foreign and lisp structures.
+
+In order to be able to correctly use @code{g-boxed-foreign} foreign type in callbacks, you should use @code{glib-defcallback}. This macro is a thin wrapper around @code{cffi:defcallback} that adds proper handling of @code{g-boxed-foreign} foreign types.
+
+Examples of usage:
+@lisp
+(define-vtable ("GtkTreeModel" c-gtk-tree-model)
+ ...
+ (tree-model-get-path-impl tree-model-get-path-cb
+ (g-boxed-foreign tree-path :return) (tree-model g-object) (iter (g-boxed-foreign tree-iter)))
+ (tree-model-get-value-impl tree-model-get-value-cb
+ :void (tree-model g-object) (iter (g-boxed-foreign tree-iter)) (n :int) (value (:pointer g-value)))
+ (tree-model-iter-next-impl tree-model-iter-next-cb
+ :boolean (tree-model g-object) (iter (g-boxed-foreign tree-iter)))
+ ...)
+
+(defcfun gtk-text-iter-forward-search :boolean
+ (iter (g-boxed-foreign text-iter))
+ (str (:string :free-to-foreign t))
+ (flags text-search-flags)
+ (match-start (g-boxed-foreign text-iter))
+ (match-end (g-boxed-foreign text-iter))
+ (limit (g-boxed-foreign text-iter)))