Tl;dr See my Change Space app
In OSX Lion Apple dispensed with the simple and effective 2D spaces grids many people loved and relied on.
In its place, there is the more dynamic concept of ‘Desktops’, which can be created by the system on the fly, for instance when running a full screen app. Also, the system can re-order the desktops according to your use.
These dynamic features are of little use to power users, who know where their apps and windows are, and like to navigate fast between them. A common layout is a 3×3 grid – then from the central space you can reach 4 others with just one keypress. Very useful for flicking between your code editor, and the browser, and perhaps mail, or iTunes for instance.
Even the animation when moving between desktops on Lion is slower than with the old Spaces system, making it really feel like a big step backwards for usability.
I’m not the only who feels this way – see stackoverflow here http://stackoverflow.com/questions/6768684/osx-lion-applescript-how-to-get-cu… … and there’s even a facebook page here https://www.facebook.com/pages/Save-Spaces/216451795053936
While many still hope that Apple will bring back the old Spaces system as an option, in the mean time something needed to be done.
Having found some clues on the stackoverflow post mentioned above, I thought I’d have a go at writing an app to do the directional switching.
If there’s one thing I hate it’s applescript. But, it has its uses. The first thing to do was to try a few little scripts to see if I could get to a particular desktop.
To run this from the command line I needed this kind of incantation
arch -i386 osascript changespace.applescript 4
And it worked – if you don’t happen to have any modifier keys other than control pressed, and if you don’t try to go to any desktop above number 4
Not good enough, but the information will come in use later.
There was a gist linked from the stackoverflow post that contains a few lines of code that can both find the id number of a desktop (they are no longer numbered sequentially – see here for an interesting post about this), and can move you to a particular desktop by sending a message to CFNotificationCenter.
This is almost everything we need. There is a wrinkle though – it appears that desktop 1 is special, and this code cannot navigate to it.
Also desktop 1 always returns the id number 1 (as opposed to some random 5 or 6 digit number).
Putting it together
At first, I made a short shell script for each direction, that ran the compiled C code or some applescript, and hooked those scripts up to Alfred.app using the Global Hotkeys feature (which is very handy by the way).
This was a disaster. Alfred starts a shell to run the shell script in, but this inteferes with the current showing desktop (because I have my terminals set to appear on desktop 5). So although I could see movement, it wasn’t useful.
So I need an app
What better time to have a play with macruby?
There are plenty of resources on the net to help you get started.
So I got macruby installed, and got myself set up in Xcode with a new app, Change Space.app.
One of the really cool things about macruby is the total integration with Objective C message passing. Everything just works together with Ruby method calls like magic. Really, it’s great – skim through this introduction if you are interested.
As I don’t know a way of directly calling C functions from macruby, I wrote a bridge class that calls them for me using Objective C messages that I can send from macruby.
So with this bridge over to the existing C code for changing and identifying spaces, I’m part of the way there.
For switching to desktop 1 I still need to send a keypress – after some investigation I found that the ScriptingBridge framework is the answer.
Here’s how I send a keypress using it:
It was rather opaque how to send the control down, and to be honest I have no idea how you would send something like control-shift. But no matter, we have what we need.
I still needed to hook the hotkeys. And I have davedelong to thank for the answer, DDHotKeyCenter.
For the next part, I wanted a status bar icon like the old spaces app. This gist was helpful, and the code is simple to adapt.
As people have different layouts for their spaces, I needed to set some preferences. In fact you can set a preferences panel up in the interface builder without much effort, see this guide from Apple.
To access the settings from macruby is simple:
defaults = NSUserDefaultsController.sharedUserDefaultsControllerlayout = defaults.values.valueForKey("gridLayout")
I added a few icons, and Bob’s your uncle – Change Space.app v1.
Celebrate with Champagne
Well, maybe not (oh ok just a sip). The app is not perfect in any way – the biggest niggle is that holding the shift key down after commanding a move to space 1 causes that movement to fail. Hopefully that can be solved.
But there are other niggles – it would be really nice if we could make the desktops move in the right directions. And if we could get notification of when the active desktop changes then the desktop number indicator on the status bar could be there at all times.
Anyway, the beauty of github is anyone can contribute – so please go ahead and fix it!