The Tcl/Tk interface

Author(s): Montse Iglesias Urraca, The CLIP Group.

The tcltk library package is a bidirectional interface to the Tcl language and the Tk toolkit. Tcl is an interpreted scripting language with many extension packages, particularly the graphical interface toolkit, Tk. The interaction between both languages is expressed in terms of an interface between the Tcl/Tk process and the Prolog process. This approach allows the development of mixed applications where both sides, Tcl/Tk and Prolog, can be combined in order to exploit their respective capabilities.

This library uses two sockets to connect both the Tcl and the Prolog processes: event_socket and term_socket. There are also two Tcl global variables: prolog_variables and terms. The value of any of the bound variables in a goal will be stored in the array prolog_variables with the variable name as index. Terms is the string which contains the printed representation of prolog terms.

Prolog to Tcl

The Tcl/Tk side waits for requests from the Prolog side, and executes the Tcl/Tk code received. Also, the Tcl/Tk side handles the events and exceptions which may be raised on its side, passing on control to the Prolog side in case it is necessary.

To use Tcl, you must create a Tcl interpreter object and send commands to it. A Tcl command is specified as follows:

      Command         --> Atom  { other than [] }
                        | Number
                        | chars(PrologString)
                        | write(Term)
                        | format(Fmt,Args)
                        | dq(Command)
                        | br(Command)
                        | sqb(Command)
                        | min(Command)
                        | ListOfCommands
      ListOfCommands  --> []
                        |[Command|ListOfCommands]

where:

Atom
denotes the printed representation of the atom.

Number
denotes their printed representations.

chars(PrologString)
denotes the string represented by PrologString (a list of character codes).

write(Term)
denotes the string that is printed by the corresponding built-in predicate.

format(Term)
denotes the string that is printed by the corresponding built-in predicate.

dq(Command)
denotes the string specified by Command, enclosed in double quotes.

br(Command)
denotes the string specified by Command, enclosed in braces.

sqb(Command)
denotes the string specified by Command, enclosed in square brackets.

min(Command)
denotes the string specified by Command, immediately preceded by a hyphen.

ListOfCommands
denotes the strings denoted by each element, separated by spaces.

The predicates to use Tcl from Prolog are tcl_new/1, tcl_delete/1, tcl_eval/3, and tcl_event/3.

An example of use with Prolog as master and Tcl as slave, consisting of a GUI to a program which calculates the factorial of a number:

:- use_module(library(tcltk)).

go :-
        tcl_new(X),
        tcl_eval(X,[button,'.b',min(text),dq('Compute!')],_),
        tcl_eval(X,[button,'.c','-text',dq('Quit')],_),
        tcl_eval(X,[entry,'.e1',min(textvariable),'inputval'],_),
        tcl_eval(X,[label,'.l1',min(text),dq('The factorial of ')],_),
        tcl_eval(X,[pack, '.l1','.e1'],_),
        tcl_eval(X,[entry,'.e2',min(textvariable),'outputval'],_),
        tcl_eval(X,[label,'.l2',min(text),dq('is  ')],_),
        tcl_eval(X,[pack, '.l2','.e2'],_),
        tcl_eval(X,[pack,'.b','.c',min(side),'left'],_),
        tcl_eval(X,[bind,'.b','<ButtonPress-1>',
	        br([set,'inputval','$inputval','\n',
		prolog_one_event,
		dq(write(execute(tk_test_aux:factorial('$inputval', 'Outputval')))),
		'\n',
		set, 'outputval','$prolog_variables(Outputval)'])],
		_),
        tcl_eval(X,[bind,'.c','<ButtonPress-1>',
	        br([prolog_one_event,
		dq(write(execute(exit_tk_event_loop)))])],
		_),
        tk_event_loop(X).

Tcl to Prolog

This is the usual way to build a GUI application. The slave, Prolog, behaves as a server that fulfills eventual requests from the master side, Tcl. At some point, during the user interaction with the GUI, an action may take place that triggers the execution of some procedure on the slave side (a form submit, for example). Thus, the slave is invoked, performs a service, and returns the result to the GUI through the socket connection.

This library includes two main specific Tcl commands:

prolog Goal
Goal is a string containing the printed representation of a Prolog goal. The goal will be called in the user module unless it is prefixed with another module name. The call is always deterministic and its can be either of the following:

1, in case of success
The value of any of the variables in the goal that is bound to a term will be returned to Tcl in the array prolog_variables with the variable name as index.

0, if the execution fails
The Prolog exception Tcl exception is raised. The error message will be "Prolog Exception: " appended with a string representation of such exception.

prolog_event Term
Adds the new term to the terms queue. These can be later retrieved through predicates tcl_event/3 and tk_next_event/2.

Additionally, seven extra Tcl commands are defined.

prolog_delete_event
Deletes the first term of the terms queue.

prolog_list_events
Sends all the terms of the terms queue through the event_socket. The last element is end_of_event_list.

prolog_cmd Command
Receives as an argument the Tcl/Tk code, evaluates it and returns through the term_socket the term tcl_error in case of error or the term tcl_result with the result of the command executed. If the command is prolog, upon return, the goal run on the prolog side is received. In order to get the value of the variables, predicates are compared using the unify_term command. Returns 0 when the sript runs without errors, and 1 if there is an error.

prolog_one_event Term
Receives as an argument the term associated to one of the Tk events. Sends the term through the event_socket and waits for its unification. Then unify_term command is called to update the prolog_variables array.

prolog_thread_event Term
Receives as an argument the term associated to one of the Tk events. Sends the term through the event_socket and waits for its unification. Then unify_term command is called to update the prolog_variables array. In this case the term_socket is non blocking.

convert_variables String
Its argument is a string containing symbols that can not be sent through the sockets. This procedure deletes them from the input string and returns the new string.

