Recently, I needed to use the BLT extension to Tk.  Since all my data comes
from ocaml, and there is a fair amount of data, I wrote a simple C interface.
Below are the steps I took under ocaml-2.04.
My questions are:
1.  Why is tcl_eval not exported by default (in protocol.mli)?  I
    don't like Tcl much, but 
    for trivial commands like "package require blt", I don't see a
    problem with direct string evaluation.
    Also, it would be nice to have some interactive control over caml programs
    compiled to native code; wouldn't Tcl work well for this?
2.  Apparently, most high-level widget interfaces are defined in
    otherlibs/labltk/Widgets.src, with special routines in 
    otherlibs/labltk/builtin/* and general low level support in 
    otherlibs/labltk/support.
    Since I only needed a small subset of the BLT commands and
    couldn't quite figure out the details in this setup, I used direct
    string evaluation with some embedded caml callbacks, e.g.
    tcl (g.g_name ^ " element create line_" ^ xv ^ " \
             -xdata "^ xv ^ " -ydata "^ yv ^ " \
             -symbol {} \
             -pixels 0.1c \
             -color "^
             (domain_color dom) ^ "\n")
    Needless to say, a clean wrapper would be better.	   
    Is there a particular approach to be followed when adding new
    widgets?
    Or better yet, does someone have a *documented* example for the
    addition of a widget requiring additions in all three places :) ?
Cheers,
        Michael
Here are my notes:
    To really use Tcl with camltk requires some special
    installation steps. 
    
    1.  Produce the include file camltk41/camltk.h
        This include file must be manually installed from the
        ocamltk41 distribution; e.g.
            cp ocamltk41/support/camltk.h /usr/local/lib/ocaml/camltk41
    
    2.  The caml header file protocol.mli is ....  It does not
        provide the (very useful) function tcl_eval.
    
        To fix this, do:
            cd ./otherlibs/labltk/support
            [ cd ocamltk41/support in 2.04 ]
            cat >>  protocol.mli <<EOF
    val tcl_eval : string -> string
    EOF
        BEFORE compiling the ocamltk41.
        [Doing this after and re-installing only changed files causes
            inexplicable core dumps later.]
    
        [Compare:
             tcl_eval "package require BLT"
         vs. 
             tkEval [| TkToken "package"; TkToken "require"; TkToken "BLT"
             |];;
         On longer inputs, this would not be amusing... ]
        
Using these, the following worked:
grid_ocaml.ml:
    (*
       set_blt_vector name array --
           set/create the BLT array "name" and
           set its entries to the values in <array>.
    *)
    external set_blt_vector : string -> float array -> unit = "set_blt_vector_" 
        
And the C file:
    
    #include <tcl.h>
    #include <blt.h>
    
    #include "caml/mlvalues.h"
    /* 
       This include file must have been manually installed from the
       ocamltk41 distribution; e.g.
       cp ocamltk41/support/camltk.h /usr/local/lib/ocaml/camltk41
    
       Some code taken from the ocaml/fortran interface example.
    
    */
    #include "camltk41/camltk.h"
    
    
    value set_blt_vector_(value vName, value vA)
    {
        char *name  = String_val(vName);
    
        /*
         * Do we have a native, ocamlopt array or a bytecode, ocamlc one?
         */
    
        int isNative = Tag_val(vA) == Double_array_tag;
    
        /*
         * How big is it?
         */
    
        int arrayLength =
        isNative ? Bosize_val(vA) / sizeof(double) : Wosize_val(vA);
    
        Blt_Vector *vecPtr;
        double *newArr;
    
        /* 
         * Make sure the Tcl interpreter exists.
         */
        if (cltclinterp == NULL) 
        failwith("Tcl not initialized.");
    
        /*
         * Make [newArr] point to a C-friendly version of [vA]
         */
    
        /* Allocate the array on the C heap, and let BLT free() it (see
           below). */
        newArr = (double *)malloc(arrayLength * sizeof(double));
    
        if (isNative)
        {
            /* ocamlopt-style array: copy it using [Double_field] */
                int i;
                    for (i = 0; i < arrayLength; ++i)
                        newArr[i] = Double_field(vA, i);
                        }
        else
        {
            /* ocamlc-style array: copy it using [Double_val(Field(...))]
        */
            int i;
                for (i = 0; i < arrayLength; ++i)
                    newArr[i] = Double_val(Field(vA, i));
                    }
    
    
        /*
         * Prepare the BLT vector. 
         */
        if (Blt_VectorExists(cltclinterp, name))  {
        if (Blt_GetVector(cltclinterp, name, &vecPtr) != TCL_OK) 
            failwith("Tcl error.");
        } else {
        if (Blt_CreateVector(cltclinterp, name, 0, &vecPtr) != TCL_OK) 
            failwith("Tcl error.");
        }
        /*
         * Reset the vector to use the new array. Clients will be notified
         * when Tk is idle. 
         * TCL_DYNAMIC tells the vector to free the memory allocated
         * if it needs to reallocate or destroy the vector.
         */
        if (Blt_ResetVector(vecPtr, newArr, arrayLength, arrayLength,
                                    TCL_DYNAMIC) != TCL_OK)
                                    failwith("Tcl error.");
      
        return Val_unit;
    }
        
This archive was generated by hypermail 2b29 : Thu Mar 23 2000 - 13:44:45 MET