New Tcl/TkAqua FAQ

Tcl/TkAqua FAQ

Note: This FAQ is an updated version of the old Mac-Tk FAQ, now lost in the Internet archives. That document, last revised in 2002, covered Tcl/Tk under Mac OS 9 and earlier and does not reflect the port of Tk to Mac OS X. This new FAQ builds on the earlier document, consolidates material in various documents such as the Tcl/TkAqua README documents, various entries at the Tcl wiki, relevant mailing list items, and other online resources/tutorials.--Kevin Walzer

1. General

1.1. What is Tcl/TkAqua, what are it's requirements, and how do I get it?

Tcl/TkAqua is the most common and attractive build of the Tcl/Tk system for Mac OS X. "Aqua" means the graphical interface has a native OS X look and feel - unlike builds linked to Xorg/X11.

Tcl/TkAqua can be built against either the Carbon or Cocoa API. Carbon is Apple's older, now deprecated API. Cocoa is the modern build, but it has some major unresolved problems. (See BUGS for more information).

Tcl/TkAqua requires MacOS X to run. Support for Classic MacOS was discontinued in 2004. To download a current version of Tcl/Tk, download ActiveTcl from http://www.activestate.com/ .

Tcl/Tk were originally developed on Unix in the late 1980s, and were ported to Windows and Mac OS in the mid-1990s by Sun Microsystems. (The original author of Tcl/Tk, John Ousterhout, was a professor at Berkeley but later left to join Sun.). Apple Computer helped to port Tk to OS X in late 2001. (Because OS X is a variant of Unix, no special effort was required to port Tcl, the command-line scripting component.)

1.2. Where is the on-line documentation for Tcl/Tk?

The Tcl/TkAqua files are stored in /Library/Frameworks. The entry page for document is in /Library/Frameworks/Tcl.framework/Versions/8.5/Resources/Documentation/Reference/Tcl/contents.htm and /Library/Frameworks/Tk.framework/Versions/8.5/Resources/Documentation/Reference/Tk/contents.htm.

1.3 How do I build Tcl/TkAqua and extensions from source?

Apple's Developer Tools CD needs to be installed (the version matching your OS release, but no earlier than April 2002). This CD should have come with Mac OS X retail or should be present as a disk image on new macs that came with OSX preinstalled. It can also be downloaded from http://connect.apple.com (after you register for free ADC membership).

  • Tcl is built as a Mac OS X framework via the Makefile in tcl/macosx, but can also be built from Apple's XCode IDE using the Tcl.pbproj project (which calls through to the Makefile).
  • TkAqua is built as a Mac OS X frameworks using Apple's Xcode IDE, but you do not have to deal with the IDE if you don't want to, the Makefile in tk/macosx takes care of calling the r command line tool with all the details taken care of.
  • Unpack the tcl and tk source release archives and place the tcl and tk source trees in a common parent directory. If you don't want have the two source trees in one directory, you'll need to create the following symbolic link for the build to work as setup by default
ln -fs /path_to_tcl/build /path_to_tk/build

(where /path_to_{tcl,tk} is the directory containing the tcl resp. tk tree) or you can pass an argument of BUILD_DIR=/somewhere to the tcl and tk make.)

  • The following instructions assume the tcl and tk source trees are named "tcl${ver}" and "tk${ver}", respectively, where ${ver} is a shell variable containing the tcl and tk version number (for example '8.4.2').

Setup the shell variable as follows:

set ver="8.4.2" ;: if your shell is csh
ver="8.4.2"     ;: if your shell is sh

The source trees will be named this way only if you are building from a release archive, if you are building from CVS, the version numbers will be missing; so set ${ver} to the empty string instead:

set ver=""     ;: if your shell is csh
ver=""         ;: if your shell is sh
  • If you're only interested in building TclTkAqua and don't plan on doing development with the Xcode projects, using the Makefiles is easiest. The following steps will build Tcl and Tk from the Terminal, assuming you are located in the directory containing the tcl and tk source trees:
make -C tcl${ver}/macosx
make -C tk${ver}/macosx

and the following will then install Tcl and Tk onto the root volume (admin password required):

sudo make -C tcl${ver}/macosx install
sudo make -C tk${ver}/macosx  install

if you don't have the admin password, you can install into your home directory, instead by passing an INSTALL_ROOT argument to make:

make -C tcl${ver}/macosx install INSTALL_ROOT="${HOME}/"
make -C tk${ver}/macosx  install INSTALL_ROOT="${HOME}/"

The default Makefile targets will build _both_ debug and optimized versions of the Tcl and Tk frameworks with the standard convention of naming the debug library Tcl.framework/Tcl_debug resp. Tk.framework/Tk_debug. This allows you to dynamically link to the debug libraries at runtime by setting

        setenv DYLD_IMAGE_SUFFIX _debug

(c.f. man dyld for more details)

If you only want to build and install the debug or optimized build, use the 'develop' or 'deploy' target variants of the Makefiles, respectively. For example, to build and install only the optimized versions:

make -C tcl${ver}/macosx deploy
make -C tk${ver}/macosx deploy
sudo make -C tcl${ver}/macosx install-deploy
sudo make -C tk${ver}/macosx  install-deploy

The Makefiles can also build a version of 'Wish Shell' that has the Tcl and Tk frameworks embedded in its application package. This allows for standalone deployment of the application with no installation required, e.g. from read-only media. To build & install in this manner, use the 'embedded' target variants of the Makefiles. For example, to build a standalone 'Wish Shell.app' in ./embedded/Applications/Utilities:

