Code by Kevin

Code by Kevin, Programming, code, business, and other pursuits

Your Host
Kevin Walzer, software developer.


Subscribe to RSS Feed
Get a syndicated feed of my weblog.



Privacy Policy

Site design: Skeleton


Sun, 19 Jul 2009

Business notes on Tk-Cocoa

As I've previously noted, I have been spending the past couple of months testing Tk-Cocoa as a foundation for my programs. This has involved repackaging one of my previous applications to run on Tk-Cocoa as a way of putting Tk-Cocoa through its paces, filing bug reports and submitting patches to enhance Tk-Cocoa, and documenting my progress. I've also developed some cool Cocoa-based extensions to add specific features to my programs; one of these extensions, TkDock, has been released as open-source and has already been adopted by a couple of programs. In the meantime, I have done no new work on my currently-released programs, which still run on the older Carbon implementation of Tk.

Does this make business sense? Nearly all of the work I've been doing has been an unpaid, volunteer effort. No one pays me to write patches or submit bug reports on Tk, and I don't earn any royalties when someone uses one of my Tk extensions in their work. The past couple of months have been very productive from a coding standpoint, but have not resulted in any updates or new releases of a commercial product.

I think the time I've been spending does make sense from a business standpoint. Everything I've been working on is directly related to the development foundations of my programs, Tcl/Tk and Python. Some of the bugs I ran into were literally showstoppers: they caused Tcl/Tk to crash. It's hardly feasible to release a commercial program that crashes frequently. Also, in terms of patches and enhanced functionality as opposed to bug reports, the code I've been working on addresses a few long-standing gripes about how Tcl/Tk looks and/or works on the Mac. These patches really, really improve a few things and put Tcl/Tk on par with other cross-platform frameworks.

So, in other words, I'm getting a lot of bang for my buck in terms of the time I've spent. I'll be able to fold these improvements into my applications immediately. And, hopefully, that will improve their sales.

The other aspect of contributing to open-source projects is one I've discussed before: it's about giving back. I've benefitted from the labor of an entire community of developers, many of whom are unpaid. (Though, to its credit, Apple apparently sponsored Daniel Steffen's work on porting Tk to run on top of Cocoa.) I am glad to share the improvements I make to Tk with the larger community.

In another sense, as well, the time I'm spending is little different than time spent by dozens of other Mac developers who have to move their code from Carbon to Cocoa. Since 2007, Apple has made it forcefully clear that Carbon is dead, and Cocoa is the future. Tcl/Tk is hardly alone in this respect, and it is not late to the game either. The time I'm spending transitioning my applications to Tk-Cocoa, and the time I spend contributing improvements to Tk-Cocoa, will be abundantly repaid later on--repaid in the continued viability of my products, in their improved capabilities, and continued and increasing sales.

[/software] permanent link

Developer notes on Tk-Cocoa

My previous post focused on the user-visible changes in Tk-Cocoa, and how these will improve Tk applications on OS X from a user perspective. This post will focus on some of the technical changes of Tk-Cocoa, so that developers who have previously deployed Tk applications on OS X can smoothly transition their applications to the new framework. Despite assertions to the contrary, there are some "script-level" changes in Tk-Cocoa--that is, changes that will require adjustments to actual Tcl/Tk code to adapt to Tk's new Cocoa implementation.

Menu Changes

I'll quote from the Tk documentation on how certain menu items are handled, then discuss their practical import:

When Tk sees a menu as the first menu in a menubar on the Macintosh, that menu's contents make up the first items of the Application menu whenever the window containing the menubar is in front. After all of the Tk-defined items, the menu will have a separator, followed by all standard Application menu items. Such a .apple menu must be present in a menu when that menu is first configured as a toplevel's menubar, otherwise a default application menu (hidden from Tk) will be inserted into the menubar at that time and subsequent addition of a .apple menu will no longer result in it becoming the Application menu.

This means that when you set up a window's menubar, the last menu command you should run is something like this:

$w configure -menu .mb

Otherwise Tk's hard-coded application menu will blow away your custom application menu, and move it elsewhere in the menu display. This works differently than the Tk Apple menu in Tk-Carbon.

