TweetFollow Us on Twitter

A platform for protecting mail servers.

Volume Number: 20 (2004)
Issue Number: 6
Column Tag: Programming

QuickTime Toolkit

by Tim Monroe

Tickle Me

Developing QuickTime Applications with Tcl/Tk


Tcl/Tk is a combination of two distinct elements: Tcl, which is a string-oriented scripting language and runtime library, and Tk, which is a toolkit for constructing graphical user interfaces. These elements were designed and implemented more or less concurrently at U.C. Berkeley beginning in 1988 by a team led by John Ousterhout. His goal was to develop an extensible language that various software tools could use to control the execution and processing of commands. Indeed, "Tcl" is an acronym for Tool Command Language (and is usually pronounced "tickle").

One distinctive feature of Tcl/Tk -- at least compared with the development environments we've considered in the past dozen articles -- is that its source code is publicly available and largely free of restrictions on its use. This has several important consequences. First, it means that Tcl can easily be embedded into an existing application to provide a scripting interface for that application; if necessary, Tk can also be embedded into that application to provide a graphical user interface. Second, it means that new capabilities can easily be added to Tcl and Tk by defining new commands and GUI objects. For present purposes, we'll be interested in a Tcl/Tk add-on called QuickTimeTcl, which allows us to work with QuickTime movies in a Tcl/Tk application. QuickTimeTcl is also freely available and can be incorporated into commercial and non-commercial products.

In this article and the next, I want to take a look at using Tcl/Tk and QuickTimeTcl to develop QuickTime applications. We'll construct an application, called TickLeez, that can open, display, edit, and play one or more QuickTime movies, while permitting all the standard sorts of user interaction. In this first article, we'll begin with an overview look at Tcl, Tk, and QuickTimeTcl. Then we'll see how to start up a Tcl/Tk application, how to construct and handle our application's menus, how to display dialog boxes, and how to open a QuickTime movie in a window. In the next article, we'll continue our investigation by seeing how to handle movie editing and document-related tasks.

All three important elements -- Tcl, Tk, and QuickTimeTcl -- are available for both Macintosh and Windows operating systems. We'll write our application script so that it is aware of the operating environment and behaves appropriately on each platform. As we saw in our previous articles on QuickTime for Java (in MacTech, January, February, and March 2004), this mainly involves making sure that the menus are arranged correctly (for instance, putting the Quit menu item in the File menu on Windows and in the Application menu on Mac OS X). There are also several other minor issues that require different treatment on each operating system. On the whole, however, we'll see that Tk, like Java's AWT and Swing, provides a very usable platform-independent graphical toolkit that allows us to script user interface objects with little or no concern as to whether they are being displayed on Mac or Windows computers.

Tcl Overview

As already noted, Tcl is a scripting language used by tools for processing commands. Tcl is refreshingly simple and readable, particularly when compared with other popular scripting languages (for instance, Perl). It's a procedural language that has a predominately C-like syntax. Tcl does not provide any object-oriented primitives, but there is an object-oriented extension of Tcl, called "[incr tcl]". (You'll learn shortly what the name signifies.) In these articles, we'll be content to work with standard Tcl.

Getting Started

A Tcl script is a series of one or more commands, each of which has this structure:

command arguments

The number of arguments is determined by the specific command. For instance, we can print the phrase "hello, world" with this line of script:

puts stdout "hello, world"

Here "puts" is the command, and "stdout" and "hello, world" are the two arguments for the command. Notice that the second argument is the entire 12-character sting enclosed by the quotation marks ("").

We can assign a value to a variable using the set command, and we can read a variable's current value by prefixing the $ character. For instance:

set message "hello, world"
puts stdout $message

These two lines produce exactly the same output as the single line shown above.

We can prevent substitution of variable values by prefixing the $ character with a backslash:

puts stdout \$message

This will produce the output "$message". Alternatively, we can use braces to delimit arguments whose variables are not to be substituted:

puts stdout {$message}

Once again, this will produce the output "$message".

Braces can also be used to delimit the names of variables when the variable name is embedded within a longer string. For instance:

puts stdout ${message}ling

This will produce the output "hello, worldling".

Evaluating Commands

A command occurring by itself on a line is evaluated and any value the command produces is returned as the command result. It's also possible to nest commands on a single line, using brackets. Here's an example:

   set x [expr [winfo screenwidth .myWindow]/2 - 180]

Here we call two nested commands, winfo (a Tk command that retrieves the specified information about a window, in this case the width of the screen that contains the window .myWindow) and expr (a Tcl command that evaluates the expression passed to it). Once this command line is executed, the variable x will contain the horizontal position at which we should position a window that is 360 pixels wide if we want to center it on the screen.