make -C tcl${ver}/macosx embedded
make -C tk${ver}/macosx embedded
sudo make -C tcl${ver}/macosx install-embedded INSTALL_ROOT=`pwd`/embedded/
sudo make -C tk${ver}/macosx  install-embedded INSTALL_ROOT=`pwd`/embedded/

Notes:

  • if you've already built standard TclTkAqua, building embedded does not require any new compiling or linking, so you can skip the first two makes. (making relinking unnecessary was added in 8.4.2)
  • the embedded frameworks include only optimized builds and no documentation.
  • the standalone Wish has the directory Wish\ Shell.app/Contents/lib in its auto_path. Thus you can place tcl extensions in this directory (i.e. embed them in the app package) and load them with package require.

It is possible to build Tk without without the tcl sourcetree; but in that case you need to tell the Tk Makefile where the copies of 'Tcl.framework' and 'tclsh8.4' are located that you want to build & link against (their default location is ${BUILD_DIR}/tcl).

For instance to use their default systemwide install locations:

make -C tk${ver}/macosx \
    TCL_FRAMEWORK_DIR=/Library/Frameworks TCLSH_DIR=/usr/bin
sudo make -C tk${ver}/macosx install \
    TCL_FRAMEWORK_DIR=/Library/Frameworks TCLSH_DIR=/usr/bin

Of course this will only work if /Library/Frameworks does indeed contain a Tcl.framework corresponding in version to the Tk.framework you're trying to ]build, and if TCLSH_DIR contains a corresponding /usr/bin/tclsh8.4

or to use an earlier install of Tcl into ˇINSTALL_ROOT="${TCLTK}/"ˇ :

make -C tk${ver}/macosx \
    TCL_FRAMEWORK_DIR=${TCLTK}/Library/Frameworks TCLSH_DIR=${TCLTK}/usr/bin
sudo make -C tk${ver}/macosx install INSTALL_ROOT="${TCLTK}/" \
    TCL_FRAMEWORK_DIR=${TCLTK}/Library/Frameworks TCLSH_DIR=${TCLTK}/usr/bin

The Makefile variables TCL_FRAMEWORK_DIR and TCLSH_DIR were added in Tk 8.4.3.

Note that html help in Tk.framework is only built if TCL_FRAMEWORK_DIR contains the tcl Makefile (as is the case for the default value of TCL_FRAMEWORK_DIR).

Thanks to Daniel Steffen's work, Mactel/universal binaries for Tcl/Tk Aqua are now simple. You can now build for 64bit on a G5 with the usual ˇ--enable-64bitˇ flag, or you can build as a fat ppc & ppc64 (& i386) binary on any ppc. Details on universal builds are in macosx/README of the Tcl/Tk source tree, but in short it suffices to set ˇCFLAGSˇ as follows:

export CFLAGS="-arch ppc -arch ppc64 -arch i386 \
-isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4"

Mac OS X 10.4, Xcode 2.2, and the appropriate SDK's are required to build Tcl/Tk Aqua in this fashion.

You may also need to add -fpascal-strings to CFLAGS for menus to work properly (particularly the default menu), otherwise you get may get menus with labels like "\pEdit\pCut/X\pCopy" where these should be separate menu items. --MAK

With Tcl/Tk 8.5/OS X 10.5, some different steps might be necessary.

  1. Set CFLAGs as above, either in your profile or by export CFLAGS="-arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4".
  2. Create a top-level directory for the Tcl and Tk source trees and change to that as your working directory, i.e. cd /Users/mydir/tcltk85.
  3. cd /Users/mydir/tcltk85/tcl8.5.0/macosx
  4. ./configure --enable-threads --enable-framework
  5. make; sudo make install
  6. cd /Users/mydir/tcltk85/tk8.5.0/macosx
  7. ./configure --enable-aqua --enable-threads --enable-framework
  8. make; sudo make install

The result of this is that the Tcl/Tk frameworks are installed in /Library/Frameworks, as expected, and are universal binaries. The process for building an embedded/standalone Wish remains as before.

To build an embedded/standalone Wish, follow this process:

make -C tcl${ver}/macosx embedded
make -C tk${ver}/macosx embedded
sudo make -C tcl${ver}/macosx install-embedded INSTALL_ROOT=`pwd`/embedded/
sudo make -C tk${ver}/macosx  install-embedded INSTALL_ROOT=`pwd`/embedded/

Why are the last two commands sudoed?

if you've already built standard TclTkAqua, building embedded does not require any new compiling or linking, so you can skip the first two makes. (making relinking unnecessary was added in 8.4.2) The embedded frameworks include only optimized builds and no documentation. The standalone Wish has the directory Wish\ Shell.app/Contents/lib in its auto_path. Thus you can place tcl extensions in this directory (i.e. embed them in the app package) and load them with package require.

To build TEA based extensions, the following configure invocation should do the trick:

./configure \
--prefix=/usr/local --libdir=/Library/Tcl \
--with-tcl=/Library/Frameworks/Tcl.framework \
--with-tclinclude=/Library/Frameworks/Tcl.framework/Headers \
--with-tk=/Library/Frameworks/Tk.framework \
--with-tkinclude=/Library/Frameworks/Tk.framework/Headers \
--enable-threads