As an alternative, you can remove all references to the Apple menu, and define the procedures tkAboutDialog and ::tk::mac::ShowPreferences. These will replace the corresponding commands in the hard-coded Tk application menu. I have found this approach simpler than using the Apple menu. (If you define tkAboutDialog to use the new tk::mac::standardAboutPanel command, you get a Cocoa-native appliction "about" window.)

When Tk sees a .menubar.window menu on the Macintosh, the menu's contents are inserted into the standard Window menu of the user's menubar whenever the window's menubar is in front. The first items in the menu are provided by Mac OS X, and the names of the current toplevels are automatically appended after all the Tk-defined items and a separator.

This is the standard Cocoa "window" menu. This menu item is not present in Tk-Carbon, and so if you want something with that functionality, you have to code your own. (Which in fact I did, with my "windowlist" package. I have not yet decided whether to continue using my own package in my Tk-Cocoa applications or rely on the Cocoa menu, but it makes sense to leverage the built-in capabilities wherever possible.)

When Tk sees a menu on the Macintosh, the menu's contents are appended to the standard Help menu of the user's menubar whenever the window's menubar is in front. The first items in the menu are provided by Mac OS X.

This is the default Cocoa help menu, which looks for a specially formatted Apple Help book in your application bundle and pops up this dialog if one isn't found:

Tk-Cocoa help dialog.

This command tripped me up at first, since I strongly dislike Apple's built-in system for viewing user help and thus don't use it, and I thought other developers might find it confusing as well. If you define your own help command in your Tcl/Tk code and place it in the "help" menu, then your application will display two separate help commands--the standard Cocoa help command, and the one you've defined. This would be very confusing to end users. After providing Daniel Steffen some feedback about this, he implemented the tk::mac::ShowHelp command to override the standard Cocoa help menu item (you can also still include additional items).

Native Icons and Bitmaps

The coolest new feature of Tk-Cocoa is its ability to access system icons natively via the tk::mac::iconBitmap command. Tcl/Tk on Windows has long had this capability, and it's time the Mac got it as well. From the "Readme" file:

TkAqua provides access to native OS X images via the Tk native bitmap facility
(including any image file readable by NSImage). A native bitmap name is
interpreted as follows (in order):
- predefined builtin 32x32 icon name (stop, caution, document, etc)
- name defined by [tk::mac::iconBitmap]
- NSImage named image name
- NSImage url string
- 4-char OSType of IconServices icon
the syntax of [tk::mac::iconBitmap] is as follows:
tk::mac::iconBitmap name width height -kind value
where -kind is one of
-file icon of file at given path
-fileType icon of given file type
-osType icon of given 4-char OSType file type
-systemType icon for given IconServices 4-char OSType
-namedImage named NSImage for given name
-imageFile image at given path
This support was added with the Cocoa-based Tk 8.5.7.

Here's a script that illustrates how the command is used:

toplevel .f

set dir [tk_chooseDirectory]
set filelist [glob -directory $dir *]

