I usually keep two 20" screens side by side on my desk, so I can code on one and test on the other. I find I can work much faster if I can just make a change in Eclipse, and by the time I turn my head to the other screen, the tests have already run. My new laptop, however, has a 15" screen, which feels a bit cramped when I'm working away from the office. I've been using the fancy Desktop Manager by Richard Wareham, which is a very nice utility to let you keep several virtual desktops, and change between them easily.
Of course, if you're using something like Emacs or Butler, all your keys will be taken already, so you'll need to use some sort of Command-Ctrl-Shift-4 keystroke for the actual desktop switching.
Turns out, the laptop has a built-in motion sensor. Nominally, it's there to protect the internal hard drive. The basic idea is this: If the accelerometer suddenly notices that the gravitational pull of earth is no longer present, the most likely explanation is that the laptop, sensor and all, is currently accelerating at 9.81 m/s² towards said earth. In that case, it will (wisely) try to turn the hard drive off in preparation for impact.
It can, however, also be used in situations not involving lobbing the laptop across the room, fun though that may be.
All code in this post is released under the GPL.
Desktop Manager patch
First, you'll need to be able to control Desktop Manager from outside.
Cocoa has a nice class called NSDistributedNotificationCenter which can
handle simple message passing between applications. DM uses a notification
center internally to send "next desktop", "previous desktop" commands to
itself, so the patch just replaces the normal version with the distributed
version. I added the following to WorkspaceController.m, inside
the init method:
[[NSDistributedNotificationCenter defaultCenter] addObserver: self
selector: @selector(selectNextWorkspace)
name: NOTIFICATION_NEXTWORKSPACE
object: nil
];
[[NSDistributedNotificationCenter defaultCenter] addObserver: self
selector: @selector(selectPreviousWorkspace)
name: NOTIFICATION_PREVWORKSPACE
object: nil
];
To control all the windows in the system, an application needs to have
access to the CGSUniversalConnection; only one application can have that at
a given time, and the Dock tends to win the battle. Desktop Manager sneakily
uses mach_inject to inject its own code into the Dock
application. There's still no x86 version of the sweet, sweet
mach_inject library (Wolf! Help us!), so not all the Desktop
Manager features will not work on Intel.
Reading the sensor
For the actual sensor reading, I used amstracker by Amit Singh. He does not allow redistribution, so you'll have to get it directly from the source.
notify: Remote control for Desktop Manager
This 15-line program lets you send random notifications to any running application.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
[[NSAutoreleasePool alloc] init];
if(argc != 2) {
NSLog(@"Use: %s notification-name", argv[0]);
return 1;
}
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName: [NSString stringWithCString: argv[1]]
object: nil];
return 0;
}
Compile it with gcc -framework Foundation -o notify notify.m,
then call it with ./notify SwitchToNextWorkspace.
Actual motion interpreter
You can do arbitrarily fancy stuff here; this 10-line Perl script just
checks to see if the horizontal acceleration exceeds some threshold in
either direction, and calls the notify program.
use strict;
my $stable;
open F,"./AMSTracker -s -u0.01 |";
while(<F>) {
my @a = /(-?\d+)/g;
print, next if @a != 3;
# we get a signed short written as two unsigned bytes
$a[0] += 256 if $a[0] < 0;
my $x = $a[1]*256 + $a[0];
if(abs($x) < 20) {
$stable++;
}
if(abs($x) > 30 && $stable > 30) {
$stable = 0;
my $foo = $x < 0 ? 'Prev' : 'Next';
system "./notify SwitchTo${foo}Workspace\n";
}
}
Summary
Here's a self-contained zip file of the above patches.- Install and run the patched DesktopManager
- Download and unzip the zip file above (I just updated it with a
binary version of
notify, so you'll have to re-download it) - Download
amstrackerfrom osxbook.com (I'm not allowed to redistribute it) - Place the
amstrackerbinary in the directory where you unzipped smackbook.zip. - You should have a directory with the files
amstracker,notifyandsmack.pl. From the terminal, in that directory, run the commandperl smack.pl