Binary extensions can also be built as universal binaries. This is a good thing, if you need to use the extension with different Tcl versions that are built for different architectures. The important thing is to link against a universal build of Tcl/Tk, because you cannot build a universal binary extension against a single architecture Tcl/Tk. So be sure to do '--with-tcl=...' in the ./configure call for the extension using a universal Tcl/Tk. Before you do the ./configure call, be sure to export the CFLAGS as noted above (e.g. -arch i386 -arch x86_64), and then configure/build as needed.

If you don't do this right, you might end up with error messages like the following, that indicate, you don't use the right combination of Tcl and extension architecture:

dlopen(libsqlite3.6.20.dylib, 10): image not found
load libsqlite2.6.20.dylib
image not found
NSCreateObjectFileImageFromFile() error: not a Mach-O MH_BUNDLE file

Error in startup script: no suitable image found.  Did find:
       libsqlite3.6.20.dylib: mach-o, but wrong architecture
NSCreateObjectFileImageFromFile() error: not a Mach-O MH_BUNDLE file

You may even get a 'bus error' on these conflicts.

When trying to build a universal binary extension and not using a universal Tcl build, this is a typical error you get, indicating the wrong combination:

ld: warning: in libtclstub8.4.a, file is not of required architecture
Undefined symbols:
 "_Tcl_InitStubs", referenced from:
     _Sqlite3_Init in tclsqlite3.o
 "_tclStubsPtr", referenced from:
     _tclStubsPtr$non_lazy_ptr in tclsqlite3.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
lipo: can't open input file: /var/folders/V+/V+EH4NTNHFyVqsfQUXAau++++TI/-Tmp-//ccf2zTQp.out (No such file or directory) 
make: *** [libsqlite3.6.20.dylib] Error 1

Note: use the 'file' shell command on a binary to find out for which architectures it was built.

1.4. What tools are available for developing Tcl applications?

