1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
|
@c Copyright (c) 1994 William Schelter.
@node General, Widgets, Top, Top
@chapter General
@menu
* Introduction::
* Getting Started::
* Common Features of Widgets::
* Return Values::
* Argument Lists::
* Lisp Functions Invoked from Graphics::
* Linked Variables::
* tkconnect::
@end menu
@node Introduction, Getting Started, General, General
@section Introduction
@b{GCL-TK} is a windowing interface for @b{GNU Common Lisp}. It provides the
functionality of the @b{TK} widget set, which in turn implements a widget
set which has the look and feel of @b{Motif}.
The interface allows the user to draw graphics, get input from menus,
make regions mouse sensitive, and bind lisp commands to regions. It
communicates over a socket with a @file{gcltksrv} process, which speaks to the
display via the @b{TK} library. The displaying process may run on
a machine which is closer to the display, and so involves less
communication. It also may remain active even though the lisp is
involved in a separate user computation. The display server can, however,
interrupt the lisp at will, to inquire about variables and run
commands.
The user may also interface with existing @code{TCL/TK} programs,
binding some buttons, or tracking some objects.
The size of the program is moderate. In its current form it adds only
about 45K bytes to the lisp image, and the @file{gcltksrv} program uses shared
libraries, and is on the order of 150Kbytes on a sparc.
This chapter describes some of the common features of the command
structure of widgets, and of control functions. The actual functions
for construction of windows
are discussed in @ref{Widgets}, and more general functions
for making them appear, lowering them, querying about them in @ref{Control}.
@node Getting Started, Common Features of Widgets, Introduction, General
@section Getting Started
Once @b{GCL} has been properly installed you should be able to do the
following simple example:
@example
(in-package "TK")
(tkconnect)
(button '.hello :text "Hello World" :command '(print "hi"))
==>.HELLO
(pack '.hello)
@end example
We first switched to the "TK" package, so that functions like button
and pack would be found.
After doing the tkconnect, a window should appear on your screen, see @xref{tkconnect}.
The invocation of the function @code{button} creates a new function
called @code{.hello} which is a @i{widget function}. It is then
made visible in the window by using the @code{pack} function.
You may now click on the little window, and you should see the command
executed in your lisp. Thus "hi" should be printed in the lisp
window. This will happen whether or not you have a job running in
the lisp, that is lisp will be interrupted and your command will run,
and then return the control to your program.
The function @code{button} is called a widget constructor, and the
function @code{.hello} is called a widget. If you have managed to
accomplish the above, then @b{GCL} is probably installed correctly, and you
can graduate to the next section! If you dont like reading but prefer
to look at demos and code, then you should look in the demos directory,
where you will find a number of examples. A monitor for the garbage
collector (mkgcmonitor), a demonstration of canvas widgets (mkitems),
a sample listbox with scrolling (mklistbox).
@node Common Features of Widgets, Return Values, Getting Started, General
@section Common Features of Widgets
A @i{widget} is a lisp symbol which has a function binding. The
first argument is always a keyword and is called the @i{option}.
The argument pattern for the remaining arguments depends on the
@i{option}. The most common @i{option} is @code{:configure} in
which case the remaining arguments are alternating keyword/value
pairs, with the same keywords being permitted as at the creation
of the widget.
A @i{widget} is created by means of a @i{widget constructor}, of
which there are currently 15, each of them appearing as the title of a
section in @ref{Widgets}. They live in the @code{"TK"} package, and for
the moment we will assume we have switched to this package. Thus for
example @code{button} is such a widget constructor function. Of course
this is lisp, and you can make your own widget constructors, but when
you do so it is a good idea to follow the standard argument patterns
that are outlined in this section.
@example
(button '.hello)
==> .HELLO
@end example
@noindent
creates a @i{widget} whose name is @code{.hello}. There is a parent child
hierarchy among widgets which is implicit in the name used for the
widget. This is much like the pathname structure on a Unix or Dos
file system, except that @code{'.'} is used as the separator rather
than a @code{/} or @code{\}. For this reason the widget instances
are sometimes referred to as @i{pathnames}. A child of the
parent widget @code{.hello} might be called @code{.hello.joe}, and
a child of this last might be @code{.hello.joe.bar}. The parent of
everyone is called @code{.} . Multiple top level windows are created
using the @code{toplevel} command (@pxref{toplevel}).
The widget constructor functions take keyword and value pairs, which
allow you to specify attributes at the time of creation:
@example
(button '.hello :text "Hello World" :width 20)
==>.HELLO
@end example
@noindent
indicating that we want the text in the button window to be
@code{Hello World} and the width of the window to be 20 characters
wide. Other types of windows allow specification in centimeters
@code{2c}, or in inches (@code{2i}) or in millimeters @code{2m}
or in pixels @code{2}. But text windows usually have their
dimensions specified as multiples of a character width and height.
This latter concept is called a grid.
Once the window has been created, if you want to change the
text you do NOT do:
@example
(button '.hello :text "Bye World" :width 20)
@end example
This would be in error, because the window .hello already exists.
You would either have to first call
@example
(destroy '.hello)
@end example
But usually you just want to change an attribute. @code{.hello} is
actually a function, as we mentioned earlier, and it is this function
that you use:
@example
(.hello :configure :text "Bye World")
@end example
This would simply change the text, and not change where the window had
been placed on the screen (if it had), or how it had been packed
into the window hierarchy. Here the argument @code{:configure} is
called an @i{option}, and it specifies which types of keywords can
follow it. For example
@example
(.hello :flash)
@end example
@noindent
is also valid, but in this case the @code{:text} keyword is not permitted
after flash. If it were, then it would mean something else besides
what it means in the above. For example one might have defined
@example
(.hello :flash :text "PUSH ME")
@end example
@noindent
so here the same keyword @code{:text} would mean something else, eg
to flash a subliminal message on the screen.
We often refer to calls to the widget functions
as messages. One reason for this is that they actually turn into
messages to the graphics process @file{gcltksrv}. To actually see these
messages you can do
@example
(debugging t).
@end example
@node Return Values, Argument Lists, Common Features of Widgets, General
@section Return Values
@subsection Widget Constructor Return Values
On successful completion, the widget constructor functions return the
symbol passed in as the first argument. It will now have a functional
binding. It is an error to pass in a symbol which already corresponds
to a widget, without first calling the @code{destroy} command. On failure,
an error is signalled.
@subsection Widget Return Values
The @i{widget} functions themselves, do not normally return any value.
Indeed the lisp process does not wait for them to return, but merely
dispatches the commands, such as to change the text in themselves.
Sometimes however you either wish to wait, in order to synchronize, or
you wish to see if your command fails or succeeds. You request values
by passing the keyword :return and a value indicating the type.
@example
(.hello :configure :text "Bye World" :return 'string)
==> ""
==> T
@end example
@noindent
the empty string is returned as first value, and the second value
@code{T} indicates that the new text value was successfully set. LISP
will not continue until the tkclsrv process indicates back that the
function call has succeeded. While waiting of course LISP will continue
to process other graphics events which arrive, since otherwise a
deadlock would arise: the user for instance might click on a mouse, just after
we had decided to wait for a return value from the @code{.hello} function.
More generally a user program may be running in @b{GCL} and be interrupted
to receive and act on communications from the @file{gcltksrv}
process. If an error occurred then the second return value of the
lisp function will be NIL. In this case the first value, the string
is usually an informative message about the type of error.
A special variable @code{tk::*break-on-errors*} which if not
@code{nil}, requests that that @b{LISP} signal an error when a message
is received indicating a function failed. Whenever a command fails,
whether a return value was requested or not, @file{gcltksrv} returns a
message indicating failure. The default is to not go into the
debugger. When debugging your windows it may be convenient however to
set this variable to @code{T} to track down incorrect messages.
The @file{gcltksrv} process always returns strings as values.
If @code{:return} @i{type} is specified, then conversion to @i{type}
is accomplished by calling
@example
(coerce-result @i{return-string} @i{type})
@end example
Here @i{type} must be a symbol with a @code{coercion-functions}
property.
The builtin return types which may be requested are:
@table @code
@item T
in which case
the string passed back from the @file{gcltksrv} process, will be read by the
lisp reader.
@item number
the string is converted to a number using the current *read-base*
@item list-strings
@example
(coerce-result "a b @{c d@} e" 'list-strings)
==> ("a" "b" "c d" "e")
@end example
@item boolean
(coerce-result "1" 'boolean)
==> T
(coerce-result "0" 'boolean)
==> NIL
@end table
The above symbols are in the @code{TK} or @code{LISP} package.
It would be possible to add new types just as the @code{:return t}
is done:
@example
(setf (get 't 'coercion-functions)
(cons #'(lambda (x) (our-read-from-string x 0))
#'(lambda (x) (format nil "~s" x))))
@end example
The @code{coercion-functions} property of a symbol, is a cons whose
@code{car} is the coercion form from a string to some possibly different
lisp object, and whose @code{cdr} is a function which builds a string
to send to the graphics server. Often the two functions are inverse
functions one of the other up to equal.
@subsection Control Function Return Values
The @i{control} functions (@pxref{Control}) do not return a value
or wait unless requested to do so, using the @code{:return} keyword.
The types and method of specification are the same as for the
Widget Functions in the previous section.
@example
(winfo :width '.hello :return 'number)
==> 120
@end example
@noindent
indicates that the @code{.hello} button is actually 120 pixels
wide.
@node Argument Lists, Lisp Functions Invoked from Graphics, Return Values, General
@section Argument Lists
@subsection Widget Functions
The rule is that the first argument for a widget function is a keyword,
called the @i{option}. The pattern of the remaining arguments depends
completely
on the @i{option} argument. Thus
@example
(.hello @i{option} ?arg1? ?arg2? ...)
@end example
One @i{option} which is permitted for every widget function is
@code{:configure}. The argument pattern following it is the same
keyword/value pair list which is used in widget creation. For a
@code{button} widget, the other valid options are @code{:deactivate},
@code{:flash}, and @code{:invoke}. To find these, since
@code{.hello} was constructed with the @code{button} constructor, you
should see @xref{button}.
The argument pattern for other options depends completely on the option
and the widget function.
For example if @code{.scrollbar} is a scroll bar window, then the option
@code{:set} must be followed by 4 numeric arguments, which indicate how
the scrollbar should be displayed, see @xref{scrollbar}.
@example
(.scrollbar :set a1 a2 a3 a4)
@end example
If on the other hand @code{.scale} is a scale (@pxref{scale}), then we have
@example
(.scale :set a1 )
@end example
@noindent
only one numeric argument should be supplied, in order to position the
scale.
@subsection Widget Constructor Argument Lists
These are
@example
(widget-constructor @i{pathname} :keyword1 value1 :keyword2 value2 ...)
@end example
@noindent
to create the widget whose name is @i{pathname}. The possible keywords
allowed are specified in the corresponding section of @xref{Widgets}.
@subsection Concatenation Using `:' in Argument List
What has been said so far about arguments is not quite true. A
special string concatenation construction is allowed in argument lists
for widgets, widget constructors and control functions.
First we introduce the function @code{tk-conc} which takes an arbitrary
number of arguments, which may be symbols, strings or numbers, and
concatenates these into a string. The print names of symbols are
converted to lower case, and package names are ignored.
@example
(tk-conc "a" 1 :b 'cd "e") ==> "a1bcde"
@end example
One could use @code{tk-conc} to construct arguments for widget
functions. But even though @code{tk-conc} has been made quite
efficient, it still would involve the creation of a string. The
@code{:} construct avoids this. In a call to a widget function,
a widget constructor, or a control function you may remove the call to
@code{tk-conc} and place @code{:} in between each of its arguments.
Those functions are able to understand this and treat the extra
arguments as if they were glued together in one string, but without
the extra cost of actually forming that string.
@example
(tk-conc a b c .. w) <==> a : b : c : ... w
(setq i 10)
(.hello :configure :text i : " pies")
(.hello :configure :text (tk-conc i " pies"))
(.hello :configure :text (format nil "~a pies" i))
@end example
The last three examples would all result in the text string being
@code{"10 pies"}, but the first method is the most efficient.
That call will be made with no string or cons creation. The
@b{GC Monitor} example, is written in such a way that there is no
creation of @code{cons} or @code{string} types during normal operation.
This is particularly useful in that case, since one is trying to
monitor usage of conses by other programs, not its own usage.
@node Lisp Functions Invoked from Graphics, Linked Variables, Argument Lists, General
@section Lisp Functions Invoked from Graphics
It is possible to make certain areas of a window mouse sensitive,
or to run commands on reception of certain events such as keystrokes,
while the focus is in a certain window. This is done by having
a lisp function invoked or some lisp form evaluated. We shall
refer to such a lisp function or form as a @emph{command}.
For example
@example
(button '.button :text "Hello" :command '(print "hi"))
(button '.jim :text "Call Jim" :command 'call-jim)
@end example
In the first case when the window @code{.button} is clicked on, the
word "hi" will be printed in the lisp to standard output. In the
second case @code{call-jim} will be funcalled with no arguments.
A command must be one of the following three types. What happens
depends on which type it is:
@table @samp
@item function
If the value satisfies @code{functionp} then it will be called with
a number of arguments which is dependent on the way it was bound,
to graphics.
@item string
If the command is a string, then it is passed directly to @b{TCL/TK}
for evaluation on that side. Lisp will not be required for the
evaluation when the command is invoked.
@item lisp form
Any other lisp object is regarded as a lisp form to be eval'd, and
this will be done when the command is invoked.
@end table
The following keywords accept as their value a command:
@example
:command
:yscroll :yscrollcommand
:xscroll :xscrollcommand
:scrollcommand
:bind
@end example
@noindent
and in addition @code{bind} takes a command as its third argument,
see @xref{bind}.
@c todo!!
Below we give three different examples using the 3 possibilities for
a command: functionp, string, and lisp form. They all accomplish
exactly the same thing.
For given a frame @code{.frame} we could construct a listbox
in it as:
@example
(listbox '.frame.listbox :yscroll 'joe)
@end example
Then whenever the listbox view position changes, or text is inserted,
so that something changes, the function @code{joe} will be invoked with 4
arguments giving the totalsize of the text, maximum number of units
the window can display, the index of the top unit, and finally the
index of the bottom unit. What these arguments are is specific
to the widget @code{listbox} and is documented @xref{listbox}.
@code{joe} might be used to do anything, but a common usage is to have
@code{joe} alter the position of some other window, such as a scroll
bar window. Indeed if @code{.scrollbar} is a scrollbar then
the function
@example
(defun joe (a b c d)
(.scrollbar :set a b c d))
@end example
@noindent
would look after sizing the scrollbar appropriately for the percentage
of the window visible, and positioning it.
A second method of accomplishing this identical, using a string (the
second type of command),
@example
(listbox '.frame.listbox :yscroll ".scrollbar set")
@end example
@noindent
and this will not involve a call back to lisp. It uses the fact that
the @b{TK} graphics side understands the window name @code{.scrollbar} and
that it takes the @i{option} @code{set}. Note that it does not get
the @code{:} before the keyword in this case.
In the case of a command which is a @i{lisp form} but is not installed
via @code{bind} or @code{:bind}, then the form will be installed as
@example
#'(lambda (&rest *arglist*) @i{lisp-form})
@end example
@noindent
where the @i{lisp-form} might wish to access the elements of the special
variable @code{*arglist*}. Most often this list will be empty, but for
example if the command was setup for @code{.scale} which is a @i{scale},
then the command will be supplied one argument which is the new numeric
value which is the scale position. A third way of accomplishing the
scrollbar setting using a lisp form is:
@example
(listbox '.frame.listbox :yscroll '(apply '.scrollbar :set *arglist*))
@end example
The @code{bind} command and @code{:bind} keyword, have an additional
wrinkle, see @xref{bind}. These are associated to an event in a
particular window, and the lisp function or form to be evaled must have
access to that information. For example the x y position, the window
name, the key pressed, etc. This is done via @i{percent symbols} which
are specified, see @xref{bind}.
@example
(bind "Entry" "<Control-KeyPress>" '(emacs-move %W %A ))
@end example
@noindent
will cause the function emacs-move to be be invoked whenever a control
key is pressed (unless there are more key specific or window specific
bindings of said key). It will be invoked with two arguments, the
first %W indicating the window in which it was invoked, and the second
being a string which is the ascii keysym which was pressed at the same
time as the control key.
These @i{percent constructs} are only permitted in commands which are
invoked via @code{bind} or @code{:bind}. The lisp form which is passed
as the command, is searched for the percent constructs, and then a
function
@example
#'(lambda (%W %A) (emacs-move %W %A))
@end example
@noindent
will be invoked with two arguments, which will be supplied by the
@b{TK} graphics server, at the time the command is invoked. The
@code{*arglist*} construct is not available for these commands.
@node Linked Variables, tkconnect, Lisp Functions Invoked from Graphics, General
@section Linked Variables
It is possible to link lisp variables to @b{TK} variables. In general
when the @b{TK} variable is changed, by for instance clicking on a
radiobutton, the linked lisp variable will be changed. Conversely
changing the lisp variable will be noticed by the @b{TK} graphics side, if
one does the assignment in lisp using @code{setk} instead of
@code{setq}.
@example
(button '.hello :textvariable '*message* :text "hi there")
(pack '.hello)
@end example
This causes linking of the global variable @code{*message*} in lisp
to a corresponding variable in @b{TK}. Moreover the message that is in
the button @code{.hello} will be whatever the value of this global
variable is (so long as the @b{TK} side is notified of the change!).
Thus if one does
@example
(setk *message* "good bye")
@end example
@noindent
then the button will change to have @i{good bye} as its text.
The lisp macro @code{setk} expands into
@example
(prog1 (setf *message* "good bye") (notice-text-variables))
@end example
@noindent
which does the assignment, and then goes thru the linked variables
checking for those that have changed, and updating the @b{TK} side should
there be any. Thus if you have a more complex program which might
have done the assignment of your global variable, you may include
the call to @code{notice-text-variables} at the end, to assure that
the graphics side knows about the changes.
A variable which is linked using the keyword @code{:textvariable} is
always a variable containing a string.
However it is possible to have other types of variables.
@example
(checkbutton '.checkbutton1 :text "A button" :variable '(boolean *joe*))
(checkbutton '.checkbutton2 :text "A button" :variable '*joe*)
(checkbutton '.checkbutton3 :text "Debugging" :variable '(t *debug*)
:onvalue 100 :offvalue -1)
@end example
The first two examples are the same in that the default variable type
for a checkbutton is @code{boolean}. Notice that the specification of a
variable type is by @code{(@i{type} variable)}. The types which are
permissible are those which have coercion-fucntions, @xref{Return
Values}. In the first example a variable @code{*joe*} will be linked, and
its default initial value will be set to nil, since the default initial
state of the check button is off, and the default off value is nil.
Actually on the @b{TK} side, the corresponding boolean values are @code{"1"}
and @code{"0"}, but the @code{boolean} type makes these become @code{t}
and @code{nil}.
In the third example the variable *debug* may have any lisp value (here
@i{type} is @code{t}). The initial value will be made to be @code{-1},
since the checkbutton is off. Clicking on @code{.checkbutton3} will
result in the value of @code{*debug*} being changed to 100, and the light
in the button will be toggled to on, @xref{checkbutton}. You may
set the variable to be another value besides 100.
You may also call
@example
(link-text-variable '*joe* 'boolean)
@end example
@noindent
to cause the linking of a variable named *joe*. This is done
automatically
whenever the variable is specified after one of the keys
@example
:variable :textvariable.
@end example
Just as one must be cautious about using global variables in lisp, one
must be cautious in making such linked variables. In particular note
that the @b{TK} side, uses variables for various purposes. If you make a
checkbutton with pathname @code{.a.b.c} then unless you specify a
@code{:variable} option, the variable @code{c} will become associated to
the @b{TK} value of the checkbutton. We do NOT link this variable by
default, feeling that one might inadvertently alter global variables,
and that they would not typically use the lisp convention of being of
the form @code{*c*}. You must specify the @code{:variable} option, or
call @code{link-variable}.
@node tkconnect, , Linked Variables, General
@section tkconnect
@example
@i{tkconnect} &key host display can-rsh gcltksrv
@end example
This function provides a connection to a graphics server process, which
in turn connects to possibly several graphics display screens. The
graphics server process, called @file{gcltksrv} may or may not run
on the same machine as the lisp to which it is attached.
@code{display}
indicates the name of the default display to connect to, and this
in turn defaults to the value of the environment variable @code{DISPLAY}.
When @i{tkconnect} is invoked, a socket is opened and it waits for
a graphics process to connect to it. If the host argument is not
supplied, then a process will be spawned which will connect back to
the lisp process. The name of the command for invoking the process
is the value of the @file{gcltksrv} argument, which defaults to
the value of the environment variable @code{GCL_TK_SERVER}. If that variable
is not set, then the lisp @code{*lib-directory*} is searched for
an entry @file{gcl-tk/gcltksrv}.
If @code{host} is supplied, then a command to run on the remote machine
will be printed on standard output. If @code{can-rsh} is not nil,
then the command will not be printed, but rather an attempt will be
made to rsh to the machine, and to run the command.
Thus
@example
(tkconnect)
@end example
@noindent
would start the process on the local machine, and use for @code{display}
the value of the environment variable @code{DISPLAY}.
@example
(tkconnect :host "max.ma.utexas.edu" :can-rsh t)
@end example
@noindent
would cause an attempt to rsh to @code{max} and to run the command
there, to connect back to the appropriate port on the localhost.
You may indicate that different @i{toplevel} windows be on different
displays, by using the @code{:display} argument when creating the
window, @xref{toplevel}.
Clearly you must have a copy of the program @file{gcltksrv} and @b{TK}
libraries installed on the machine where you wish to run the server.
|