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

DEVONthink Pro 2.9.11 - Knowledge base,...
DEVONthink Pro is your essential assistant for today's world, where almost everything is digital. From shopping receipts to important research papers, your life often fills your hard drive in the... Read more
DiskCatalogMaker 6.8.1 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Tunnelblick 3.7.0 - GUI for OpenVPN.
Tunnelblick is a free, open source graphic user interface for OpenVPN on OS X. It provides easy control of OpenVPN client and/or server connections. It comes as a ready-to-use application with all... Read more
Adobe Dreamweaver CC 2017 -...
Dreamweaver CC 2017 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Dreamweaver customer). Adobe Dreamweaver CC 2017 allows you to... Read more
Adobe Animate CC 2017 16.2.0 - Advanced...
Animate CC 2017 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Flash Professional customer). Animate CC 2017 (was Flash CC) lets you... Read more
A Better Finder Rename 10.15 - File, pho...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
Creative Kit 1.1 - $149.99
Creative Kit 2016--made exclusively for Mac users--is your ticket to the most amazing images you've ever created. With a variety of powerful tools at your fingertips, you'll not only repair and fine-... Read more
iMazing 2.2.3 - Complete iOS device mana...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
Fantastical 2.3.6 - Create calendar even...
Fantastical 2 is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event... Read more
Apple Configurator 2.4 - Configure and d...
Apple Configurator makes it easy to deploy iPad, iPhone, iPod touch, and Apple TV devices in your school or business. Use Apple Configurator to quickly configure large numbers of devices connected to... Read more

Power Rangers: Legacy Wars beginner...
Rita Repulsa is back, but this time she's invading your mobile phone in Power Rangers: Legacy Wars. What looks to be a straightforward beat 'em up is actually a tough-as-nails multiplayer strategy game that requires some deft tactical maneuvering.... | Read more »
Hearthstone celebrates the upcoming Jour...
Hearthstone gets a new expansion, Journey to Un'Goro, in a little over a week, and they'll be welcoming the Year of the Mammoth, the next season, at the same time. There's a lot to be excited about, so Blizzard is celebrating in kind. Players will... | Read more »
4 smart and stylish puzzle games like Ty...
TypeShift launched a little over a week ago, offering some puzzling new challenges for word nerds equipped with an iOS device. Created by Zach Gage, the mind behind Spelltower, TypeShift boasts, like its predecessor, a sleak design and some very... | Read more »
The best deals on the App Store this wee...
Deals, deals, deals. We're all about a good bargain here on 148Apps, and luckily this was another fine week in App Store discounts. There's a big board game sale happening right now, and a few fine indies are still discounted through the weekend.... | Read more »
The best new games we played this week
It's been quite the week, but now that all of that business is out of the way, it's time to hunker down with some of the excellent games that were released over the past few days. There's a fair few to help you relax in your down time or if you're... | Read more »
Orphan Black: The Game (Games)
Orphan Black: The Game 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Dive into a dark and twisted puzzle-adventure that retells the pivotal events of Orphan Black. | Read more »
The Elder Scrolls: Legends is now availa...
| Read more »
Ticket to Earth beginner's guide: H...
Robot Circus launched Ticket to Earth as part of the App Store's indie games event last week. If you're not quite digging the space operatics Mass Effect: Andromeda is serving up, you'll be pleased to know that there's a surprising alternative on... | Read more »
Leap to victory in Nexx Studios new plat...
You’re always a hop, skip, and a jump away from a fiery death in Temple Jump, a new platformer-cum-endless runner from Nexx Studio. It’s out now on both iOS and Android if you’re an adventurer seeking treasure in a crumbling, pixel-laden temple. | Read more »
Failbetter Games details changes coming...
Sunless Sea, Failbetter Games' dark and gloomy sea explorer, sets sail for the iPad tomorrow. Ahead of the game's launch, Failbetter took to Twitter to discuss what will be different in the mobile version of the game. Many of the changes make... | Read more »

Price Scanner via

Deal alert! 15-inch and 13-inch MacBook Pros...
B&H Photo has the new 2016 15″ and 13″ Apple MacBook Pros in stock today and on sale for up to $200 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.7GHz Touch Bar... Read more
Save up to $420 on a new MacBook Pro with App...
Apple is offering Certified Refurbished 2016 15″ and 13″ MacBook Pros, including some Touch Bar models, for up to $420 off original MSRP. An Apple one-year warranty is included with each model, and... Read more
12-inch 1.2GHz Retina MacBooks on sale for $1...
B&H has 12″ 1.2GHz Retina MacBooks on sale for up to $200 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.2GHz Space Gray Retina MacBook: $1449 $150 off MSRP - 12″ 1.... Read more
Is A New 10.5-inch iPad Still Coming In April...
There was no sign or mention of a long-rumored and much anticipated 10.5-inch iPad Pro in Apple’s product announcements last week. The exciting iPad news was release of an upgraded iPad Air with a... Read more
T-Mobile’s Premium Device Protection Now Incl...
Good news for T-Mobile customers who love their iPhones and iPads. The “Un-carrier” has become the first national wireless company to give customers AppleCare Services at zero additional cost as part... Read more
FileWave Ensures Support for Latest Apple OS...
FileWave multi-platform device management providers announced support for Apple’s release yesterday of iOS 10.3, macOS Sierra 10.12.4, and tvOS 11.2. FileWave has a history of providing zero-day... Read more
Use Apple’s Education discount to save up to...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free: -... Read more
Apple refurbished Apple Watches available sta...
Apple is now offering Certified Refurbished Series 1 and Series 2 Apple Watches for 14-16% off MSRP, starting at $229. An Apple one-year warranty is included with each watch. Shipping is free: Series... Read more
9-inch 32GB Space Gray iPad Pro on sale for $...
B&H Photo has the 9.7″ 32GB Space Gray Apple iPad Pro on sale for $549 for a limited time. Shipping is free, and B&H charges NY sales tax only. Their price is $50 off MSRP. Read more
13-inch MacBook Airs on sale for $100-$150 of...
B&H Photo has 13″ MacBook Airs on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 1.6GHz/128GB MacBook Air (MMGF2LL/A): $899 $100 off MSRP - 13″ 1.... Read more

Jobs Board

Fulltime aan de slag als shopmanager in een h...
Ben jij helemaal gek van Apple -producten en vind je het helemaal super om fulltime shopmanager te zijn in een jonge en hippe elektronicazaak? Wil jij werken in Read more
Desktop Analyst - *Apple* Products - Montef...
…technology to improve patient care. JOB RESPONSIBILITIES: Provide day-to-day support for Apple Hardware and Software in the environment based on the team's support Read more
*Apple* Mobile Master - Best Buy (United Sta...
**493168BR** **Job Title:** Apple Mobile Master **Location Number:** 000827-Denton-Store **Job Description:** **What does a Best Buy Apple Mobile Master do?** At Read more
Fulltime aan de slag als shopmanager in een h...
Ben jij helemaal gek van Apple -producten en vind je het helemaal super om fulltime shopmanager te zijn in een jonge en hippe elektronicazaak? Wil jij werken in Read more
*Apple* Mobile Master - Best Buy (United Sta...
**492889BR** **Job Title:** Apple Mobile Master **Location Number:** 000886-Norwalk-Store **Job Description:** **What does a Best Buy Apple Mobile Master do?** Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.