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

calibre 3.8.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Carbon Copy Cloner 5.0.2 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
Evernote 6.12.3 - Create searchable note...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
Default Folder X 5.1.6 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click on... Read more
Geekbench 4.1.2 - Measure processor and...
Geekbench provides a comprehensive set of benchmarks engineered to quickly and accurately measure processor and memory performance. Designed to make benchmarks easy to run and easy to understand,... Read more
GraphicConverter 10.5 - $39.95
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
Dropbox 35.4.20 - Cloud backup and synch...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
XMind 8 Update 4 - Popular mind mapping...
XMind is the most popular mind mapping tool. Millions of people use XMind to clarify thinking, manage complex information, run brainstorming and get work organized. It couldn't be easier to get... Read more
Safari Technology Preview 11.1 - The new...
Safari Technology Preview contains the most recent additions and improvements to WebKit and the latest advances in Safari web technologies. And once installed, you will receive notifications of... Read more
Chromium 61.0.3163.91 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 61.0.3163.91: Release notes were unavailable... Read more

Stormbound: Kingdom Wars guide - how to...
Stormbound: Kingdom Wars is an excellent new RTS turned card battler out now on iOS and Android. Lovers of strategy will get a lot of enjoyment out of Stormbound's chess-like mechanics, and it's cardbased units are perfect for anyone who loves the... | Read more »
The best AR apps and games on iOS right...
iOS 11 has officially launched, and with it comes Apple's ARKit, a helpful framework that makes it easier than ever for developers to create mobile AR experiences. To celebrate the occassion, we're featuring some of the best AR apps and games on... | Read more »
Phoenix Wright: Ace Attorney - Spirit of...
Phoenix Wright: Ace Attorney - Spirit of Justice 1.00.00 Device: iOS Universal Category: Games Price: $.99, Version: 1.00.00 (iTunes) Description: ************************************************※IMPORTANT※・Please read the “When... | Read more »
Kpressor (Utilities)
Kpressor 1.0.0 Device: iOS Universal Category: Utilities Price: $4.99, Version: 1.0.0 (iTunes) Description: The ultimate ZIP compression application for iPhone and iPad. - Full integration of iOS 11 with support for multitasking.-... | Read more »
Find out how you can save £35 and win a...
Nothing raises excitement like a good competition, and we’re thrilled to announce our latest contest. We’ll be sending one lucky reader and a friend to the Summoners War World Arena Championship at Le Comedia in Paris on October 7th. It’s the... | Read more »
Another Lost Phone: Laura's Story...
Another Lost Phone: Laura's Story 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Another Lost Phone is a game about exploring the social life of a young woman whose phone you have just... | Read more »
The Witness (Games)
The Witness 1.0 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0 (iTunes) Description: You wake up, alone, on a strange island full of puzzles that will challenge and surprise you. You don't remember who you are, and... | Read more »
Egg, Inc. guide - how to build your gold...
Egg, Inc.'s been around for some time now, but don't you believe for one second that this quirky clicker game has gone out of style. The game keeps popping up on Reddit and other community forums thanks to the outlandish gameplay (plus, the... | Read more »
The best deals on the App Store this wee...
Good news, everyone! Your favorite day of the week has arrived at last -- it's discount roundup day! This fine Wednesday evening we're gathering up the hottest deals on the App Store. We've got action platformers, we've got puzzle games, we've got... | Read more »
Morphite (Games)
Morphite 1.08 Device: iOS Universal Category: Games Price: $7.99, Version: 1.08 (iTunes) Description: | Read more »

Price Scanner via

Apple Offering Up To $455 Credit Toward iPhon...
iPhone 8 and 8 Plus are now available at the Apple Store, and you can receive up to $375 credit toward a new iPhone purchase when you trade in your eligible smartphone. Photo Courtesy Apple Just... Read more
AnyTrans Offers iOS Users Three Ways For Movi...
iMobie Inc. today announceed AnyTrans v6.0.1, which now can help iOS users move all data to iPhone 8/8 Plus seamlessly. The software is available both on Mac and Windows and fully able to move all... Read more
Snag a 13-inch 2.3GHz MacBook Pro for $100 of...
B&H Photo has 2017 13″ 2.3GHz MacBook Pros in stock today and on sale for $100 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
Verizon offers new iPhone 8 for $100-$300 off...
Verizon is offering the new iPhone 8 for up to $300 off MSRP with an eligible trade-in: • $300 off: iPhone 6S/6S Plus/7/7 Plus, Google Pixel XL, LG G6, Moto Z2 Force, Samsung Galaxy S7/S7 edge/S8/S8... Read more
Apple Refurbished 2017 13-inch MacBook Pros a...
Apple has Certified Refurbished 2017 13″ Touch Bar MacBook Pros in stock today and available for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is... Read more
OWC USB-C Travel Dock with 5 Ports Connectivi...
OWC have announced the new OWC USB-C Travel Dock, the latest addition to their line of connectivity solutions. The USB-C Travel Dock lets you connect its integrated USB-C cable to a Mac or PC laptop... Read more
Pelican Products, Inc. Unveils Cases For All...
Pelican Products, Inc. has announced the launch of its full line of cases including Voyager, Adventurer, Protector, Ambassador, Interceptor (for the Apple iPhone 8 and 8 Plus backwards compatible... Read more
$100 off new 2017 13-inch MacBook Airs
B&H Photo has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. B&H charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off... Read more
Apple restocks Certified Refurbished 13-inch...
Apple has Certified Refurbished 2015 13″ MacBook Airs available starting at $719 and 2016 models available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
Is iPhone X Really The Future Of The Smartpho...
Should iPhone X even be called a telephone? It does of course support telephony and texting, but its main feature set is oriented to other things. It is also debatable whether it makes any rational... Read more

Jobs Board

Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
Full time *Apple* Hardware Tech needed - ma...
…high level of attention to detail Ethics, integrity and trust Be a geek & Previous Apple experience a must. Previous Apple Retail or other Apple Specialist Read more
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
*Apple* Store - Technical Specialist - Apple...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.