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