Thehotfix.net Logo                            To the forums          

 How to create a SmackBook Pro

 

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.

 

Video on Smackbook pro, Click here!!

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.
  1. Install and run the patched DesktopManager
  2. 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)
  3. Download amstracker from osxbook.com (I'm not allowed to redistribute it)
  4. Place the amstracker binary in the directory where you unzipped smackbook.zip.
  5. You should have a directory with the files amstracker, notify and smack.pl. From the terminal, in that directory, run the command perl smack.pl

 

*If you're on a PowerBook or iBook, the line

Rather than this:
my $x = $a[1]*256 + $a[0];

may need to be replaced with

my $x = $a[0];

Instead change it to :

my $x = $a[1];
NOT
my $x = $a[0];

The first value in the array (at least for my on my 12 inch PB) does not prove as useful as the second value. I suppose that the second value is the actual x value.

Also, to tweak sensitivity, you want to change the number 8 in this line:
if(abs($x) > 8 && $stable > 30) {
That is the absolute value that the x axis can go before it triggers the change.
Mine is set to 8 but you can change this to your comfort level.
my smack.pl in its entirety is here:
I don't know if the formatting works here, so just use it for reference, don't copy-and-paste.

use strict;

my $stable;

open F,"./AMSTracker -s -u0.01 |";
while() {
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] my $x = $a[1];

if(abs($x) $stable++;
}

if(abs($x) > 8 && $stable > 30) {
$stable = 0;
my $foo = $x system "./notify SwitchTo${foo}Workspace\n";
}
}

 

Special thanks to http://blog.medallia.com/2006/05/smacbook_pro.html for this how-to. Please take note that if any of the content was edited unintentionally, we apologise for it, and hope so that someone would alert us on Darylngch@thehotfix.net .


 

 

 

<