For GUI building, tools include TkProE (http://tkproe.sourceforge.net/ ), SpecTcl (http://spectcl.sourceforge.net ), and Visual Tcl (http://vtcl.sourceforge.net ). However, these tools are either no longer actively developed (SpecTcl and VTcl) or do not have a large user base (TkProE). The best commercial development environment for Tk, ActiveState's Komodo (http://www.activestate.com/Products/Komodo/ ), is now available on OS X, and has a free version. Many Tcl/Tk developers prefer to write their GUI code by hand; as Tk is a simple and elegant system for creating graphical interfaces, learning to code a GUI by hand is not difficult.

Alpha is a fine code editor that is mostly written in Tcl; various flavors of the program (OS X-specific and cross-platform) are available. Alpha is shareware. Other popular editors include such Mac-specific tools as Textwrangler (free) and BBEdit (commercial) from Bare Bones Software (http://www.barebones.com ). BBEdit is a legendary program on the Mac, with powerful code editing and text management features; Textwrangler offers much of the functionality of the commercial product, includes good support for Tcl, and is free. An alternate Tcl language module for TextWrangler and BBEdit is also available. It features improved recognition of procedure definitions which use the namespace:: syntax. [L1 ]

The leading Unix-based code editors include Vim and Emacs. Both originated as command-line applications, and can be used on the Mac in this fashion by calling them in the Terminal application. However, both are also available in Mac-native GUI formats. The official site for an Aqua-native version of Vim is http://www.macvim.org . While there is not yet an officially available version of Emacs for OS X, unofficial builds can be download from a variety of locations, including http://www.aquamacs.org , http://home.att.ne.jp/alpha/z123/emacs-mac-e.html , and http://emacs-on-aqua.sourceforge.net .

1.5. What commercial apps have been released with Tcl & Tk?

AOL's webserver (http://www.aol.com ), one of the busiest in the world, makes extensive use of Tcl. Tcl is used by such companies as Motorola (http://www.motorola.com ) and Cisco (http://www.cisco.com ) for internal product testing and development. ActiveState has built a successful business providing programming tools to Tcl developers, as well as developers in other languages. Other commercial developers include Mark Roseman (http://www.courseforum.com ), Michael Kirkham (http://www.muonics.com ), Kevin Walzer (http://www.codebykevin.com ), Simulistics, developer of the modeling/simulation program Simile (http://www.simulistics.com/ ); Inivis, developer of the 3-D graphics program AC3D (http://www.ac3d.org ); Bitrock, developer of InstallBuilder, an installer development toolkit (http://www.bitrock.com ); Peter Caffin, developer of RReplace (file search and replace, http://rreplace.autons.net ) and Padded, a PAD file builder (http://padded.autons.net ).

Numerous open-source developers also make use of Tcl/Tk, including Mats Bengtsson (http://thecoccinella.org/ ); Tom Hennigan, the Mac maintainer of aMSN (http://www.amsn-project.net ), Andres Garcia, developer of Getleft, a web-site downloader (http://personal1.iddeo.es/andresgarci/getleft/english/ ); Randolf Schultz, developer of Ayam, a 3-D/OpenGL modeler (http://www.ayam3d.org ); and others.

1.6. Is there a mailing list for Tcl/Tk Aqua?

The tcl-mac mailing list on sourceforge is the canonical place for questions specific to Tcl & Tk on Mac OS X:

        http://lists.sourceforge.net/lists/listinfo/tcl-mac

(this page also has a link to searchable archives of the list, please check them before asking on the list, many questions have already been answered).

1.7. Where are some other sites for information about Tcl & Tk?

The jumping-off point for information about Tcl/Tk is https://www.tcl-lang.org . You can find links to documentation, applications, and other resources. The Tcl Wiki at https://wiki.tcl-lang.org is a more informal, but continuously updated, source of information on specific Tcl/Tk topics. This is an excellent resource to find specific information and code samples on almost any aspect of Tcl/Tk programming. A wiki can be edited by anyone, so you are also welcome to contribute pages, code samples, updates and clarification to existing pages, and so forth.

The wiki has a page listing known bugs in Mac OS X Tcl/Tk (and other tips)

        https://wiki.tcl-lang.org/MacOS%20X

as well as a page with info on building Tcl/Tk on Mac OS X

        https://wiki.tcl-lang.org/Steps%20to%20build%20Tcl/Tk%208.4.0%20on%20MacOS%20X

The final essential Tcl/Tk resource is the usenet group comp.lang.tcl.

2. Running the Shells

2.1. What are the shells provided with Tcl/Tk Aqua?

Tclsh (tcl shell) is the main shell for running command-line Tcl scripts. That shell can be invoked only from the command line, in the Terminal application, and is located at /usr/bin/tclsh on OS X.

Wish (windowing shell) is the shell used to run Tk. Wish comes in two forms: a command-line version that is installed in /usr/bin/wish; and an application bundle, Wish Shell.app, that is installed in /Applications/Utilities.

2.2 . How can I respond to having files dropped on my Wish Application?

Define a proc named:

proc ::tk::mac::OpenDocument args {
    # args will be a list of all the documents dropped on your app, or double-clicked
}

in your AppMain.tcl script. Tk will feed this the file names from any Open Document events sent to Wish.

2.3. Can I get Wish to do something when I double-click on my Tcl scripts?

The Tcl/TkAqua Batteries Included distribution includes a utility called Launcher that will activate Wish if you double-click on a Tcl script. Wish will then run the script.

3. Adding Commands

3.1. How do I add commands to Tcl or Tk?

There are two ways to do this:

  • If you can implement the command in Tcl, then you just write a new tcl proc, using the proc command. See the proc.n.html file for more details.
  • If the guts of your command are implemented in C, you need to use the Tcl C API for creating commands.Books such as Practical Programming in Tcl/Tk by Brent Welch are a helpful resource here.

3.2. Okay, I wrote my C-based command, now how do I get Tcl to acknowledge its existance?

The best way to do this is to package your new command into a shared library, and then either load it directly into Tcl using the load command, or set it up as a Tcl package, and use the package require mechanism.

3.3. What compilers should I use to build my extension?

Tcl/Tk Aqua is built using Xcode and GCC (Gnu compiler). These tools are free installs from Apple.

4. Menus

4.1. How do I install my own menus into the Macintosh Menubar?

Each toplevel has a menu associated with it. You set it with the -menu option of the toplevel thusly:

menu .mbar -tearoff 0
. configure -menu .mbar

This menu is displayed in the Main Macintosh menubar whenever the toplevel that owns it (in this example, .) is in the foreground.

4.2. How do I add pulldowns to a Macintosh Menubar?

To make the menu entries in the menubar, you add cascade entries to the menu you have installed for that toplevel. Each cascade entry will show up as a separate pulldown of the main menu bar. So the following code installs a pulldown called "File" with "New", "Open...", "Save" and "Quit" entries into the menubar .mbar:

.mbar add cascade -label File -menu .mbar.file
menu .mbar.file -tearoff 0
.mbar.file add command -label New  -accelerator Command-N -command "NewDoc"
.mbar.file add command -label Open...  -accelerator Command-O -command "OpenFile"
.mbar.file add command -label Close  -accelerator Command-W -command "CloseDoc"
.mbar.file add separator
.mbar.file add command -label Save  -accelerator Command-S -command "SaveDoc"
.mbar.file add command -label "Save As..." -command "SaveDocAs"
.mbar.file add separator
.mbar.file add command -label Quit  -accelerator Command-Q -command exit 

4.3. Do I have to make a new menubar for each toplevel?

No. By default all toplevels inherit the menubar of their parent. Since everything is a child of ".", this means that changing the menubar for "." propagates that change to all the toplevels in your application. So if you create a new toplevel with:

toplevel .top

then ".top" will display the same menubar as ".". If later on, you make a new menubar for .top, and then create a child of .top thusly:

.top configure -menu .top.mbar
toplevel .top.child

Then . will have its original menubar, and .top AND .top.child will share the menubar given by .top.mbar.

4.4. Can I install my own items in the Application and Help menus?

Yes. To install an entry in the Application menu, you need to create a special cascade entry for your menubar where the last part of the name is apple. If the menubar you are using is called ".mbar", then create a cascade menu entry, whose menu is ".mbar.apple":

menu .mbar.apple
.mbar add cascade -menu .mbar.apple

Then all the menu entries that you add to .mbar.apple will appear under the Application Menu pulldow and will be put at the top of the menu (called "Wish" or "Wish Shell" unless you change the Application name as described below). Note, that the above two lines will also remove the "About Tcl & Tk..." entry in the Application menu. This enables you to put your own "About ..." entry there (perhaps specific to Tk 8.5):

.mbar.apple add command -label "About this software ..." -command myAboutCmd
.mbar.apple add separator

For this to work correctly on the Cocoas based Tk 8.6, configuring the main menu should be the last thing you do in setting up the menu. i.e.

. configure -menu .mbar

must be the LAST line of menu-setup-code. Tk-Cocoa sets everything up first. If you do not do this, you will get an additional menu with your apple menu items in. Since this approach also works for Tk 8.5 and 8.4, just make it a habit to configure the toplevel as the last thing.

Note also, the name "apple" is historical, on Mac OS 9 the place for Application-wide menu items was in the Apple Menu. But on Mac OS X, those items now go in the Application Menu. It is no longer possible for Applications to add to the Apple menu.

To install entries in the help menu, create a cascade entry whose menu is .mbar.help (i.e., with the last component being called help):

menu .mbar.help
.mbar add cascade -menu .mbar.help

4.5. Can I add Menus to the default Wish menu bar?

No. This menubar is a simple Macintosh menubar, and cannot be modified. However, the only substantial code in the default menu, namely that which implements the Cut, Copy, Paste and Clear entries, is easily duplicated using the Tk virtual event generation. Just use:

menu .mbar -tearoff 0
.mbar add cascade -menu .mbar.file -label File
.mbar add cascade -menu .mbar.edit -label Edit
menu .mbar.edit -tearoff 0
.mbar.edit add command -label Cut -accel Command-X -command {
    event generate [focus] <<Cut>>
}
.mbar.edit add command -label Copy -accel Command-C -command {
    event generate [focus] <<Copy>>
}
.mbar.edit add command -label Paste -accel Command-V -command {
    event generate [focus] <<Paste>>
}
.mbar.edit add command -label Clear -command {
    event generate [focus] <<Clear>>
}

5. AppleScript

5.1. Can I use AppleScript to communicate from a Tk Application?

Yes. You can do this in a couple of different ways. The simplest is to call the Tclapplescript package, which is a standard part of the ActiveState distribution, at the beginning of your script. Use this syntax:

package require Tclapplescript

Then, when you are ready to call AppleScript specifically, you can set it up like this:

AppleScript execute {
    tell application "Finder"
        display dialog "Tk Aqua rocks!"
    end tell
}

Another way to call AppleScript is to do so via the osascript command line tool, like this:

exec osascript -e {
    tell application "Finder"
        display dialog "Cool"
    end tell
}

Yet another way to access the same functionality is to use TclAE. This allows you to handle AppleEvents directly instead of expressing your commands in the somewhat woolly AppleScript language.

5.2. How can I use scripts that I have written in the Script Editor?

Use the AppleScript load command to load the script, and then the run subcommand to run it:

set myScript [AppleScript load myAppleScriptFile]
button .b1 -text "Run Script"  -command [list AppleScript run $myScript]

5.3. How can I talk to a Tk app from another application.

Tk will respond to the "do script" Apple Event, so you can send Tcl scripts that way.

Otherwise you can use TclAE to install your own AppleEvent handlers.

5.4. Other Apple Events.

As mentioned in section 2.2 above, the application-specific Tcl procedure ::tk::mac::OpenDocument is called when the user drops a document on your application or double-clicks a document created by your application. The list of Apple events that trigger application-specific Tcl procedures is:

Event Handler
kAEOpenDocuments ::tk::mac::OpenDocument
kEventAppHidden ::tk::mac::OnHide
kEventAppShown ::tk::mac::OnShow
kAEShowPreferences ::tk::mac::ShowPreferences
kAEQuitApplication exit (not application specific but can be made so using rename)

Only the OpenDocument procedure receives any arguments. Handling the arguments is discussed in section 2.2 above.

6. Packaging Applications

6.1. How do I turn my script into a double-clickable app?

The Wish application is not just a tool for launching scripts; it can also serve as a wrapper for standalone applications. Wish, like all GUI Aqua applications, is actually a file directory diguised as a single file with its own icon. It is designed by the Tcl/Tk Aqua developers to package entire Tcl/Tk application suites.

The first thing to do is find the Wish Shell-standalone application (with the frameworks installed). Copy the application to another directory, such as your desktop. Then, right-click on the application and choose "Show Package Contents." You will see a "Contents" folder; navigate into this folder and you will see the "MacOS" and "Resources" directory. Add a "Scripts" folder to the "Resources" directory.

The next thing to do is to navigate to the source code folder for your script. If you have one main script, copy it to the "Scripts" folder. Then, set up another script called "AppMain.tcl" and put the following material in it:

if {[string first "-psn" [lindex $argv 0]] == 0} {
    set argv [lrange $argv 1 end]
}
console show
if [catch {source [file join [file dirname [info script]] foo.tcl]}] {
    puts $errorInfo
}

If you don't want the console to show (it is useful for debugging the application while you are packaging it), comment out that line with the # symbol. You can also use "console hide". Be sure to replace "foo.tcl" with the actual name of your main application script.

The next thing to do is navigate up a level to the "Contents" directory. If you have supporting packages/libraries (such as Tclapplescript), copy the libraries to this directory.

Next, navigate to the Resources directory. You should find a file called "Wish.icns." This is the generic Wish Shell application icon; "icns" is the Macintosh icon file format. If you want a custom icon, open Icon Composer, found in your Developer directory. Find another graphic image to import, select "Thumbnail 32-bit Data" from the import options, and then save the graphic as an icon file ("title.icns") in the "Resources" directory of the Visual Tcl app bundle. You may want to test the application at this point by double-clicking on the icon (find the application icon in the Finder; don't try to click on the "icns" file inside the resources directory). If it launches, then the hard part is over and you are almost finished.

Next, navigate up one level from the Resources directory. You should find a file called "Info.plist." This is an XML file that includes a variety of information about the application bundle, including the name of the executable file, the name of the application bundle itself, and the name of the icon file. Find the line marked "CFBundleIcon" and change the name from "Wish.icns" to "title.icns" or whatever name you choose. If you want to change the application name, then find the line "CFBundleName" and change the name from "Wish" to whatever you choose, such as "MyCoolAppName." Save and close the file. Navigate to /Contents/MacOS and change the name of the executable in that directory, "Wish Shell," to "MyCoolAppName." If your application defines an own document type and you want documents of this type to carry the application icon and want the application to be connected to the documents so that it starts if documents are opened (double-click) in the Finder you have to add appropriate keys and values to the "CFBundleDocumentTypes" array (see also [L2 ]). Beware, this connection only works if the application bundle is later copied to your "Programs" directory and you may need to log out and in again to make the Finder aware of the changes. If your application startup sequence takes some time, a small ::tk::mac::OpenDocument procedure should be defined in your "AppMain.tcl" that saves the arguments (file names of documents double clicked in the finder) in a global variable for later processing after application startup finished. Otherwise your application might miss the OpenDocument event while starting up.

Now close the entire application directory. Don't forget to rename the application itself in the Finder with the new name you provided in the "Info.plist" file, just as if you were renaming any other file or folder.

If you follow these steps, you'll have a standalone application bundle of your Tcl script: it won't even need a separate installation of Tcl/Tk on another machine.

For a more detailed set of instructions on preparing a Mac application bundle, including screenshots, see https://www.codebykevin.com/tutorial.html .

6.2. Starpacks and Other Techniques

anoved finds Starpack-based application packages easier to manage and has written a tutorial on the topic here: [L3 ]

Building Stand-Alone Tcl/Tk Applications under Mac OS X contains more information about packaging Tcl/Tk programs as Macintosh applications.

peterc notes: ActiveState's commercial Tcl Dev Kit 4 software now supports the generation of starpacks on Mac OS X and it will even package your application into an .app program through its UI. It's well worth the money.

6.3. Application Bundles

Making an Application Bundle is much the same for Tcl applications as for any other software, however, there are some things worth noting:

  • ActiveState's commercial Tcl Dev Kit 4 can automate the entire application bundling process.
  • Similar to the Preferences item in the Application menu item (which requires ::tk::mac::ShowPreferences to be defined as a proc) is the Help menu item called '${Appname} Help' with a Command-? accelerator. This appears where the CFBundleHelpBookFolder key is set in an Application Bundle's Info.plist, even if it is set to an empty string. Removing this key from your Info.plist (or not setting it in the first place) will ensure this entry does not appear.

7. Cross-Platform Issues

7.1. How do I know what platform I am running on?

There is a Tcl global variable called tcl_platform that contains this information. To check this, just type in "tclsh" into your Terminal application, which will launch the Tcl command-line shell (not Wish). Then, type parray tcl_platform. Here is the output you'll see:

% parray tcl_platform
tcl_platform(byteOrder) = bigEndian
tcl_platform(machine) = ppc
tcl_platform(os) = Darwin
tcl_platform(osVersion) = 7.6
tcl_platform(platform) = unix

There is also the useful

tk windowingsystem

command, which returns one of

aqua
win32
x11

On MacOS X, you might see either "aqua" or "x11" depending on whether you are using TkAqua or not.

7.2. I have some bindings in my code that rely on the other two mouse buttons. How can I simulate these events on the Mac?

There are two ways to do this. The cleanest way to is to make a set of abstract button events, <<LeftMousePress>>, <<CenterMousePress>>, and <<RightMousePress>>, say, and use these everywhere in your code. Then somewhere at startup, use the "event add" command to bind <<LeftMousePress>> to ButtonPress-1, and on Unix bind <<CenterMousePress>> to <ButtonPress-2>, but on the Mac, bind it to <Control-ButtonPress-1>, or something else that you are not using...

The second way is to dispatch your own ButtonPress-2,3 events, with something like:

bind all <Control-ButtonPress-1> {event generate %W <ButtonPress-2> \
    -x %x -y %y -rootx %X -rooty %Y -button 2 -time %t}

You do have to populate all the detail fields of the event that you are likely to use in your bindings, as this example demonstrates.

Duoas 2009-01-14: Here's a shameless plug for VirtualMouse Cross Platform Mouse Handling. I'd love some feedback from all you folks working on a Mac.

7.3. Hey, aren't the buttons the wrong way round?

For historical reasons, MacMice buttons 2 and 3 refer to the right and middle buttons respectively, which is indeed the opposite way round from Windows and *nix systems.

7.4. How do I get the Mac OS version number?

$::tcl_platform(osVersion) returns the kernel's version number, not the product version number. To get the product version number, use:

set version [exec sw_vers -productVersion]

Product Version numbers for Mac OS:

Descriptive NameVersionNotes
Yosemite10.10
El Capitan10.11.6Graphite appearance
Sierra10.12.6
High Sierra10.13.6
Mojave10.14.6dark mode, multiple accent colors
Catalina10.15.5as of 2020-6-5

8. Reporting Bugs

As of 2011, most pre-packaged versions of Tcl/Tk are based on the Cocoa API and have some serious unresolved issues; especially concerning the event loop. Cocoa is also the default build from source code. These issues evidence in various ways, but notably as very slow screen redraws in non-trivial Tk apps. They are currently the focus of much discussion at the tcl-mac mailing list. http://sourceforge.net/mailarchive/forum.php?forum_name=tcl-mac

You should report bugs to the sourceforge bug trackers as usual:

Tcl
http://sourceforge.net/tracker/?atid=110894&group_id=10894&func=browse
Tk
http://sourceforge.net/tracker/?atid=112997&group_id=12997&func=browse

please make sure that you report Tk-specific bugs to the tktoolkit bug tracker and not the tcl one.

9. Additional Notes on Tcl/TkAqua

  • Mac OS X 10.1 (or higher) is required to run TclTkAqua.
  • Tcl built on Mac OS X 10.2 or higher will not run on 10.1 due to missing symbols in libSystem, however Tcl built on 10.1 will run on 10.2 (but without prebinding and other optimizations).
  • If standard input is a special file of zero length (e.g. /dev/null), Wish brings up the tk console window at startup. This is the case when double clicking Wish in the Finder (or using 'open Wish\ Shell.app' from the Terminal).
  • Tcl extensions will be found in any of: $HOME/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl $HOME/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks (searched in that order).

Given a potential package directory $pkg, Tcl on OSX checks for the file $pkg/Resources/Scripts/pkgIndex.tcl as well as the usual $pkg/pkgIndex.tcl. This allows building extensions as frameworks with all script files contained in the Resources/Scripts directory of the framework.

  • the frameworks Tcl.framework and Tk.framework can be placed in any of the system's standard framework directories: $HOME/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks and 'Wish Shell' as well as /usr/bin/tclsh will work.
  • /usr/bin/wish is a script that calls a copy of 'Wish Shell' contained in Tk.framework/Resources
  • if 'Wish Shell' is started from the Finder or via 'open', $argv contains a "-psn_XXXX" argument. This is the Wish's carbon process serial number, you may need to filter it out for cross platform compatibility of your scripts.
  • the env array is different when Wish is started from the Finder than when it (or tclsh) is invoked from the Terminal, in particular PATH may not be what you expect. (Wish started from the Finder inherits the Finder's environment variables, which are essentially those set in $HOME/.MacOSX/environment.plist and not those set by your shell configuration files).
  • As of Tk 8.4.7, AquaTk has a version of the low-level drawing primitives using the CoreGraphics (CG) routines - the code is primarily due to James Tittle. There were numerous problems with the QuickDraw (QD) version, mostly due to the different drawing model of QD & Tk. CG also trivially supports dashed lines, and the various end caps & miters. So this is a great improvement.

The old QD code is retained for now, just in case there are any compatibility problems. To switch back to the QD drawing, just put:

set tk::mac::useCGDrawing 0

in your script before you do drawing. Also the CG drawing can anti-alias line drawing. However, anti-aliased thin lines look washed out, so the threshold for antialiasing is set to 3 pixel width lines. You can change this if you want by putting:

set tk::mac::CGAntialiasLimit <limit>

in your script before drawing, in which case only lines thinner that <limit> pixels will not be antialiased.

  • Quickdraw text antialiasing is enabled by default when available (from 10.1.5 onwards). Changing the global boolean variable '::tk::mac::antialiasedtext' allows to dis/enable antialiasing on the fly from tcl (even for existing text).
  • the format of binary extensions expected by load is that of ordinary shared libraries (.dylib) and not MachO bundles, at present loading of MachO bundles is not supported.
  • Scrollbars: There are two scrollbar variants in Aqua, normal & small. The normal scrollbar has a small dimension of 16, the small variant 12. Access to the small variant was added in Tk 8.4.2.
  • Cursors: You can now put up and spin the Classic MacOS spinner, and the counting hands and watch cursor. The way this is done is each of the spinners have a base name:
Name Description
spinning The circular B&W circular spinner
countinguphand The counting up hand
countingdownhand The counting down hand
countingupanddownhand The counting up then down hand
watch The watch cursor

Then to get the sequential variants, add an integer to the end of the base name. So, for instance this code will spin the spinner:

proc spinCursor {widget count} {
    $widget configure -cursor spinning$count
    after 100 spinCursor [incr count]
}

This was added in Tk 8.4.2.


NEM: Excellent effort. I haven't had time to read through it all yet, but it seems to cover most of the material. This will be a big help for those of us on OS X. One point I did notice: In section 1.5 (Commercial apps) you say AOLServer is built on top of tclhttpd. I don't think this is the case. Both use Tcl heavily, but AOLServer is primarily written in C, as I understand things, whereas tclhttpd is 100% pure Tcl.


Brian Theado: I have a question about packaging applications. Is it possible to package an application from a different platform? I'd like to distribute an application for the Mac, but don't have access to a Mac.

Kevin Walzer: You can always package an application as a starkit on any platform, but it would be difficult to give it all the Mac bells and whistles unless it's packaged on that platform. Things like the Apple menu look weird on other platforms, the icon "icns" format is proprietary to Apple, and so forth.

jcw 2004-11-19: A workable (but not-so-terrific) fallback option right now is to package a starpack using the tclkit-darwin-ppc binary. This runs with Apple's X11 system, which is a separate download (see [L4 ]) and which needs to be running. There is no Aqua based tclkit, i.e. using the starkit/starpack approach, though it looks like it could technically be done. Note that Daniel Steffen's BI distro is set up to run .kit files with "wishkit", which is Aqua, so you can deploy starkits, tell people to install the BI distro, and end up with a double-clickable solution which uses Aqua. Making the GUI look well in that context is going to require a Mac, though.

Lars H: JCW, when you say "wishkit" is not a "tclkit", then what do you mean? Is this merely a matter of names, or is there some technical difference?

They are two different binaries. From [L5 ]: "Note the presence in the distribution of both Tclkit and the new Wishkit, which allows the running of starkits under either Tk/X11 or Tk/Aqua." -jcw

Lars H: Yeah, I knew that much, but it doesn't address my point. From the above "There is no Aqua based tclkit" and "wishkit is Aqua" it should follow that, in your authorative opinion, "Wishkit is not a tclkit", should it not? What property of Wishkit disqualifies it from being "a tclkit"?

DAS: Wishkit is simply a standalone Wish.app with the necessary extensions embedded to allow it to source starkits, and its auto_path adjusted to not look outside the Wishkit.app bundle. It has nothing directly to do with tclkit, hence the distinction. Now that TkAqua is dynamically loadable, it should be possible to build an aqua tclkit, but somebody first needs to implement a way to build a single file Tk.dylib in the macosx Tk build system (i.e. not a framework), the main problem with that scenario is how to deal with the Tk.rsrc file...

Kevin Walzer: Recent builds of tclkit make it possible to bundle up Tcl scripts as starpacks under Mac OS X, either in the Aqua or X11 environment. These can be placed inside a standard Mac application bundle. See http://www.codebykevin.com/opensource/tutorial.html for more information.


jt: Section 1.4 needs to be amended a bit. Apple delivers a precompiled vi and emacs within the Mac OS X Developer Tools package [L6 ] (downloadable through a free ADC account). I personally use emacs-x11 [L7 ] (not to be confused with xemacs [L8 ]) which is installable through Fink [L9 ].


UKo 2005-01-19: just tweaked the layout a little bit to get a better handling. (there is absolutely a need for wikit to support structure for documents)

I have to investigate some questions to make my Tcl apps behave and look better on OS X:

How to bind something to the 'Quit' menu?

DAS: do you mean the application menu 'Quit' item? all this does is send Wish a kAEQuitApplication apple event, the default handler for that event runs [exit], you can either rename that command, or install your own kAEQuitApplication apple event handler, e.g. with TclAE.

UKo: Can you give an example on how to achieve this? I was not able to understand the TclAE documentation -- there is so much more to give than just the event name ...

Ashley Ward: The following did some of what I wanted: not sure if it is quite what you need, UKo...

bind . <Command-q> { exit }

Why is java able to change the apps name in the first menu and Tcl isn't? The normal java program just displays the class name but this can be changed from within the program (without using a app-bundle!).

DAS: there is no public API to change the application name, Java uses a private Apple-internal SPI.

UKo: Wouldn't it be a "good thing to do", to make something like the com.apple.mrj package for Tcl (or integrate it into the core) that gives us all the nuts and bolts to make real OSX applications?

Kevin Walzer: You can change the application name in the menu by editing the info.plist file in the Wish application bundle, and defining your own "Apple" menu in the code of your script. It's not hard to make your application compliant with the Apple/Aqua HIG via these methods, and you can also use the Tile extension package to help with the Aqua-native appearance as well. See http://www.codebykevin.com/opensource/tutorial.html for more information.

peterc: ActiveState's TDK provides convenient support for generating application bundles as one of the final steps in the starpack wrapping process. It provides a handy dialog for editing info.plist data and also allows you to specify a custom .icns icon file. Other things to watch out for if you're doing cross-platform apps is OS-specific conventions for menu item placement. For example, your About and Check For Updates entries go in your Help menu on Windows/X11 but in the Apple menu on Mac.


Jasper Taylor: I have a question that doesn't appear to be answered here. The Wish application includes a help menu, and I can install extra entries in it as described in section 4.4 above. However I cannot set a command to execute when the 'Wish Help' entry in this menu is selected, nor can I delete this command since it isn't actually listed as a menu entry. I wondered if there was an AppleEvent corresponding to it, since like the Preferences command it exists in all Mac apps. However I had a quick look through the Apple documentation and can see no reference to an event for the default Help command. So, anyone out there with a clue?

Kevin Walzer: I'm not sure I follow your question: Wish.app does not include a help menu by default. Launch Wish.app without sourcing a Tcl script and you'll see. You have to define the help menu item and the command procedures to launch it. There are no built-in Apple Events to do this: many Tcl/Tk applications simply define the help procedure as a varation of exec open /path/to/help/index.html, which opens the help index page in the default browser. Now, if you do include a help menu, that is automatically placed at the end of the menu: perhaps that's what you are thinking of?

I have written a Tcl wrapper for the most common Apple Carbon Help API functions, which will register a standard Apple Help book and load the help book into the Help Viewer. See tclAppleHelp for the particulars. This extension can be easily compiled with critcl. This extension provides the Apple events you are referring to, though you still have to prepare the help documents with the correct HTML tags, correct identification in the info.plist file, and so on, in accordance with the Apple documentation.

Gary Newby: Or.. just set the creator code of the doc you want opened in Help Viewer to "hbwr" "TEXT" and issue an "exec open docname.htm". Works fine for me in Tiger/Panther.

peterc 2008-11-19: Personally, I use a urlOpen proc which sends the user to the documentation index on my web site. However, I do like Gary Newby's idea above: often the time you need documentation is the day the networks are playing up (Murphy's Law).

hans: I found '::tk::mac::Quit', which seems like a better option than overriding 'exit' for handling kAEQuitApplication events.


chrstphrchvz - 2019-07-17: The old Mac Tk FAQ can still be found from a search engine: https://www.tcl-lang.org/software/mac/macFAQ.tml?sc_format=wider . Should it be taken down?

2019-09-03: The tcl-mac mailing list has been virtually dead for the past few years; I have opened a ticket to see if it can be discontinued. I would recommend new questions be asked on comp.lang.tcl or the issue trackers instead, where they are much more likely to get a response.