WorkspaceHack 1.1

Introduction

This documents WorkspaceHack, a set of perl scripts that patches the binary of NeXT's Workspace application to add support for two new options in the defaults database. These defaults are completely independent, and you can choose to use either one, both, or none of them. The installation program never modifies the standard system Workspace, rather it creates a copy as ~/Apps/Workspace.app, and if you already have one there it makes a backup. A simple procedure, which I explain below, can restore your system to its original state.

Workspace CustomEmptyRecyclerSound

This is the name of a sound file. If this default is set, and the named file is a valid sound file, Workspace will play the sound when you empty the recycler. I used SuperHack to change my recycler to a toilet, so I naturally chose the flush.snd that's available on sonata.cc.purdue.edu in pub/next/submissions/sounds. This hack makes deleting files so much fun that your disk space problems will be gone forever!

Workspace CustomEnvironmentCommand

This lets you set up the environment variables of the Workspace program itself, so that all applications you launch from Workspace will have the environment you want them to have. This is useful in Terminal/Stuart type programs, where the current compromise is to have every new shell read your .login file, which may not be ideal. Having a flexible environment is especially important to TeXview users like myself who have expanded the TEXINPUTS, etc., variables. TeXview needs to know those variables. My previous compromise was never to start TeXview from Workspace, rather always from a shell.

The value of this default is a string that gets passed to the shell. That is, it's something you could type in your terminal window. The command must print on standard output the entire environment you want programs to see. The format is that produced by printenv. The value of this default I use is:

    csh -c "source ~/.environment; printenv"

The file .environment consists of a bunch of setenv commands.  There can be any shell commands there as long as whatever they print is something you want to go into your environment.

Setting the environment by running a command is more flexible than reading a fixed environment from a file for two reasons.  First, you probably do shell variable substitutions in setting up your environment. For example, my .login contains

    setenv TEXINPUTS .:$HOME/lib/tex/inputs:/LocalLibrary . . .

If you're on a heterogeneous network you may want something like this:

    set machine=`sys` 
    set path = ( . ~/$machine/bin /usr/local/$machine/bin . . . )

By running a command to determine the environment, this new default lets you keep your current flexibility.

Installation

The software consists of two .c files, which are compiled into a binary image that is never itself run, and a slew of Perl scripts that examine and modify Mach-O files. I'm running perl version 4.0.1.4, patch level 10. Your mileage may vary with other versions. Some people may find the perl scripts to be of more general use. If you intend to use this program in conjunction with SuperHack, which is how you get a true multimedia toilet, then you must run SuperHack first.

You modify your Workspace by typing Install. There is no NeXTstep user interface.  Install is a perl script that drives other scripts, and does some poking around itself. If you've already run SuperHack, then you already have your own Workspace in ~/Apps/Workspace.app. In this case, Install will move Workspace.app/Workspace to Workspace.app/Workspace.orig, and install a new version as Workspace.app/Workspace, deriving from Workspace.app/Workspace.orig.

Install reads the value loginwindow->Workspace to determine if you already have a custom Workspace. If this default exists in the defaults database, Install interprets the value as the binary image of your Workspace. For some users this is wrong. Some users have created a shell script that sets up environment variables, maybe plays a sound, etc., and finally runs the real Workspace. These users specify the name of this shell script as the value for loginwindow->Workspace. If you do this, listen up. You need to make a temporary change to the value of your default from its current value to the name of the actual binary for Workspace. For example, something like this might be appropriate:

    dwrite loginwindow Workspace ~/Apps/Workspace.app/Workspace
    Install
    dwrite loginwindow Workspace ~/Apps/Workspace.app/WorkspaceStart

Remember, the above paragraph applies only if you have a loginwindow->Workspace default that doesn't point to the real Workspace.

If you haven't yet run SuperHack (do it first if you're going to), then Install derives from /usr/lib/NextStep/Workspace.app/Workspace and creates ~/Apps/Workspace.app.

The scripts all expect perl to be installed in /usr/bin. If you don't have it there, I'd suggest making a link there pointing to where you do have it. If you don't want to or can't do that, you need to edit the first line of the five executable perl scripts in the distribution. This should take only a minute.

Install will run

    dwrite loginwindow Workspace ~/Apps/Workspace.app/Workspace

at its completion, but you need to set up the two new preferences yourself. I've included a file CustomWorkspace.dset which shows the values I use. Here's what it looks like:

    Workspace CustomEnvironmentCommand "csh -c \"source ~/.environment; printenv\""
    Workspace CustomEmptyRecyclerSound /usr/cap/lib/Sounds/flush.snd

