Detecting when a space changes in Spaces in Mac OS

2019-01-21 15:37发布

问题:

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.

回答1:

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.



回答2:

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