Custom Extensions to Tcl

By this point, you should have a pretty decent understanding of the underlying philosophy of Tcl and Tk, and the whole concept of extensions, of which [incr Tcl] and PLplot are examples. These alone are enough to allow the rapid prototyping and development of powerful, flexible graphical applications. Normally the programmer simply writes a shell script to be executed by the Tk windowing shell, wish. It is in vogue for each Tcl/Tk extension package to build it's own extended WISH. There are many examples of this, and indeed even PLplot's plserver program, described in an earlier chapter, could just as easily have been called plwish.

In any event, as exciting and useful as these standalone, extended windowing shells may be, they are ultimately only the beginning of what you can do. The real benefit of this approach is realized when you make your own extended WISH, comprised of Tcl, Tk, any of the standard extensions you like, and finally embellished with a smattering of application specific extensions designed to support your own application domain. In this section we give a detailed introduction to the process of constructing your own WISH. After that, you're on your own...

WISH Construction

The standard way to make your own WISH, as supported by the Tcl/Tk system, is to take a boilerplate file, tkAppInit.c, edit to reflect the Tcl/Tk extensions you will be requiring, add some commands to the interpreter, and link it all together.

Here for example is the important part of the tk02 demo, extracted from the file xtk02.c, which is effectively the extended WISH definition file for the tk02 demo. Comments and other miscellany are omitted.

	  #include "tk.h"
	  #include "itcl.h"

	  /* ... */

	  int   myplotCmd        (ClientData, Tcl_Interp *, int, char **);

	  int
	  Tcl_AppInit(interp)
	  Tcl_Interp *interp;		/* Interpreter for application. */
	  {
	  int   plFrameCmd        (ClientData, Tcl_Interp *, int, char **);

	  Tk_Window main;

	  main = Tk_MainWindow(interp);

	  /*
	  * Call the init procedures for included packages.  Each call should
	  * look like this:
	  *
	  * if (Mod_Init(interp) == TCL_ERROR) {
	  *     return TCL_ERROR;
	  * }
	  *
	  * where "Mod" is the name of the module.
	  */

	  if (Tcl_Init(interp) == TCL_ERROR) {
	  return TCL_ERROR;
	  }
	  if (Tk_Init(interp) == TCL_ERROR) {
	  return TCL_ERROR;
	  }
	  if (Itcl_Init(interp) == TCL_ERROR) {
	  return TCL_ERROR;
	  }
	  if (Pltk_Init(interp) == TCL_ERROR) {
	  return TCL_ERROR;
	  }

	  /*
	  * Call Tcl_CreateCommand for application-specific commands, if
	  * they weren't already created by the init procedures called above.
	  */

	  Tcl_CreateCommand(interp, "myplot", myplotCmd,
	  (ClientData) main, (void (*)(ClientData)) NULL);


	  /*
	  * Specify a user-specific start up file to invoke if the
	  * application is run interactively.  Typically the start up
	  * file is "~/.apprc" where "app" is the name of the application.
	  * If this line is deleted then no user-specific start up file
	  * will be run under any conditions.
	  */

	  tcl_RcFileName = "~/.wishrc";
	  return TCL_OK;
	  }

	  /* ... myPlotCmd, etc ... */

The calls to Tcl_Init() and Tk_Init() are in every WISH. To make an extended WISH, you add calls to the initialization routines for any extension packages you want to use, in this [incr Tcl] (Itcl_Init()) and PLplot (Pltk_Init()). Finally you add keywords to the interpreter, associating them with functions in your code using Tcl_CreateCommand() as shown.

In particular, PLplot has a number of [incr Tcl] classes in its Tcl library. If you want to be able to use those in your WISH, you need to include the initialization of [incr Tcl].

WISH Linking

Having constructed your Tcl_AppInit() function, you now merely need to link this file with your own private files to provide the code for any functions you registered via Tcl_CreateCommand() (and any they depend on), against the Tcl, Tk and extension libraries you are using.

	  cc -c tkAppInit.c
	  cc -c mycommands.c
	  cc -o my_wish tkAppInit.o mycommands.o
	  -lplplotftk -ltcl -ltk -litcl -lX11 -lm

Add any needed -L options as needed.

Voila! You have made a wish.

WISH Programming

Now you are ready to put the genie to work. The basic plan here is to write shell scripts which use your new application specific windowing shell as their interpreter, to implement X Windows user interfaces to control and utilize the facilities made available in your extensions.

Effectively this just comes down to writing Tcl/Tk code, embellished as appropriate with calls to the extension commands you registered. Additionally, since this wish includes the PLplot extensions, you can instantiate any of the PLplot family of [incr Tcl] classes, and invoke methods on those objects to effect the drawing of graphs. Similarly, you may have your extension commands (which are coded in C) call the PLplot C programmers API to draw into the widget. In this way you can have the best of both worlds. Use compiled C code when the computational demands require the speed of compiled code, or use Tcl when your programming convenience is more important than raw speed.