Top.app
One thing that’s always bothered me about MacOS X’s Terminal.app is that you
can’t really run multiple applications. Technically you can but it’s not right
having to switch to Terminal and then cycle through the windows to get to the
one you want.
And I’m not talking about being able to have multiple shells running so keep
your iTerm has tabs
bullshit to yourself. I use
GNU/Screen for that and am quite happy
with it.
There’s a handful of textmode tools I’d like to be able to run as if they were all out Mac applications like Mutt, irssi, elinks, and Vim.
Some of the more popular textmode tools have graphical versions. Mac Vim is solid. AquaEmacs was a little wonky the last time I played with it. MacIrssi sucks because you can’t use plugins and, really, what’s the point of using a shitty textmode anything if you can’t customize the piss out of it?
We need Terminal.app to be a generic container for all of the textmode tools
we’d like to pull up to first-class application land. The good news is that,
after reading this article, you’ll be able to do just that. The bad news is that
it requires quite a bit of work and the technique is pretty nasty. I would even
go so far as to call it a big giant hack.
To illustrate, we’re going to turn top into a standalone application:
Top.app. Yes, even a tool as humble as top ought to have its own bouncy Dock
icon and Command+Tab target. We’ll use it as a backup for Activity Monitor
the next time it goes all beach-ball on us.
We need another .app
The first thing I don’t like about this approach is that you have to copy
Terminal.app in its entirety. I recommend the Applications directory
under your $HOME:
$ mkdir -p ~/Applications # this may already exists
$ cp -r /Applications/Utilities/Terminal.app ~/Applications/Top.app
Without doing anything else, you can run Top.app and get a separate item in
The Dock and Command+Tab.
Open it from Finder, or:
$ open ~/Applications/Top.app
Changing The Menu
The menu still says “Terminal”, which is kind of annoying. We can change
this without too much hassle by editing the InfoPlist.strings file under your
locale’s directory. Check this out:
$ cd ~/Applications/Top.app/Contents/Resources/English.lproj
$ cat InfoPlist.strings
"CFBundleHelpBookName" = "Terminal Help";
"CFBundleName" = "Terminal";
"NSHumanReadableCopyright" = "? Copyright 1995-2003 Apple Compute ...
We need to open the InfoPlist.strings file in an editor that’s UTF-16 aware and change
the CFBundleName value from “Terminal” to “Top”. Vim worked swimmingly for
this task and OmniOutliner actually has a special graphical mode for strings
files. But you can open it in TextEdit if neither of those is available to you:
$ open -a TextEdit InfoPlist.strings
Once saved, you can quit and start Top.app again and you should now see
“Top” in the menu instead of Terminal.
Changing The Icon
The hard part about this step is finding an .icns file for the tool you’re
running. top is the command-line equivalent of Activity Monitor, so let’s
just grab the icon from there:
$ cd ~/Applications/Top.app/Contents/Resources
$ cp icon.icns{,.orig} # backup original icons file
$ AM=/Applications/Utilities/Activity\ Monitor.app
$ cp "$AM/Contents/Resources/ActivityMonitor.icns" icon.icns
Note that the new icon won’t show up until you restart Finder. In most tutorials, this is where you logoff and back on. Fuck that:
$ killall Finder
TIP: If you have Apple’s Developer Tools installed, you can find
more icns files in the wilderness that is /Developer/Applications.
Customization
Now comes the sickest part of the hack.
We’re presented with a bit of a dilemma. We want our Top.app window to be
fully customized and we also need a specific command to be executed
(/usr/bin/top). That’s not the problem - Terminal.app stores these types
of customization in .term files, which are easily created by opening a
terminal, customizing it using the inspector (Command+I), and then saving it
(File -> Save As or Command+Shift+S). When you save the .term file
there’s an option labeled, Open this file when Terminal starts up and this
is the problem: the setting applies to all Terminal applications (even
copies) because the default .term file is set as a user global preference in
~/Library/Preferences/com.apple.Terminal.plist. So, if we open Top.app as
is, customize it, save it and check that box, we’ll end up loading the
Top.term file when any terminal is launched.
But it’s okay because Mac applications turn out to be extremely hackable. On most systems, you’d be getting out your hex editor and patching binaries. But not here - changing the preference property list used by an application turns out to be trivial:
$ cd ~/Applications/Top.app/Contents/
$ grep -A1 CFBundleId Info.plist
<key>CFBundleIdentifier</key>
<string>com.apple.Terminal</string>
See that? Rock! All we need to do is change com.apple.Terminal to something else, like
com.rtomayko.Top. You can open the file in the nice little Property List Editor.app and
change the CFBundleIdentifier property or you can start using your machine as God intended:
$ perl -pi.orig -e 's/com\.apple\.Terminal/com.rtomayko.Top/'
$ grep -A1 CFBundleId Info.plist
<key>CFBundleIdentifier</key>
<string>com.rtomayko.Top</string>
It’s smooth sailing from here on out. Open Top.app and you should get a little white terminal
window. Run top -s1 -ocpu at the prompt so we can get a feel for how the window should be
dimensioned. Bump the font size up about 5 times using Command + and then resize the window so
that the top output fits just right.
Next, hit Command+I to get into the inspector, and customize it as you see fit. Here
are the settings I used for each of the customization areas:
- Shell - When the shell exits, close the window.
- Processes - Prompt before closing window: never.
- Buffer - Buffer Size: Disabled (there’s no need for a scrollback buffer in cursors apps).
- Display - Text: Bitstream Vera Sans Mono, Anti-aliasing, Disable Blinking Text.
- Color - Green on Black, Transparency.
- Window - Title: “Top”, disable everything else.
Now, hit Command+S to save the .term file. You get a normal Save As dialog with a few
extra options. Enter “Top” in the Save As box, you want to save the Main Window, you want to
open this file when Terminal starts up, and you want to execute the following command:
exec /usr/bin/top -s1 -ocpu
You also want to check the Execute command in a shell box (it’s the only way I’ve found that let’s you pass arguments).
Save it and Quit. If everything went right, you should be right back where you left the next
time you open Top.app.
Lather, Rinse, Repeat
To sum up, the basic steps are as follows:
- Copy
Terminal.apptoFoo.app. - Edit
Locale.lproj/InfoPlist.stringsfor the menu andInfo.plistfor the preference. - Overwrite
icon.icnswith a distinct.icnsfile. - Open
Foo.app, customize, save.termfile as Default.
Issues / Ideas
This approach has drawbacks and limitations:
-
It’s not correct.
Terminal.appshould provide a mechanism for achieving these results without all the hackery. -
Updates to
Terminal.appwill not automatically be picked up. It may be necessary to go through the process after an update. -
I have not been able to figure out if it’s possible to open files or pass arguments to these applications otherwise.
I’m considering throwing together a quick shell script that’s capable of
performing the nitty gritty aspects given a directory containing a few files:
the .icns file and maybe some kind of simple config file that contains the
values needed for the Info.plist.



