Added documentation about creating GObject classes
authorDmitry Kalyanov <Kalyanov.Dmitry@gmail.com>
Sat, 18 Jul 2009 16:55:23 +0000 (20:55 +0400)
committerDmitry Kalyanov <Kalyanov.Dmitry@gmail.com>
Sat, 18 Jul 2009 16:55:23 +0000 (20:55 +0400)
doc/gobject.texi

index 949642d..5c31a4d 100644 (file)
 * Closures::
 * GObject low-level::
 * GObject high-level::
-* Subclassing GObjects and implementing GInterfaces::
+* Creating GObjects classes and implementing GInterfaces::
 * GBoxed::
 * Generating type definitions by introspection::
 @end menu
@@ -1552,8 +1552,126 @@ This defines the function that returns an instance of GObject class:
 #<GTK:BUTTON @{1002DE74B1@}>
 @end example
 
-@node Subclassing GObjects and implementing GInterfaces
-@chapter Subclassing GObjects and implementing GInterfaces
+@node Creating GObjects classes and implementing GInterfaces
+@chapter Creating GObjects classes and implementing GInterfaces
+
+@menu
+* define-vtable::
+* register-object-type-implementation::
+@end menu
+
+Creating GObject classes from Lisp is the most complex part of GObject binding.
+
+GObject binding at the moment provides only limited scenarios of creating GObject classes. It lets register GObject class (as a subclass of another class or of GObject), specify its properties and implemented interfaces. Each property is associated with Lisp getter and setter functions. Each interface is associated wth vtable (table of virtual function pointers, see @uref{http://en.wikipedia.org/wiki/Vtable}) that specifies a list of methods and their signatures. If class is ever created from GObject side (not from Lisp side, must be constructable with no parameters).
+
+Each virtual function is mapped to a generic function for which class should provide a specialized method. This function should not be called by user. Rather, user code should call corresponding foreign function.
+
+Practically speaking, creating GObject class requires defining CLOS class that correspond to GObject class and calling @code{register-object-type-implementation} with information about the class (its GType name, superclass, interfaces and properties).
+
+Interface that is implemented by a class should have its vtable defined by @code{define-vtable}. Vtable definitions consists of a list of functions's names and signatures and their locations in vtable.
+
+Unfortunately, GObject does not provide information about vtables, and does not support using GClosures to implement virtual functions. Therefore, implementation for all interface's functions are defined as CFFI foreign callbacks. These callbacks in turn call corresponding generic functions that should be specialized on required objects.
+
+@node define-vtable
+@section define-vtable
+
+@example
+(define-vtable (type-name cstruct-name)
+  &body item*)
+
+item ::= (name callback-name return-type &rest arg*)
+item ::= (:skip cffi-structure-item)
+arg ::= (arg-name arg-type)
+@end example
+
+@table @var
+@item @var{type-name}
+A string naming the GObject type of interface
+@item @var{cstruct-name}
+A name for a generated CFFI foreign structure
+@item @var{name}
+A name for implementation generic function
+@item @var{callback-name}
+A name for generated callback function
+@item @var{return-type}
+A CFFI specifier for foreign function return type
+@item @var{arg-name}
+A symbol naming the argument of interface method
+@item @var{arg-type}
+A CFFI specifier for foreign function argument type
+@end table
+
+Macro that specifies the vtable for an interface. This macro defines generic functions (named by @code{name}) that correspond to methods of an interface. On these generic functions methods should be defined that implement the interface method. @code{item}s specify the CFFI foreign structure for vtable. Vtable contains not only function pointers, but other slots. Such slots should be specified here with @code{:skip} prepended to them. This is needed to be able to correctly calculate offsets to function pointers in vtable.
+
+Example:
+@example
+(define-vtable ("GtkTreeModel" c-gtk-tree-model)
+  (:skip parent-instance g-type-interface)
+  ;;some signals
+  (:skip tree-model-row-changed :pointer)
+  (:skip tree-model-row-inserted :pointer)
+  (:skip tree-model-row-has-child-toggled :pointer)
+  (:skip tree-model-row-deleted :pointer)
+  (:skip tree-model-rows-reordered :pointer)
+  ;;methods
+  (tree-model-get-flags-impl tree-model-get-flags-cb
+    tree-model-flags (tree-model g-object))
+  (tree-model-get-n-columns-impl tree-model-get-n-columns-cb
+    :int (tree-model g-object))
+  (tree-model-get-column-type-impl tree-model-get-column-type-cb
+    g-type (tree-model g-object) (index :int))
+  (tree-model-get-iter-impl tree-model-get-iter-cb
+    :boolean (tree-model g-object) (iter (g-boxed-ref tree-iter)) (path (g-boxed-ref tree-path)))
+  (tree-model-get-path-impl tree-model-get-path-cb
+    (g-boxed-ref tree-path) (tree-model g-object) (iter (g-boxed-ref tree-iter)))
+  (tree-model-get-value-impl tree-model-get-value-cb
+    :void (tree-model g-object) (iter (g-boxed-ref 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-ref tree-iter)))
+  (tree-model-iter-children-impl tree-model-iter-children-cb
+    :boolean (tree-model g-object) (iter (g-boxed-ref tree-iter)) (parent (g-boxed-ref tree-iter)))
+  (tree-model-iter-has-child-impl tree-model-iter-has-child-cb
+    :boolean (tree-model g-object) (iter (g-boxed-ref tree-iter)))
+  (tree-model-iter-n-children-impl tree-model-iter-n-children-cb
+    :int (tree-model g-object) (iter (g-boxed-ref tree-iter)))
+  (tree-model-iter-nth-child-impl tree-model-iter-nth-child-cb
+    :boolean (tree-model g-object) (iter (g-boxed-ref tree-iter)) (parent (g-boxed-ref tree-iter)) (n :int))
+  (tree-model-iter-parent-impl tree-model-iter-parent-cb
+    :boolean (tree-model g-object) (iter (g-boxed-ref tree-iter)) (child (g-boxed-ref tree-iter)))
+  (tree-model-ref-node-impl tree-model-ref-node-cb
+    :void (tree-model g-object) (iter (g-boxed-ref tree-iter)))
+  (tree-model-unref-node-impl tree-model-unref-node-cb
+    :void (tree-model g-object) (iter (g-boxed-ref tree-iter))))
+@end example
+
+@node register-object-type-implementation
+@section register-object-type-implementation
+
+@code{(register-object-type-implementation name class parent interfaces properties)}
+
+@table @var
+@item @var{name}
+A string naming the new GObject class.
+@item @var{class}
+A class name of corresponding CLOS class. It should be inherited from @code{g-object} or its descendants.
+@item @var{parent}
+A string naming the GObject superclass
+@item @var{interfaces}
+A list of names of interfaces that this class implements.
+@item @var{properties}
+A list of properties that this class provides.
+Each property is defined as
+@example
+property ::= (property-name property-type accessor property-get-fn property-set-fn)
+@end example
+@end table
+
+A macro that creates a new GObject type and registers the Lisp implementation for it.
+
+Example:
+@example
+(register-object-type-implementation "LispArrayListStore" array-list-store "GObject" ("GtkTreeModel") nil)
+@end example
 
 @node GBoxed
 @chapter GBoxed