Next: , Up: Creating GObjects classes and implementing GInterfaces


11.1 define-vtable

— Macro: define-vtable
     (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)
g-type-name
A string naming the GObject type of interface
cffi-structure-item
A structure item that is inserted verbatim into foreign structure definition of vtable and is not used as a pointer to method
method-name
A name for implementation generic function
return-type
A CFFI specifier for foreign function return type
arg-name
A symbol naming the argument of interface method
arg-type
A CFFI specifier for foreign function argument type
call-code
A body of code that is used to convert arguments and return values between interface signature and desired implementor generic function signature

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. items 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))))