Tcl provides a large number of built-in commands. We've already encountered the set, puts, and expr commands. A handful of additional Tcl commands are unset, if, while, switch, array, and return. The incr command increments the value of a variable by a specified amount, or by 1 if no amount is specified. Thus, if the value of the variable xyz is 10, then the following command will set the value of xyz to 11:

incr xyz

In Tcl, any built-in commands can be redefined. In the following article, we'll need to redefine the built-in command exit to allow TickLeez a chance to clean up before the application terminates.

Defining Procedures

We can define procedures in Tcl using the proc command. The general form of a procedure definition is this:

proc name {arguments} {commands}

For instance, Listing 1 defines two procedures, min and max, which return the smaller or larger of the two values passed in as arguments.

Listing 1: Getting greater and lesser values

max, min
proc max {a b} {
   if {$a > $b} {set a} else {set b}
proc min {a b} {
   if {$a < $b} {set a} else {set b}

Notice that the argument list is enclosed in braces, to delay evaluation of the arguments until the procedure is called. Notice also that a value is returned to the caller as the side effect of executing the set command. (A procedure's return value is the return value of the last command executed in the procedure.) We could just as easily write the min procedure like this, which uses the return command:

proc min {a b} {
   if {$a < $b} {return $a} else {return $b}

There is one final item to keep in mind: there must be a space following the right brace that encloses the argument list; otherwise the Tcl interpreter will complain that there are extra characters after the closing brace.

Using Structured Data

The basic data type in Tcl is the string; all arguments are passed as strings, although certain commands (for instance incr) may interpret their input numerically. Tcl also provides two ways to combine strings into structures: lists and arrays. A list is roughly equivalent to a string whose elements are separated from one another by white space. Tcl provides a large number of commands to create and operate on lists, including list, lindex, llength, lappend, concat, and split. List indices start at 0; the word end can be used to pick out the last element in a list.

For large collections of data elements, it's often easier to use an array, which is a variable whose values are addressed using a string index. (Tcl arrays are also called associative arrays, dictionaries, or hashes.) In TickLeez, we will employ arrays extensively. In particular, we will store six pieces of global application data in an array called appData. The array element appData(winNo) will contain the number of the next window to open; we'll use this information to construct a unique internal name that identifies that window. The array element appData(nextNewWinNo) will contain the number of the next new window to open; we'll use this information to construct a movie name of the form "". The array element appData(os) will contain a string that identifies the current operating system. The array element appData(modKey) will contain the name of the OS-specific modifier key (namely, either "Command" or "Control"). The array element appData(winTag) will contain a unique tag we use to construct the names of our movie windows. Finally, the array element appData(tempDir) will contain the full pathname of a directory that holds any temporary files we need to create.

We'll also need to associate some data with each movie window that we open. For instance, we'll need to maintain information about the movie contained in a window, such as its edited state or the pathname of the file it was loaded from. Unfortunately, Tk does not provide a standard means to attach a list or array to a specific window (as we could do using the functions SetWRefCon and SetWindowLong in our C-based applications). We can work around this limitation by storing that data in the appData global associative array using array indices that contain the window's name. For instance, if the winName variable contains the name of a specific window, then we can use the string "$winName,fileName" as an index into the appData array; the value associated with that index is the full pathname of the movie file.

We'll use this little trick to store five pieces of information in the appData array for each open movie. The array element appData($winName,movie) will contain the QuickTimeTcl identifier for the movie. The array element appData($winName,dirty) will contain the character "1" or "0", indicating whether the movie has been edited or not. The array element appData($winName,undoLevel) will contain the undo level for the movie (that is, the number of undoable edits that have been applied to the movie). Finally, the array element appData($winName,undoOp,n) will contain a string indicating which edit operation was applied a the undo level n. We'll use that string to set the text of the Undo menu item, as we'll see in the next article.

In order for the elements of the appData associative array to be visible throughout our application, we need to include the following line at the beginning of any procedure that accesses the data in that array:

global appData

Note that we could have used individual variable names for the six pieces of global application data; by collecting them all into one array, we reduce the number of global statements we need to use in each procedure.

Tk Overview

Tk (short for "Toolkit" and usually pronounced "tee-kay") is a toolkit for constructing graphical user interfaces. We can use it to create and display the windows, alert boxes, dialog boxes, menus, and other visible elements of our application. Moreover, Tk handles events and user actions involving the elements in those windows, dialog boxes, and menus. In other words, it provides event-driven control flow for our applications. Originally Tk was designed to work in conjunction with the X Windowing System, but subsequently it has been modified to support other graphical user interface systems, including those on Mac OS and Windows. On Mac OS X, Tk uses the Aqua interface, although it currently has a few drawing and event-handling glitches.

Creating Windows

In Tk parlance, a widget is any visible user interface element. In TickLeez, we'll be mainly concerned with three kinds of widgets: windows, menus, and movies. It's very easy to create a new window. Here's part of the code we'll use to create our application's About box:

toplevel .about -width 360 -height 160

The toplevel command creates a new toplevel window, in this case one that is 360 by 160 pixels. The first argument to the toplevel command is the name of the new window. In Tk, widgets are arranged in a hierarchy, the root of which is a toplevel window whose name is ".". All new widgets must have names that are relative to some existing widget. In particular, all widgets must begin with the "." character. As you can see, the name of our About box is ".about".

The names of windows are reasonably arbitrary, as long as they too begin with the "." character. To make it easy to find all and only the movie windows, let's give all our movie windows names of the form ".winRTMn", for some integer n. So the first movie window we create will have the name ".winRTM1"; the second will be ".winRTM2", and so on. As noted earlier, the array element appData(winNo) holds the next available window number, so we can generate a movie window name like this:

set winName $appData(winTag)[incr appData(winNo)]

Based on this naming scheme, we can tell whether a given window is a movie window by passing its name to the isMovieWindow procedure, shown in Listing 2. isMovieWindow just looks to see whether the winName argument begins with the string "winRTM".

Listing 2: Finding movie windows

proc isMovieWindow {winName} {
   global appData
   if {[string first $appData(winTag) $winName] == 0} {
      return 1
   } else {
      return 0

An alternative strategy is to set a movie window's class by including the "-class RTM" option when we create the movie window. In that case, the if line in Listing 2 would look like this:

   if {[string equal [winfo class .$winName] RTM]} {

In a large application with many kinds of windows, using window classes is probably preferable. In TickLeez, since we display only movie windows and the About box, we'll stick with the method that uses a set of special window names.

We can find the frontmost movie window by calling the topMovieWindow procedure defined in Listing 3. First we create a list of all open toplevel windows by executing the wm stackorder command. Then we look at each window, from top to bottom, until we find one that satisfies the isMovieWindow procedure.

Listing 3: Finding the frontmost movie window

proc topMovieWindow {} {
   global appData
   set winlist [wm stackorder .]
   set index [expr [llength $winlist] - 1]
   while {![isMovieWindow [string range \
      [lindex $winlist $index] 1 end]] && ($index >= 0)} {
      incr index -1
   return [string range [lindex $winlist $index] 1 end]

The calls to range chop off the first character of the specified list element (that is, "."). If no movie windows are open, topMovieWindow returns an empty string.

Creating Menu Bars and Menus

We can use Tk to create and manage menu bars and menus, which can contain standard menu items, separator lines, checkbutton items, and radiobutton items. A checkbutton menu item toggles between two states, and radiobutton menu items are organized into groups such that exactly one item in the group is selected at any time. Menu items are in fact just buttons that behave in specific ways and that are grouped into menus.

A menu bar is always associated with a specific toplevel window; this means that we'll need to create a menu bar and a set of menus for each movie window opened by TickLeez. On Windows computers, the menu bar is contained in the movie window itself, as shown in Figure 1. On Macintosh computers, the menu bar is drawn at the top of the main screen, as usual.

Figure 1: A movie window displayed by TickLeez (Windows)

A menu bar is in fact itself a menu. In Tk this is known as a cascading menu, since the items of the menu cascade from left to right. We create a menu bar by executing the menu command:

set bar [menu ${w}mbar -tearoff 0]

Here the variable w is assumed to be the full name of a window. So, for instance, the movie window whose name is ".winRTM1" would have an associated menu bar whose name is ".winRTM1mbar". We associate a menu bar with a window like this:

$w configure -menu $bar

On Macintosh computers, we will create a menu bar and set of menus for the root window ".", even though we hide the root window during application startup. This allows TickLeez to display a menu bar even when no movie windows are open. On Windows, we don't create a menu bar and set of menus for the root window; instead, we create a new empty movie window (Figure 2) when the application starts up; the user can use the menus in that window to open movie files. (We'll see the code that does all this a bit later, in Listing 7.)

Figure 2: A new movie window displayed by TickLeez (Windows)

We can add menus to the menu bar with the add cascade command. Here's how we'll create a File menu and add it to the menu bar:

set m [menu $bar.file -tearoff 0]
$bar add cascade -label "File" -menu $m

And we can add menu items to a menu with the menu's add command command. Here's how we'll add the New item to the File menu:

$m add command -label "New" \
      -accelerator "$appData(modKey)-N" -command {newDoc}   

Notice that we specify the TickLeez procedure that is to be called when this menu item is selected by using the -command argument.

Listing 4 show the complete definition of the setupMenus procedure.

Listing 4: Setting up the menus and menu items

proc setupMenus {w} {
   global appData
   # create a new menu bar
   set bar [menu ${w}mbar -tearoff 0]
   # File menu   
   set m [menu $bar.file -tearoff 0]
   $bar add cascade -label "File" -menu $m
   $m add command -label "New" \
         -accelerator "$appData(modKey)-N" -command {newDoc}   
   $m add command -label "Open..." \
         -accelerator "$appData(modKey)-O" -command {openDoc}
   $m add command -label "Close" \
         -accelerator "$appData(modKey)-W" -command {closeDoc}
   $m add sep
   $m add command -label "Save" \
         -accelerator "$appData(modKey)-S" -command {saveDoc}
   $m add command -label "Save As..." \
         -accelerator "$appData(modKey)-Shift-S" \
         -command {saveAsDoc}
   if {[string equal $appData(os) "windows"]} {
      $m add sep
      $m add command -label "Exit" \
         -accelerator "$appData(modKey)-Q" -command {exit}
   #   Edit menu
   set m [menu $bar.edit -tearoff 0]
   $bar add cascade -label "Edit" -menu $m
   $m add command -label "Undo" \
         -accelerator "$appData(modKey)-Z" -command {undoDoc}
   $m add sep
   $m add command -label "Cut" \
         -accelerator "$appData(modKey)-X" \
         -command {editDoc cut}
   $m add command -label "Copy" \
         -accelerator "$appData(modKey)-C" \
         -command {editDoc copy}
   $m add command -label "Paste" \
         -accelerator "$appData(modKey)-V" \
         -command {editDoc paste}
   $m add command -label "Clear" -command {editDoc clear}
   $m add sep
   $m add command -label "Select All" \
         -accelerator "$appData(modKey)-A" \
         -command {selectDoc all}
   $m add command -label "Select None" \
         -accelerator "$appData(modKey)-B" \
         -command {selectDoc none}
   #   Movie menu
   set m [menu $ -tearoff 0]
   $bar add cascade -label "Movie" -menu $m
   $m add command -label "Hide Controller Bar" \
         -accelerator "$appData(modKey)-1" \
         -command {puts "TO BE PROVIDED"}
   #   Help menu
   if {[string equal $appData(os) "windows"]} {
      set m [menu $ -tearoff 0]
      $bar add cascade -label "Help" -menu $m
   } else {
      set m [menu $ -tearoff 0]
      $bar add cascade -menu $m 
   $m add command -label "About TickLeez" \
         -command {showAboutBox}
   $w configure -menu $bar

We'll encounter the various procedures attached as commands later on in this article and the next.

Adding the About Box

Let's look at a real-life example of using Tk to display and manage a window on the screen, in this case our application's About box. The Windows version of the About box is shown in Figure 3, and the Macintosh version is shown in Figure 4.

Figure 3: The About box of TickLeez (Windows)

Figure 4: The About box of TickLeez (Macintosh)

You'll notice that the appearance of the Macintosh About box isn't quite right; Tk currently is unable to draw the horizontal stripes that form the background of an Aqua dialog box.

The first time the user selects the About TickLeez menu item to display the About box, we'll use the toplevel command to create a new toplevel window, as mentioned above. When the user closes the About box, however, we won't destroy the window. Rather, we'll simply hide the window (by issuing the withdraw command); if the user later decides to display the About box again, we can just show the hidden window with these commands:

wm state .about normal
raise .about

This saves us from having to create and delete the images in the About box each time it's displayed.

Our About box contains four widgets: the OK button, a static text field, and two additional buttons. We can create and position the OK button with this code:

place [button .about.ok -text OK -default active \ 
            -width 5 -command {wm withdraw .about}] \
            -x 284 -y 124

As you can see, the command associated with the OK button is to withdraw (that is, hide) the window .about, which is the About box itself.

The two additional buttons are used to display the images in the About box. In TickLeez, the About box is configured in such a way that clicking the penguin image changes that picture to the Tcl logo. Figure 5 shows the result of clicking the penguin image in Figure 4.

Figure 5: The About box of TickLeez (clicked)

We can load the penguin image like this:

set penguin [image create photo -file \
      [file join [pwd] penguin.jpeg]]

And we create and position the button like this:

place [button .about.pen -image $penguin \
      -width 76 -height 105 -relief flat \
      -command "raise .about.tcl .about.pen"] -x 20 -y 8

Toggling the two images is accomplished using the raise command; when passed two arguments, it causes the first image to be drawn on top of the second image. Since our two images are cleverly configured to be the same size, this causes one image to become visible and the other invisible.

Listing 5 shows our complete definition of the showAboutBox procedure.

Listing 5: Showing the About box

proc showAboutBox {} {
   global appData
   # if the About box exists already, just show it and bring it to the front
   if {[winfo exists .about]} {
      wm state .about normal
      raise .about
   # otherwise, create the About box
   toplevel .about -width 360 -height 160
   wm resizable .about 0 0
   wm title .about "About TickLeez"
   if {[string match "mac*" $appData(os)]} {
      ::tk::unsupported::MacWindowStyle style .about \
         document {closeBox}
   place [button .about.ok -text OK -default active \ 
            -width 5 -command {wm withdraw .about}] \
            -x 284 -y 124
   place [label .about.what -wraplength 220 -justify left \
            -text "A QuickTime movie player built with \
            Tcl/Tk.\n\n\u00a9 2004 by Tim Monroe"] -x 120 -y 12
   set penguin [image create photo -file \
      [file join [pwd] penguin.jpeg]]
   set feather [image create photo -file \
      [file join [pwd] tcl.jpeg]]
   place [button .about.pen -image $penguin \
            -width 76 -height 105 -relief flat \
            -command "raise .about.tcl .about.pen"] -x 20 -y 8
   place [button .about.tcl -image $feather \
            -width 76 -height 105 -relief flat \
            -command "raise .about.pen .about.tcl"] -x 20 -y 8
   raise .about.pen .about.tcl
   bind .about <Return> {.about.ok flash; .about.ok invoke}
   wm protocol .about WM_DELETE_WINDOW {.about.ok invoke}
   # center the About box on the screen
   set x [expr [winfo screenwidth .about]/2 - 180]
   set y [expr [winfo screenheight .about]/2 - 80]
   wm geom .about +$x+$y

Notice that Return key presses and clicks in the window's close box are configured to have the same effect as pressing the OK button.

We have laid out the widgets in this dialog box using the place command, by specifying item positions in terms of absolute coordinates in the dialog box. Here we are using the place geometry manager. Tk also provides the pack geometry manager, which lays out items in frames, which can be grouped and positioned relative to other frames. For complex widget positioning, the pack geometry manager is virtually always preferred. Indeed, using the place geometry manager with explicit coordinates is generally considered bad practice. We can get away with using it here because our About box is so simple.

QuickTimeTcl Overview

QuickTimeTcl is an extension to Tcl/Tk that we can use to open, display, and modify QuickTime movies. It was originally written by Bruce O'Neel, and has subsequently been significantly enhanced and extended by Mats Bengtsson. QuickTimeTcl supports QuickTime movie playback and editing on all three major platforms currently supported by QuickTime: classic Mac OS 8 and 9, Mac OS X, and Windows.

QuickTimeTcl extends Tcl/Tk by defining two new widgets, movie and seqgrabber, which support movie playback and editing, and audiovisual capture. In addition, QuickTimeTcl supports a handful of other commands that provide information or supplementary capabilities; for instance, it supports the function tk_getOpenFilePreview, which extends the Tk function tk_getOpenFile by adding a file preview to the file-opening dialog box and by automatically restricting the selectable files to those that can be opened by QuickTime. Here's how easy it is to open a file using QuickTimeTcl:

package require QuickTimeTcl 
set filename [tk_getOpenFilePreview]
movie .m -file $filename
pack .m

We indicate that the QuickTimeTcl package is required; we elicit a filename from the user; we configure a movie object in the root window; and then we pack the movie widget into the root window. Since the movie is the only widget in the window, the window is sized to exactly hold the movie.

QuickTimeTcl is a reasonably complete Tcl/Tk wrapper for the most common QuickTime APIs. It provides support for movie editing, importing and exporting, applying video effects to movies and images, displaying movies full screen, and creating movies from a series of images. QuickTimeTcl also provides a mechanism to intercept and monitor a large number of messages passed to the QuickTime movie controller, including notifications of key events, custom button clicks, time and volume changes, mouse button clicks, selection changes, and (for QuickTime VR movies) changes in the pan, tilt, or field of view angles. This mechanism stands in for several of QuickTime's callback procedures, in particular for the movie controller action filter procedure.

If we need to extend QuickTimeTcl to support capabilities that it does not currently provide (for instance, support for intermovie communication), we can download and modify the source code, which is freely available. The QuickTimeTcl extension is written in fairly vanilla C, and indeed relies in part on some of the sample code we've considered earlier in this QuickTime Toolkit series of articles. For instance, Listing 6 shows the routine that QuickTimeTcl uses to determine the height of the movie controller bar.

Listing 6: Finding the height of the controller bar

short GetControllerBarHeight (MovieController mc) 
   Boolean         wasAttached = false;
   Rect               myRect;
   short            myHeight = 0;
   /* If the controller bar is attached, detach it (and remember we did so) */
   if (MCIsControllerAttached(mc) == 1) {
      wasAttached = true;
      MCSetControllerAttached(mc, false);
   /* Get the rectangle of the controller */
   MCGetControllerBoundsRect(mc, &myRect);
   myHeight = myRect.bottom -;
   /* Now reattach the controller bar, if it was originally attached */
   if (wasAttached) {
      MCSetControllerAttached(mc, true);

If you have a very good memory, you may recognize this as a slightly modified version of the function QTUtils_GetControllerBarHeight that we encountered in the article "Movie Controller Potpourri" (MacTech, February 2000).

Note that QuickTimeTcl can also be used as a pure scripting tool, with no user interface. This would allow us, for instance, to use Tcl scripts to automate various movie operations, such as creating a movie from a series of images or transcoding existing movies into new formats. In these articles, we will not investigate this way of using QuickTimeTcl.

Application Startup

Let's get started writing TickLeez, which we want to be able to open and display QuickTime movies, allow the user to edit those movies, and exhibit all the standard document-related behaviors. The TickLeez script begins with the "package require QuickTimeTcl" directive considered earlier. Then it defines several dozen procedures and ends with this command:


Our main procedure performs launch-time initializations and adds the six pieces of global information to the appData array. Listing 7 shows our implementation of the main procedure. We make sure that the Tk package is available and then set the appData(os) array element to either "windows", or "macintosh", or "macosx", depending on whether the script is executing on Windows, Mac OS 8 or 9, or Mac OS X.

Listing 7: Opening the application

proc main {} {
   global appData
   # make sure the resources we need are available
   if {[catch {package require Tk}]} {
        tk_messageBox -icon error -type ok \
                           -message {Tk did not initialize.}
      exit 1
   # we use a variable 'appData(os)' that is more convenient for Mac OS X
   switch -- $::tcl_platform(platform) {
      unix {
         set appData(os) $::tcl_platform(platform)
         if {[package vcompare [info tclversion] 8.3] == 1} {   
            if {[string equal [tk windowingsystem] "aqua"]} {
               set appData(os) "macosx"
      windows - macintosh {
         set appData(os) $::tcl_platform(platform)
   if {[string match "mac*" $appData(os)]}  {
      set appData(modKey) Command
   } else {
      set appData(modKey) Control
   # initialize global variables
   set appData(winNo) 0
   set appData(nextNewWinNo) 0
   set appData(winTag) winRTM
   # create a new empty directory for temporary files
   if {[info exists ::env(TMPDIR)] && \
         [file isdirectory $::env(TMPDIR)]} {
      set appData(tempDir) \
            [file join $::env(TMPDIR) $appData(winTag)[pid]]
  } else {
      if {[string match "mac*" $appData(os)]} {
         set tmpDir /tmp
      } else {
         set tmpDir [pwd]
      set appData(tempDir) \
            [file join $tmpDir $appData(winTag)[pid]]
   if {[file exists $appData(tempDir)]} {
      file delete -force $appData(tempDir)
   file mkdir $appData(tempDir)
   # set the current directory
   cd [file dirname [info script]]
   # set up the menus
   if {[string match "mac*" $appData(os)]} {
      setupMenus .
      setupBindings ""
   } else {
   # hide the root window and the Console window
   wm withdraw .
   console hide

If we're running on Windows, we call the newDoc procedure to open a new empty movie window. (See Figure 2 again.) Otherwise, we call the three procedures setupMenus, adjustMenus, and setupBindings, which we'll consider in depth in the next article. On both Mac and Windows, we hide the root window (whose name is ".") and the Console window.

Movie Windows

Earlier we saw how to use the toplevel command to create a window. A movie window in TickLeez is just a toplevel window that contains a movie widget. We can create a movie widget by specifying a unique pathname to the movie command:

movie .$

And we can attach a movie file to that widget using the configure command:

.$ configure -file $fileName

In TickLeez, we want a movie window to be editable and resizable; we also want to be able to intercept movie controller actions targeted at the movie. So we'll call the configure command again, like this:

.$ configure -mccommand controllerProc \
               -mcedit 1 -resizable 1

In the next article, we'll see how to define the controllerProc procedure.

Next we need to resize the window to exactly contain the movie and its associated movie controller bar. We can use the pack command, which resizes a window to exactly contain the widgets inside it:

pack .$

Listing 8 shows the complete definition of the openFileInWindow function. Given a full pathname for a movie file and a value that indicates whether the movie is a new movie, it opens that movie in a window on the screen. (Note that the -resizable option does not appear to work correctly on Windows. This may be fixed in a future QuickTimeTcl release.)

Listing 8: Opening a movie in a new window

proc openFileInWindow {fileName isNew} {
   global appData
   # create a unique Tk path for the new window
   set winName $appData(winTag)[incr appData(winNo)]
   # create a new window
   toplevel .$winName
   wm resizable .$winName 0 0
   wm title .$winName [file tail $fileName]
   wm protocol .$winName WM_DELETE_WINDOW \
               "attemptClose $winName closing"
   if {[string match "mac*" $appData(os)]} {
      ::tk::unsupported::MacWindowStyle style .$winName \
         document {closeBox horizontalZoom collapseBox}
   movie .$
   if {$isNew} {
      .$ new $fileName
   } else {
      .$ configure -file $fileName
   .$ configure -mccommand controllerProc \
               -mcedit 1 -resizable 1
   pack .$
   # save window-specific info in global array
   set appData($winName,movie) .$   
   set appData($winName,dirty) 0   
   set appData($winName,fileName) $fileName   
   set appData($winName,undoLevel) 0
   # force the new window to be displayed
   update idletasks
   setupMenus .$winName
   setupBindings $winName

The openFileInWindow procedure is called by two menu-handling procedures, newDoc and openDoc. The newDoc procedure, shown in Listing 9, creates a filename for a non-existent file in our application's temporary directory. QuickTimeTcl requires that a file be associated with every local movie it manages, even for new empty movies.

Listing 9: Creating a new empty movie

proc newDoc {} {
   global appData
   # new windows are entitled "", "", ""....
   incr appData(nextNewWinNo)
   set visWinNum $appData(nextNewWinNo)
   if {$visWinNum == 1} {
      set visWinNum ""
   # construct a new temp file name
   set filename [file join $appData(tempDir) \
   openFileInWindow $filename 1

The openDoc function, shown in Listing 10, elicits a filename from the user by calling the tk_getOpenFile command. This command displays the standard file-opening dialog box and returns the full pathname of the selected file (or the empty string if no file was selected).

Listing 10: Handling the Open menu item

proc openDoc {} {
   set filename [tk_getOpenFile -title "TickLeez: Open a \
                                                         Movie File"]
   if {$filename != ""} {
      openFileInWindow $filename 0


In this article, we've taken a preliminary look at Tcl/Tk and the QuickTimeTcl add-on, which allows us to use the Tcl/Tk scripting language to build a QuickTime-savvy application. We've fashioned our menus and menu bars, and we've seen how to add a simple dialog box -- our application's About box -- to an application. Most important, we learned how to use QuickTimeTcl commands to open a movie file and display it in a movie on the screen.

In the next article, we'll continue working with Tcl/Tk as a delivery platform for QuickTime applications. We'll see how to bind certain events to our application's procedures, and we'll see how to handle standard movie editing. That of course will require that we also implement the standard document behaviors, such as prompting the user to save or discard unsaved changes to a movie that's being closed.

Acknowledgements and References

Special thanks are due to Jim Ingham and to Mats Bengtsson for reviewing a draft of this article and for providing invaluable feedback.

The latest Tcl/Tk release for Windows computers is available at the Tcl/Tk Developer Xchange site ( You can download the QuickTimeTcl extension at For Macintosh OS X computers, you should use the all-inclusive Tcl/Tk distribution available at

Tim Monroe is a member of the QuickTime engineering team at Apple. You can contact him at The views expressed here are not necessarily shared by his employer.


Community Search:
MacTech Search:

Software Updates via MacUpdate

TextSoap 8.4.1 - Automate tedious text d...
TextSoap can automatically remove unwanted characters, fix up messed up carriage returns, and do pretty much anything else that we can think of to text. Save time and effort. Be more productive. Stop... Read more
TextSoap 8.4.1 - Automate tedious text d...
TextSoap can automatically remove unwanted characters, fix up messed up carriage returns, and do pretty much anything else that we can think of to text. Save time and effort. Be more productive. Stop... Read more
Backblaze - Online backup servi...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
Numi 3.15 - Menu-bar calculator supports...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
EtreCheck 3.3.3 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
BusyContacts 1.1.8 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
TunnelBear 3.0.14 - Subscription-based p...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more
Apple Final Cut Pro X 10.3.4 - Professio...
Apple Final Cut Pro X is a professional video editing solution.Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Hopper Disassembler 4.2.1- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32-bit and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about... Read more
Slack 2.6.2 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.6.2: Fixed Inexplicably, context menus and spell-check... Read more

Latest Forum Discussions

See All

The best new games we played this week
We were quite busy this week. A bunch of big mobile games launched over the past few days, alongside a few teeny surprises. There're lots of quality games to load your phone with. We've gone and picked out five of our favorites for the week. [... | Read more »
Magikarp Jump beginner's guide
Magikarp Jump is a mystifying little game. Part Tamagotchi, part idle clicker, there's not a whole lot of video game there, per se, but for some reason we can't help coming back to it again and again. Your goal is to train up a little Magikarp to... | Read more »
Goat Simulator PAYDAY (Games)
Goat Simulator PAYDAY 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICES **iPhone 4S, iPad 2, iPod Touch 5 or better Goat Simulator: Payday is the most... | Read more »
GRID Autosport delayed until autumn
Sorry mobile racing fans -- GRID Autosport has been delayed a few months. The game is now expected to launch this fall on iOS. Feral Interactive announced that they wanted more time to work on the game's UI and overall performance before launching... | Read more »
Zombie Gunship Survival Beginner's...
The much anticipated Zombie Gunship Survival is here. In this latest entry in the Zombie Gunship franchise, you're tasked with supporting ground troops and protecting your base from the zombie horde. There's a lot of rich base building fun, and... | Read more »
Mordheim: Warband Skirmish (Games)
Mordheim: Warband Skirmish 1.2.2 Device: iOS Universal Category: Games Price: $3.99, Version: 1.2.2 (iTunes) Description: Explore the ruins of the City of Mordheim, clash with other scavenging warbands and collect Wyrdstone -... | Read more »
Mordheim: Warband Skirmish brings tablet...
Legendary Games has just launched Mordheim: Warband Skirmish, a new turn-based action game for iOS and Android. | Read more »
Magikarp Jump splashes onto Android worl...
If you're tired ofPokémon GObut still want something to satisfy your mobilePokémon fix,Magikarp Jumpmay just do the trick. It's out now on Android devices the world over. While it looks like a simple arcade jumper, there's quite a bit more to it... | Read more »
Purrfectly charming open-world RPG Cat Q...
Cat Quest, an expansive open-world RPG from former Koei-Tecmo developers, got a new gameplay trailer today. The video showcases the combat and exploration features of this feline-themed RPG. Cat puns abound as you travel across a large map in a... | Read more »
Jaipur: A Card Game of Duels (Games)
Jaipur: A Card Game of Duels 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: ** WARNING: iPad 2, iPad Mini 1 & iPhone 4S are NOT compatible. ** *** Special Launch Price for a limited... | Read more »

Price Scanner via

Memorial Day savings: 13-inch Touch Bar MacBo...
B&H Photo has the 2016 Apple 13″ Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 13″ 2.9GHz/512GB... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $... Read more
Apple restocks refurbished 11-inch MacBook Ai...
Apple has Certified Refurbished 11″ MacBook Airs (the latest models recently discontinued by Apple), available for up to $170 off original MSRP. An Apple one-year warranty is included with each... Read more
12-inch 1.2GHz Retina MacBooks on sale for up...
B&H has 12″ 1.2GHz Retina MacBooks on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 12″ 1.2GHz Space Gray Retina MacBook: $1449.99 $150 off... Read more
15-inch 2.7GHz Silver Touch Bar MacBook Pro o...
MacMall has the 15-inch 2.7GHz Silver Touch Bar MacBook Pro (MLW82LL/A) on sale for $2569 as part of their Memorial Day sale. Shipping is free. Their price is $230 off MSRP. Read more
Free Tread Wisely Mobile App Endorsed By Fath...
Just in time for the summer driving season, Cooper Tire & Rubber Company has announced the launch of a new Tread Wisely mobile app. Designed to promote tire and vehicle safety among teens and... Read more
Commercial Notebooks And Detachable Tablets W...
Worldwide shipments of personal computing devices (PCDs), comprised of traditional PCs (a combination of desktop, notebook, and workstations) and tablets (slates and detachables), are forecast to... Read more
Best value this Memorial Day weekend: Touch B...
Apple has Certified Refurbished 2016 15″ and 13″ MacBook Pros available for $230 to $420 off original MSRP. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2.6GHz... Read more
13-inch MacBook Airs on sale for up to $130 o... has 13″ MacBook Airs on sale for up to $130 off MSRP including free shipping: - 13″ 1.6GHz/128GB MacBook Air (sku MMGF2LL/A): $869.99 $130 off MSRP - 13″ 1.6GHz/256GB MacBook Air (sku... Read more
2.8GHz Mac mini available for $973 with free...
Adorama has the 2.8GHz Mac mini available for $973, $16 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more

Jobs Board

*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
Best Buy *Apple* Computing Master - Best Bu...
**509643BR** **Job Title:** Best Buy Apple Computing Master **Location Number:** 001482- Apple Valley-Store **Job Description:** **What does a Best Buy Apple Read more
*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
*Apple* Mac and Mobility Engineer - Infogrou...
Title: Apple Mac and Mobility Engineer Location: Portland, OR Area Type: 12 month contract Job: 17412 Here's a chance to take your skills to the limit, learn new Read more
*Apple* Retail - Multiple Positions, White P...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.