13

Let's say I want to write a simple Cocoa app to make the Spaces feature of Leopard more useful. I would like to configure each space to have, say, different

  • screen resolutions
  • keyboard layouts
  • volume (for audio)

So there are two parts to my question:

  1. I suppose there are ways to modify these three things independently of Spaces, right? If so, how?
  2. How can I detect in my app when a space change occurs, and when that happens, determine what space the user just switched to? Does Leopard send out some distributed notifications or something?

Update: There has to be some public API way of doing this, judging from all the Spaces-related apps on the Mac App Store.

Enchilada
  • 3,859
  • 1
  • 36
  • 69
  • I don't know how it is done, but there's an open source app called WhichSpace on GitHub. You could take a look at its source code. – iconoclast Aug 30 '23 at 00:00

2 Answers2

12

As Peter says, in 10.6 you can use the NSWorkSpace NSWorkspaceActiveSpaceDidChangeNotification to get a notification when the workspace changes.

You can then determine the current space using Quartz API, the kCGWindowWorkspace dictionary key holds the workspace. e.g:

int currentSpace;
// get an array of all the windows in the current Space
CFArrayRef windowsInSpace = CGWindowListCopyWindowInfo(kCGWindowListOptionAll | kCGWindowListOptionOnScreenOnly, kCGNullWindowID);      

// now loop over the array looking for a window with the kCGWindowWorkspace key
for (NSMutableDictionary *thisWindow in (NSArray *)windowsInSpace)
{
     if ([thisWindow objectForKey:(id)kCGWindowWorkspace])
       {
           currentSpace = [thisWindow objectForKey(id)kCGWindowWorkspace] intValue];
           break;
       }
}

Alternatively you can get the Space using the private API, take a look at CGSPrivate.h which allows you to do this:

int currentSpace = 0;
CGSGetWorkspace(_CGSDefaultConnection(), &currentSpace);

To change the screen resolution you'll want to look at Quartz services, for altering the volume this may be helpful.

El Developer
  • 3,345
  • 1
  • 21
  • 40
BendiLow
  • 467
  • 4
  • 9
  • Thanks. But what if there are no windows in the space? Can that case be handled via public API? – Enchilada Jun 05 '11 at 14:30
  • 3
    In your app create a transparent window and set it join all Spaces, then look for that in the array of windows. To set a window to be on all spaces use this: [transparentWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces] – BendiLow Jun 05 '11 at 22:03
  • 1
    When using `kCGWindowWorkspace` I noticed that the Space ID changes after a reboot for spaces after the first one (on Lion). That makes storing the ID pretty much useless... Is there another public API for this? (Maybe related to this: http://openradar.appspot.com/9241430) – Mark Jan 08 '12 at 06:27
  • I know this is an old question, but is NSWorkspaceActiveSpaceDidChangeNotification still relevant? I can't seem to get it to work. I'm new to mac development, so may be missing something. I'm trying to get notified any time the user switches the desktop space and observe this notification in the app delegate. What am I missing? – chetem May 04 '16 at 04:51
  • 2
    I know this answer is 9 years old, but I thought I would give a heads up that kCGWindowWorkspace is no longer available. Trying to use it gives the error message: 'kCGWindowWorkspace' is unavailable in macOS: No longer supported. Looks like it was deprecated in macOS 10.9 – yesthisisjoe Apr 27 '20 at 20:32
6

NSWorkspace posts a NSWorkspaceActiveSpaceDidChangeNotification on its own notification center, but only on Snow Leopard.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • 2
    Yes, but that notification only tells you that the space changes. But there no userInfo dictionary with that notification with info like what is the current space, etc. So it's not really a powerful notification.. – Enchilada Mar 13 '10 at 23:36