If you have DefaultMgr, which is a really awesome program, you can drag my .dset file into your defaults database. If you don't have it, you can put a ªdwrite º at the beginning of each line of the .dset file and then execute it as a shell script. However, you'll have to type the first one with different punctuation in the quotation marks:

    dwrite Workspace CustomEnvironmentCommand "csh -c 'source ~/.environment; printenv'"
    
Obviously, you should change the sound file preference unless your sound is under /usr/cap! Note that in the environment default, it's okay to use the ~ notation for your home directory, because that command is passed to the shell, which expands it. But the sound file default must be a complete path name not involving any shell stuff.

I've also included my ~/.environment as an example of what you might want to do. I have ªsource ~/.environmentº in my .login file, and I don't set any other environment variables in .login (though you can). This way I have only one file to change when I want to change my environment, and I get a consistent environment across all programs.

You need to log out and back in to start running the new Workspace, and also any time you change those defaults, since Workspace reads them only at start time.

Deinstalling WorkspaceHack

It's easy to restore your system to the original state before running Install. Here's how to do this. If you already had a custom Workspace, say because of having run SuperHack, you'd just say

    cd ~/Apps/Workspace.app
    mv Workspace.orig Workspace

If you didn't already have a custom Workspace, you'd do

    dremove loginwindow Workspace
    rm -rf ~/Apps/Workspace.app

Installing WorkspaceHack multiple times

If you run Install a second time, it will make the same additions to Workspace, but this time to the already modified executable (because it will find in your defaults database that you have a custom Workspace). This will work fine, but it will add the new code in again, after the first copy of the new code. So the new Workspace will be a little bigger than it needs to be. If you need to install again, it would be better to restore the system to the original state before running Install. The preceeding section tells you how to do this.

Programs that present special problems

Terminal, Stuart and the PATH variable

The programs Terminal and Stuart have an option to make the shells think they're login shells, causing them to read the .login file. I expect most people use this to set their environment in shells. Since you can now set the environment of Workspace, and hence programs it starts, you ought to be able to turn off the Terminal preference. However, there's one problem with that. Terminal and Stuart set the PATH variable for you before starting the shell, so changing the PATH variable of Workspace, and thus Stuart, won't change it for your shells. If you're using a recent Stuart, you can set the Stuart->ShellPaths default to be the path you want. Just set PATH up how you want in the shell, type echo $PATH, and paste the value into your defaults database.

Here's a pedantic example that makes the above problematic.  Suppose you're at CMU, where they change the system configuration every week. In this environment you have to change your path every time the system changes. In login shells you don't have a problem because you already have some complicated program you invoke to figure out the appropriate path for each login session. If you set up Workspace's environment the way I do, by invoking a shell on a little script like .environment, then you already have the path you want in everything but Stuart. Fortunately, there's a way to make Stuart use the path set by that script. Just place a line like

    dwrite Stuart ShellPaths "$PATH"

in your .environment file after you set PATH. With this, I don't see Stuart's fixed path as a limitation.

The Workspace Shell tool

The ªWorkspace Shellº tool, which you invoke from Workspace's Tools->New Shell menu, gets its environment through a different mechanism than other programs that Workspace starts. This mechanism allows only a fixed set of environment variables. The variables HOME, SHELL, USER, and PATH inherit their values from Workspace, so you are okay here. Workspace provides fixed values for TERMCAP, TERM, and Workspace, so you can't change those. Finally, Workspace doesn't pass to its shell any environment variables other than these, even if Workspace itself has other variables set. Remember, this paragraph applies only to the shell created by the New Shell command, not to programs in general.

Details on choosing a CustomEnvironmentCommand

The value of this default is a string passed to the popen(3) library routine. This means that the string will be executed by /bin/sh alwaysÐnever csh. So if you want your command to source a shell script, it must be a Bourne shell script. If you want to use a C shell script to set up your environment, you need to give a Bourne shell command to invoke the C shell.  Look at my above example to see how to do it.

The output of the command must be a list of (variable, value) pairs separated by an = sign, for example ªEDITOR=emacsº. This is exactly the format produced by the program printenv, so I set my environment up without printing anything, and then run printenv to show the new environment. Workspace takes verbatim the text printed by this command and makes it the entire environment of Workspace. Actually this isn't quite true, because Workspace adds a ªWorkspace=...º variable. If your command prints nothing, you will get an empty environment. The ªidentityº command, the one that leaves the environment unchanged, would be just ªprintenvº. But if you don't want to change your environment you needn't set the preference at all.  If you want just a constant environment, you could choose something like ªcat ~/my_environmentº, but that doesn't give you the usual flexibility of having the shell set up your environment, so I recommend my first example.

