Perl/Tk has its roots in the X Window System and the Tcl language. So let's take a detour into the pages of history, to give you an idea of where Perl/Tk came from and how it got here.
The X Window System (known to its friends as just "X" or "X11") was first released in 1987 as a graphical platform for Unix systems. Like most Unix software, X applications are almost universally written in the C language, using a library such as Xt, Motif, or (if you were really unlucky or just really brave) the underlying library for X-based applications, Xlib.
Xlib has the advantage that you can do anything, at the expense of dealing with everything. For instance, here's one way to make a simple pull-down menu using Xlib (which is one statement in Tk). First, determine the dimensions of the longest menu item. For argument's sake, assume the menu label string is in the C variable menu_item. Subroutine XTextExtents determines several metrics about menu_item, such as its overall width in pixels in the current font and its pixel height, computed by summing the maximum ascent and descent (the number of pixels above and below the baseline, respectively). After accounting for the number of menu items, border widths, and including some slop for good luck, we arrive at the dimensions of the menu window itself, and its relative (x, y) position in the MainWindow.
XTextExtents( font_info, menu_item, strlen( menu_item ), &direction, &ascent, &descent, &overall ); menu_width = overall.width + 4; menu_pane_height = overall.ascent + overall.descent + 4; menu_height = menu_pane_height * menu_pane_count; x = window_width - menu_width - ( 2 * menu_border_width ); y = 0;
XCreateSimpleWindow draws the menu with the proper border and background colors, although nothing appears on the display because the window hasn't yet been mapped.
theMenu = XCreateSimpleWindow( theDisplay, theWindow, x, y, menu_width, menu_height, menu_border_width, theBorderPixel, theBackgroundPixel );
But every menu item is itself a tiny window, so create them all, save the structure pointers for later use, and select the events they'll respond to. Notice that we haven't drawn the actual text of the menu items. To do that, we need to define font and graphic context items, then call XDrawImageString to paint the characters (that's all done in initialization and event handler code):
for( i = 0; i < menu_pane_count; i++ ) { menu[i].menu_pane = XCreateSimpleWindow( theDisplay, theMenu, 0, menu_height/menu_pane_count*i, menu_width, menu_pane_height, menu_border_width = 1, theForegroundPixel, theBackgroundPixel ); XSelectInput( theDisplay, menu[i].menu_pane, EVENT_MASK3 ); } XMapSubWindows( theDisplay, theMenu );
The symbol EVENT_MASK3 enumerates the events applicable to the menu item windows:
#define EVENT_MASK3 ButtonPresMask | ButtonReleaseMask | ExposureMask | EnterWindowMask | LeaveWindowMask
Now we must write the event handlers, including an Expose handler that actually draws the windows, our own event loop, and even our own event dispatching code, and on and on and on .... Whew!
Programming with higher-level libraries such as Motif or Xt is somewhat more civilized, but it's no walk in the park either. A significant stumbling block was that no matter what library you used, X remained in the clutches of C programmers. C is a fine language, but it kept X in the hands of the professionals—no hobbyists or hackers need apply. If you needed to develop an in-house tool (e.g., for tracking bugs), many companies would balk at spending the time and resources required for developing a C application, so you'd end up with a clunky script with a command-line interface.
Something had to be done, and something was.
The Tool Command Language (Tcl) was developed in 1987 by John K. Ousterhout of the University of California at Berkeley. Ousterhout envisioned an embeddable, extensible command language that many different applications could reuse. Each application would inherit identical basic features such as control structures, scalar variables and arrays, and built-in procedures. In turn, an application would add its unique commands, each of which had the same "feel" as any other Tcl command.[2]
[2] Years earlier, Control Data Corporation carried the concept of an embeddable, extensible command language to a logical conclusion with its operating system, NOS/VE. The command language was called System Command Language (SCL) and as the name implies it was used by the entire operating system, from utilities, compilers, and debuggers, to terminal servers and end-user scripts and applications. Any application could embed any other application—automatically, courtesy of the operating system—without any work from the user. The symmetry and consistency between applications was most amazing.
But Ousterhout needed to prove his ideas, as much to himself as to others. Since he was interested in GUIs, he devised a toolkit of graphical components and tied them together using Tcl. He reasoned this approach would be more cost effective than writing C language code, even using a toolkit like Motif. His hunch was proven correct, bringing us to his next accomplishment: his graphical toolkit called Tk, from which Perl/Tk is derived.
In early 1991, Ousterhout released Tk Version 1.0, the graphical extension to the Tcl scripting language. Tk's high-level widget set (which ultimately uses Xlib as its drawing package) was an immediate hit. In the years following, thousands of Tcl/Tk applications were written and Tk was ported to languages such as Eiffel, Modula-3, Prolog, Python, Scheme, and more.
By November of 1993, Tcl/Tk was at Version 3.4 and, believe it or not, folks were busy pasting Tcl/Tk GUIs on top of their Perl programs. If only we Perlers had known that help was on its way, for that very same month Malcolm Beattie of Oxford University began his TkPerl project.[3]
[3] While TkPerl is no longer available, Malcolm has two CPAN modules that allow you to use Tcl/Tk commands from a Perl script. Of course, they rely on Tcl/Tk libraries, so you need Tcl/Tk installed.
Malcolm's goal was a pure Perl 5, object-oriented interface to Tk without any dependence on Tcl, which meant converting Tcl code to Perl and writing XSUBs so Perl could call Tk C library routines. The marriage of Tk and Perl was complicated further because in those days Tcl/Tk C subroutines passed simple strings back and forth, which didn't fit well with Perl's model of native data types. Nonetheless, by the summer of 1994, TkPerl was available in alpha form for general use, sans the Text widget and a handful of lesser-used commands and bindings.
Here's an early TkPerl "Hello World" program:
use Tk; $mw = tkinit; $b = Button::new($mw, -text => 'Hello World'); $b->configure(-method => sub {exit}); tkpack($b); tkmainloop;
If this looks odd to you, remember it was the state of affairs nearly eight years ago, when TkPerl was alpha, and Perl's object-oriented features were still beta. Notice that pack hadn't yet been turned into a widget method and was renamed tkpack so it didn't conflict with Perl's built-in function by the same name. Yet it worked, and it let us use Tk from Perl, which, after all, was the goal.
Around this time, another chap from the United Kingdom, Nick Ing-Simmons (then of Texas Instruments), began using TkPerl in earnest. He and Malcolm collaborated for a time, and they mutually agreed that Nick would continue development. From this came nTk, or "new Tk," or possibly "Nick's Tk," and thus began the evolution of Perl's Tk programming interface to what it is today. In May 1995, there was another name change, and Nick's package became known as pTk, for "pure Tk," or "portable Tk," or "Perl/Tk." Throughout the years, user-contributed widgets and Ioi Kim Lam's Tk Interface Extension (Tix) widgets found their way into the distribution. These Tks were all based on Tcl/Tk Version 4.x, a version for Unix only.
Remember the Xlib code we showed? Figure 1-1 shows a simple Perl/Tk window.
This window was created with the following Perl one-liner:
perl -MTk -e 'MainWindow->new->Label(-text => "Hello, Perl/Tk")->pack; MainLoop'
This example highlights just how far we've come.
In the meantime, the Tcl/Tk team members weren't resting on their well-deserved laurels. By the summer of 1995, Tcl/Tk 8.x[4] was running on Unix, MacOS classic, and Win32 operating systems, with a look and feel appropriate for each environment. It would take two more years for Perl/Tk to catch up.[5]
[4] There were no Tk 5.x, 6.x, or 7.x versions. Tk jumped from a 4.x version number to 8.x to match the corresponding Tcl version. This made it easier to know which version of Tk matched which Tcl installation.
[5] On Windows, that is; Perl/Tk is still unavailable on Mac OS at the time of this writing.
By the summer of 1997, Gurusamy Sarathy, a well-known and respected Perl porter, had produced a binary distribution of Perl 5.004 and Tk 40x.000 (and other useful modules) specifically for Window 95 and Windows NT. The growth of Perl/Tk took off exponentially. The only major complaint was that a Perl/Tk GUI looked too Motif-like, due to its Unix roots.
Nick, with his prodigious programming abilities, wasn't idling either, for in early 1998 he'd merged all of Perl/Tk, Tix, Jan Nijtmans' image package, and Tcl/Tk 8.0, thus creating the basis for the current Perl/Tk 800.000 series.
Simultaneously, Sarathy was heading the effort to combine the disparate Perl ports into a unified Unix and Win32 distribution, commonly called Oneperl. Finally, in the summer of 1998, we had one Perl, 5.005, for Unix and Win32. ActiveState Corporation distributes this unified Perl in binary form, used on most Win32 systems these days.
Around July 1998, Nick produced a unified Unix and Win32 Perl/Tk distribution, and placed a binary version of Perl/Tk 800.010 in ActiveState's PPM repository. The result is that Win32 users can simply download binary installation packages of Perl and Tk. For most Unix users, using a simple idiom, you compile Perl and Tk yourself. If you're really lucky, you can search the Web and find a binary distribution of Perl/Tk for your particular flavor of Unix.
Running Perl/Tk Programs on Win32
There are no differences between writing Perl/Tk applications on Unix or Windows machines. You can use any simple text editor on either system. However, there can be a small difference in the way you run them.
The lowest common denominator is to manually invoke Perl and specify the Perl/Tk program filename on the command line, like this:
perl myprog.plA Unix user commonly gives his program execute permission and ensures that the first line of the program is a valid "bang" line. This allows the user to invoke Perl/Tk programs by name. When invoking a program by name, the Unix command processor, called the shell program, inspects the file's first line and, if it begins with the characters #!, treats the remainder of the line as the command to execute, possibly with arguments. The ! character is the bang. A line of this form invokes Perl with the -w switch:
#!/usr/local/bin/perl -wConceptually, Win32 users do the same thing by associating the extension .pl with the Perl interpreter, so they can use Explorer and double-click the script to execute it. See Appendix A, "Installing Perl/Tk" for more details.