unify_term Term1 Term2
Unifies Term1 and Term2 and updates the the prolog_variables array.

The predicates to use Prolog from Tcl are tk_event_loop/1, tk_main_loop/1, tk_new/2, and tk_next_event/2.

An example of use with Tcl as master and Prolog as slave, implementing the well known "Hello, world!" dummy program (more can be seen in directory examples):

Prolog side:

:- use_module(library(tcltk)).
:- use_package(classic).
     
hello('Hello, world!').
     
go :-
	tk_new([name('Simple')], Tcl),
	tcl_eval(Tcl, 'source simple.tcl', _),
	tk_main_loop(Tcl),
	tcl_delete(Tcl).

Tcl side (simple.tcl):

label .l -textvariable tvar
button .b -text "Go!" -command {run}
pack .l .b -side top

proc run {} {

    global prolog_variables
    global tvar 

    prolog hello(X)
    set tvar $prolog_variables(X)
}


Usage and interface

Documentation on exports

PREDICATE

Usage:tcl_new(TclInterpreter)

Creates a new interpreter, initializes it, and returns a handle to it in TclInterpreter.

  • Call and exit should be compatible with:
    (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
  • The following properties should hold at call time:
    (term_typing:var/1)TclInterpreter is a free variable.

PREDICATE

Usage:tcl_eval(TclInterpreter,Command,Result)

Evaluates the commands given in Command in the Tcl interpreter TclInterpreter. The result will be stored as a string in Result. If there is an error in Command an exception is raised. The error messages will be Tcl Exception: if the error is in the syntax of the Tcl/Tk code or Prolog Exception:, if the error is in the prolog term.

  • Call and exit should be compatible with:
    (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
    (tcltk:tclCommand/1)Command is a Tcl command.
    (basic_props:string/1)Result is a string (a list of character codes).
  • The following properties should hold at call time:
    (term_typing:nonvar/1)TclInterpreter is currently a term which is not a free variable.
    (term_typing:nonvar/1)Command is currently a term which is not a free variable.
    (term_typing:var/1)Result is a free variable.
Meta-predicate with arguments: tcl_eval(?,?,addmodule(?)).

PREDICATE

Usage:tcl_delete(TclInterpreter)

Given a handle to a Tcl interpreter in variable TclInterpreter, it deletes the interpreter from the system.

  • Call and exit should be compatible with:
    (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
  • The following properties should hold at call time:
    (term_typing:nonvar/1)TclInterpreter is currently a term which is not a free variable.

PREDICATE

Usage:tcl_event(TclInterpreter,Command,Events)

Evaluates the commands given in Command in the Tcl interpreter whose handle is provided in TclInterpreter. Events is a list of terms stored from Tcl by prolog_event. Blocks until there is something on the event queue

  • Call and exit should be compatible with:
    (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
    (tcltk:tclCommand/1)Command is a Tcl command.
    (basic_props:list/1)Events is a list.
  • The following properties should hold at call time:
    (term_typing:nonvar/1)TclInterpreter is currently a term which is not a free variable.
    (term_typing:nonvar/1)Command is currently a term which is not a free variable.
    (term_typing:var/1)Events is a free variable.

REGTYPE

Usage:tclInterpreter(I)

I is a reference to a Tcl interpreter.

    REGTYPE

    Usage:tclCommand(C)

    C is a Tcl command.

      PREDICATE

      Usage:tk_event_loop(TclInterpreter)

      Waits for an event and executes the goal associated to it. Events are stored from Tcl with the prolog command. The unified term is sent to the Tcl interpreter in order to obtain the value of the tcl array of prolog_variables. If the term received does not have the form execute(Goal), the predicate silently exits. If the execution of Goal raises a Prolog error, the interpreter is deleted and an error message is given.

      • Call and exit should be compatible with:
        (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
      • The following properties should hold at call time:
        (term_typing:nonvar/1)TclInterpreter is currently a term which is not a free variable.

      PREDICATE

      Usage:tk_main_loop(TclInterpreter)

      Passes control to Tk until all windows are gone.

      • Call and exit should be compatible with:
        (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
      • The following properties should hold at call time:
        (term_typing:nonvar/1)TclInterpreter is currently a term which is not a free variable.

      PREDICATE

      Usage:tk_new(Options,TclInterpreter)

      Performs basic Tcl and Tk initialization and creates the main window of a Tk application.Options is a list of optional elements according to:

      name(+ApplicationName)
      Sets the Tk main window title to ApplicationName. It is also used for communicating between Tcl/Tk applications via the Tcl send command. Default name is an empty string.

      display(+Display)
      Gives the name of the screen on which to create the main window. Default is normally determined by the DISPLAY environment variable.

      file
      Opens the sript file. Commands will not be read from standard input and the execution returns back to Prolog only after all windows (and the interpreter) have been deleted.

      • Call and exit should be compatible with:
        (basic_props:list/1)Options is a list.
        (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
      • The following properties should hold at call time:
        (term_typing:nonvar/1)Options is currently a term which is not a free variable.
        (term_typing:var/1)TclInterpreter is a free variable.

      PREDICATE

      Usage:tk_next_event(TclInterpreter,Event)

      Processes events until there is at least one Prolog event associated with TclInterpreter. Event is the term correspondig to the head of a queue of events stored from Tcl with the prolog_event command.

      • Call and exit should be compatible with:
        (tcltk:tclInterpreter/1)TclInterpreter is a reference to a Tcl interpreter.
        (basic_props:string/1)Event is a string (a list of character codes).
      • The following properties should hold at call time:
        (term_typing:nonvar/1)TclInterpreter is currently a term which is not a free variable.
        (term_typing:var/1)Event is a free variable.