The exit status of your command must be 0. If it's not, Workspace retains the default environment. The normal exit status of programs is 0, so this is a check that your command succeeded.

A hack to try at home

If you use SuperHack or some other method to change your recycler images to something else, it's virtually canonical to change the File->Empty Recycler menu item to the appropriate label. Mine says ªFlush Toilet.º There are several other occurrences of the word Recycler in the Workspace user interface, and you should change them all if you want to be tidy. But the menu item that you press is the one that really must be changed.

Changing the text is easy, using Interface Builder. To change the menu item, extract the Workspace.nib section from the __NIB segment of Workspace, then use IB to change the text around in Workspace.nib, and finally replace Workspace.nib in Workspace. You should do this before running WorkspaceHack. You can extract and replace the nib files using segedit or SegHoarker, though I've had SegHoarker fail (without telling me!) more times than not.

What if it doesn't work?

The distribution comes with several three line configuration files of the form config.xxx. If there is no configuration file for your version of Workspace, Install won't be able to proceed, and it will tell you what to do. There's a file called PORTING.rtf that tells you how to make a configuration file for your system. This is easy and takes only about 10 minutes, so please do it and send me the result, so I can include it in future releases.

If Install completes its work, and the resulting Workspace doesn't work as expected, then something happened that I didn't anticipate. This has never happened to anyone, as far as I know, and if it ever does, I want to know about it. In the mean time, you want to get your system back to its original condition, and here's how.  If Workspace won't start at all, you'll have to do this from another machine or from a terminal connected to a serial port.  Type

    dremove loginwindow Workspace

to your shell. You should then be able to log in at the console, and you'll run the system default Workspace. If your NeXT console is the only way to log in, you can type ªconsoleº to the login prompt of loginwindow, and this will give you a non-NeXTstep interface, which will let you type the dremove command. If your computer is set up so you don't have to type a login name and password, then you have to crash your computer (hold both command keys and press `), boot in single user mode, and unset the default. If you don't know how to do this, uh, call me: (412) 361-6301. It's not hard, but it would be less error-prone if I talked you through it.

How compatible is this with other Workspace hacks?

The bottom line is that WorkspaceHack is likely work with other changes you've made to Workspace, but only if you run WorkspaceHack after making all other changes. (This means you should save a pre-WorkspaceHack copy of Workspace, so that you can make further changes.  Install does this for you.) If you want to know the details, keep reading this section.

I'll define two types of hacks. The first is a hack that modifies executable code. That's what WorkspaceHack does, and I don't know of any others that do. If there are any, they probably don't modify exactly the same code as WorkspaceHack, so they won't interfere. But I make no guarantees.

The second type of hack is one that modifies .tiff images, .nib files, and other non-code. This is what SuperHack does. These programs operate by replacing ªsectionsº of the Workspace executable. If the size of any section changes, some of the sections may need to be moved.  WorkspaceHack operates by installing new code at the end of the last section of the current Workspace, and then patching the standard executable part to jump into the new code. If the new code were to move, the hooks wouldn't connect to the right place. You can replace sections after running WorkspaceHack if you're very careful that you don't move any of the new code. My recommendation though is not to try it, because I can't think of a reason why you need to.

Future directions

An important concern for me is getting comments on what other changes you'd like to see in Workspace. I see this release of WorkspaceHack first as an addition of two things that had to be there (especially the toilet flush :-)), but also as a proof of conceptÐthat we can make existing programs more useful by patching the binaries. The perl scripts I've written are admittedly rough, but if you'll look at them you'll see an attempt to make them general enough that we can use them to make other patches, and patch other programs (Mail.app comes to mind).

I haven't tried grafting Objective-C code into Workspace, but I think it will work. If so, and if we can accurately determine the functionality of existing classes in an application, then the possibilities are limitless. Think about the class_poseAs function.  Anybody interested in a dock extender that's built into Workspace, and thus doesn't have any of the necessary limitations of separate-program-dock-extenders?

What things would you like to see added?

Thanks Brad!

Special thanks go to Brad Skrbec (skrbec@rtsg.mot.com) for getting this working on NeXTstep 2.2.

Chris Paris								August 5, 1992
cap+@cmu.edu							(412) 361-6301