Next: register-object-type-implementation, Up: Creating GObjects classes and implementing GInterfaces
(define-vtable (g-type-name type-name) &body item*) item ::= (:skip cffi-structure-item) item ::= (method-name (return-type &rest arg*) &key impl-call) arg ::= (arg-name arg-type) impl-call ::= ((arg-name*) &body call-code)
Macro that specifies the vtable for an interface. Vtable for an interface is a structure that contains pointer to implementations of interface methods. Vtable is used to dispach method calls to corresponding method implementations. In cl-gtk2-gobject, vtables are needed to create classes that implement GObject interfaces.
GObject interfaces are implemented in the following way. For every method, an implementor generic function is defined. This generic function is called by interface method callback, and CLOS classes specialize on this generic function to implement an interface. The generic function has the same signature as the interface's function, but signatures may differ.
This macro defines generic functions (named by concatenatinag type-name, name and impl
; e.g., get-flags
method of class tree-model
will have generic function named tree-model-get-flags-impl
) that correspond to methods of an interface. On these generic functions methods should be defined that implement the interface method. 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 :skip
prepended to them. This is needed to be able to correctly calculate offsets to function pointers in vtable.
In some cases, the signature of interface method is not very lispy: it may pass void*
pointers, pointers to places where return values should be stored. To conceal such unlispy things, you specify your own code that will call the generic function and translate arguments for implementor generic function. This is implemented by specifying impl-call method option. impl-call specifies the signature of implementor function and code that calls the generic function and returns its result. The code is put in return position of callback, and it has access to the arguments of callback and its return value becomes the return value of callback.
Example:
(define-vtable ("GtkTreeModel" 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 (get-flags (tree-model-flags (tree-model g-object))) (get-value (:void (tree-model g-object) (iter (g-boxed-foreign tree-iter)) (n :int) (value (:pointer g-value))) :impl-call ((tree-model iter n) (multiple-value-bind (v type) (tree-model-get-value-impl tree-model iter n) (set-g-value value v type))))) (defmethod tree-model-get-flags-impl ((model array-list-store)) '(:list-only)) (defmethod tree-model-get-value-impl ((model array-list-store) iter n) (let ((n-row (tree-iter-user-data iter))) (values (funcall (aref (store-getters model) n) (aref (store-items model) n-row)) (aref (store-types model) n))))