I puzzled for a few hours over this the other night - it’s something that used to work in VirtueDesktops, and for some reason I just assumed it no longer functioned under Mac OS X 10.5. Aside from an embarrassing bout of forgetting to get the window number properly, this turned out to be remarkably simple.
Prerequisites
You’ll need a copy of the CGSPrivate header in your project.
How to move a window between workspaces
Simply use the following code, where ibo_window is an Interface Builder outlet to an NSWindow in your XIB file:
CGSWindowID windowId = (CGSWindowID)[ibo_window windowNumber];
// The following integer represents the space you want to move the window to - the array is not zero-based - Space 1 == 1, Space 2 == 2, etc
NSInteger spaceToMoveTo = 2;
// Window count can be more than one, but for this example we're using a single window
NSInteger windowCount = 1;
// Now for the magical call:
CGSMoveWorkspaceWindowList(_CGSDefaultConnection(), &windowId, windowCount, spaceToMoveTo);
// If you want to check which space a window is on, simple use the following code:
NSInteger windowId = -1;
CGSGetWindowWorkspace(_CGSDefaultConnection(), windowId, &workspaceID);
NSLog(@"Your window is now on space %i", windowId);
Easy, huh? I’m pretty sure this won’t work across processes (that’s why all the old desktop managers insert code into the running Dock application - it’s one of the only applications that has permission to muck about with other application’s windows). You should also probably try to intercept any errors thrown by the CGS* methods, but I’ll leave that as an exercise to you, gentle reader.
About 12 months ago, I had a conversation with a friend of mine that convinced me it was time to try my hand at writing a commercial software product. At the time, I had only very recently dropped development of VirtueDesktops and was seriously considering just taking a break from Mac development for a while - thankfully I didn’t, and today I’m releasing the fruits of 12 months of learning and hard work: Hyperspaces 1.0 Public Preview.
So what’s this all about, you ask? Put simply, Hyperspaces works hand-in-hand with Apple’s Spaces to add back a few key features that traditional virtual desktop applications provide, such as:
- Different desktop backgrounds per-space;
- Coloured tinting of desktop backgrounds per-space;
- Naming of each space;
- Desktop labels that show each space’s name;
- Customisable hotkeys to switch directly to each space;
- and more!
I’ve got quite a few features on the drawing board including a much more customisable switcher and more customisation options for each space.
I also need to thank quite a few people who’ve been a huge support and invaluable resources:
- My girl Leah - you can have your boy back for a bit now sweetheart :)
- Jan Van Boghout for all of the code and advice at every stage of development;
- Sean O’Brien for the kickass space selector view in the preferences (and quite a few other groovy graphical doodads!);
- Steve Voida who helped reverse engineer quite a number of new private CGS calls (thanks Steve!);
- Nik Youdale and Zac Cohan from Aqualia for advice and crazy code that I barely understand;
- Chris Forsythe for the kick in the pants to do this in the first place;
- Sebastiaan De With for the incredible application icon;
- Neil Ang, James Pamplin and Dean Robinson - for constantly, consistently pestering me to finish this app - you guys are awesome to work with - roll out, CocoaBots!
It’s been a long and rewarding road over the last year, and I wouldn’t trade a minute of it but here’s a couple of things I’ll know not to do next time:
- Working full-time while trying to get your first product off the ground is really hard - I found taking a break once every few weekends really made a difference;
- Don’t buy a house in the middle of writing your first application (on top of working full time);
- Don’t start renovating a house in the middle of writing your first application (on top of … you get the picture);
- Be ready to drop features for 1.0. The Hyperspaces alphas had some great features that will probably come back in a future release, but they weren’t critical to what I am trying to achieve with Hyperspaces;
I’ll post a post-mortem that goes into some detail about the programming challenges I faced in a few days. OK, enough rambling from me - go download the preview and let me know what you think!
Uploaded with plasq’s Skitch!
You’ve seen it before - Exposé’s F-10 mode stops working for no apparent reason. F-9 is still good to go, but F-10 just looks busted.
Why?
Your application has set one of it’s NSWindow instances to the desktop level or lower (kCGDesktopIconWindowLevel or kCGDesktopWindowLevelKey are where it all seems to start).
Can I fix it?
Yes - fixing this problem is simple - either stop using windows at or below the desktop icon level, or add the following code to a window category or subclass in your project and execute the “clearExposeTags” method upon an active instance of your troublesome NSWindow. If you’re using CGSPrivate.h, you can just include the method without all the typedefs and externs.
typedef int CGSConnection;
typedef int CGSWindow;
typedef enum {
CGSTagNone = 0, // No tags
CGSTagExposeFade = 0x0002, // Fade out when Expose activates.
CGSTagNoShadow = 0x0008, // No window shadow.
CGSTagTransparent = 0x0200, // Transparent to mouse clicks.
CGSTagSticky = 0x0800, // Appears on all workspaces.
} CGSWindowTag;
extern CGSConnection _CGSDefaultConnection(void);
extern CGError CGSClearWindowTags(const CGSConnection cid, const CGSWindow wid, CGSWindowTag *tags, int thirtyTwo);
- (OSStatus)clearExposeTags
{
CGSConnection cid;
CGSWindow wid;
CGSWindowTag tags[2];
wid = [self windowNumber];
cid = _CGSDefaultConnection();
tags[0] = 0x02;
tags[1] = 0;
return CGSClearWindowTags(cid, wid, tags, 32);
}