foreach item $filelist {

tk::mac::iconBitmap $item 16 16 -file $item

puts "creating iconbitmap for $item..."

label .f.[lsearch $filelist $item] -bitmap $item -text [file tail $item] -compound left
pack .f.[lsearch $filelist $item]


And here's what that looks like:

Native Mac icons, rendered by Tk.

This command was causing a hard-to-isolate crash in Tk; thanks to Daniel Steffen for tracking it down and fixing it. Now that the command is stable, it's the jewel of Tk-Cocoa, in my view.

What Tk-Cocoa Can't Do

My last post also said that it wasn't possible to render a "unified toolbar" in Tk-Cocoa. That isn't entirely accurate. Through a combination of Mac-specific configuration items (specifically, setting the window's style to "metal," and drawing many widgets with the "systemTransparent" background), it is possible to closely emulate the unified toolbar, as the screenshot below shows.

Tk-Cocoa unified toolbar.

However, the resulting application window has serious usability issues. The window "flashes" when it's resized, and it can also be dragged around from any point on the window, instead of just from the titlebar, which is standard Mac behavior. (Apparently exposing the underlying "metal" background of the window via the "systemTransparent" background causes some of these issues.) The fact that the window can be dragged from any point makes it hard to select and delete text from the entry field, for instance. It gives the entire window a jerky, unpleasant feel.

In this case, I'm going to forego the native Mac appearance for something that looks a bit less native (see the other application screenshot in my previous past) but is more usable.

There are some other things still missing from Tk-Cocoa as well: native drag-and-drop integration and native, non-command-line printing are two of the biggest gaps. However, these capabilities are not part of Tk's core on other platforms, either, such as Windows. Extensions for such capabilities exist, but they either have not been ported to the Mac or depend so heavily on Tk's platform-specific implementation (i.e. Carbon) that they need to be rewritten for Cocoa.

No matter. All in all, Tk-Cocoa is a big step forward for Tk developers on the Mac, and I hope these notes provide some assistance in getting other Tk applications to work with it.

[/software] permanent link

User notes on Tk-Cocoa

The Tk-Cocoa port has now been merged into the main line of Tk development, and will be the standard going forward as Tk 8.6 moves toward final release. The Tk-Cocoa developer, Daniel Steffen, is also graciously maintaining a version of Tk-Cocoa that is based on Tk 8.5, the current production release of Tk. (It's unusual for such sweeping changes to a programming framework to be incorporated into the current release.)

In using Tk-Cocoa to develop a new application, I've run across a few bugs--errors or problems in the software--that required some fixing. Specifically, the new command to retrieve native Mac icons causes occasional crashes--my program would just quit without explanation. I've also submitted a couple of patches (partial updates to the software) to improve a few of its features: specifically, the notebook widget now uses modern tabs for its layout, and a table column header now renders in standard Aqua blue when it's selected. Both Daniel and Csaba Nemethi, the developer of Tablelist--a table widget for Tcl/Tk that is similar to the table layout you see in the Mac's Mail application--have used these bug reports and patches as the basis for updates and improvements, for which I thank them. These changes greatly enhance Tk's appearance and platform integration under OS X. Note the screenshots below:

The updated Tk-Cocoa notebook display.

The updated Tk-Cocoa column display, with "Aqua-blue" column header and sorting arrow.

Based on these updates, nearly all of my long-term complaints about Tk on the Mac have been addressed. As a result, I'm moving full speed ahead with development of an application on Tk-Cocoa, and I'd like to highlight some of the ways Tk-Cocoa will enhance my software. I'd also like to highlight some of the changes that Tk-Cocoa requires. (Despite the claim that Tk-Cocoa requires no "script-level" changes, this isn't entirely true.)

Tk-Cocoa in Use

Here's a Tk-Cocoa-based screenshot from the application I'm currently developing, NameFind, which is a file-search tool:

NameFind under Tk-Cocoa.

And here's a screenshot from an older version of the application, which I discontinued a couple of years ago, with Tk's older Carbon implementation:

NameFind under Tk-Carbon.

You'll notice some immediate differences. The Tk-Cocoa version uses native Mac icons, retrieved on the fly from the system like other Mac applications, such as Finder. The Tk-Carbon version uses generic images, because it could not render Mac icons correctly. The Tk-Cocoa version also correctly implements the sorting layout of a Mac table view, with the column header rendering its selected status natively ("Aqua-blue"). The Tk-Carbon version didn't support this.

From a user standpoint, the advantages of the Tk-Cocoa version are pretty clear-cut. It offers superior visual integration with OS X, making it easier for users to be productive. No need to take a close look at the file, for instance, to figure out what kind it is; the native icon provides a visual cue. Similarly, the "blue" column header makes it immediately obvious which column is being sorted.

Under the hood, there's another advantage: I've compiled NameFind as a 64-bit application, which is the direction all Macs are going. 64-bit allows increased memory usage, and can improve performance.

Changes that Tk-Cocoa Requires

I'm still discovering some of the ways that Tk-Cocoa differs from Tk-Carbon. For one thing, some commands seem to work a bit differently. As an example, a command for handling window closing and application shutdown doesn't work quite as expected; I think it's a bug, which I've reported on the appropriate Tk developer tracker. I can work around this bug in my programs, but it may require a bit of additional code on my part. I've also found, as you can see in the application screenshot above, that Tk-Cocoa doesn't access certain aspects of Mac UI appearance very well; the "unified" toolbar so prevalent in Mac applications today is an example of this. The help menu, the window menu, and other things also differ a bit. (I'll have more to say about the technical details of Tk-Cocoa in a subsequent post.)

All in all, however, I'm very pleased with the improvements that Tk-Cocoa is allowing my software. My software will benefit from an improved UI appearance, improved 64-bit performance, and continued viability on OS X.

[/software] permanent link