Is it possible to determine if the "Displays have separate spaces" option is checked in OSX Mavericks? I found the option is stored in com.apple.spaces.plist with name "spans-displays" but this code doesn't work with sandboxing:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] init];
[userDefaults addSuiteNamed:@"com.apple.spaces"];
NSLog(@"%i", [[userDefaults objectForKey:@"spans-displays"] integerValue]);
[userDefaults release];
Thanks!
To my knowledge there is no simple API to discover this, Apple have never provided comprehensive API relating to Spaces.
However, with a bit of lateral thinking you can figure it out.
What is a distinctive feature of displays having separate spaces?
There are multiple menubars.
So "Are there multiple menubars?" has the same answer as "Do displays have separate spaces?"
Is there an API to tell you if a screen has a menubar?
Again, not to my knowledge, but can we figure it out?
NSWindow
has an instance method constrainFrameRect:toScreen:
which given a rectangle, representing a window frame, and a screen returns an adjusted rectangle where at least part of the rectangle is visible on the screen. Furthermore, by definition if the top edge of the rectangle is above the menubar area the rectangle will be adjusted so the top edge abuts the menubar...
Which means if we pass it a rectangle abutting the top edge of the screen the returned rectangle will abut the top edge of the menubar, provided there is a menubar. If there is no menubar then the returned rectangle will have the same top edge.
So we can determine if there is a menubar and its height. One small wrinkle, as constrainFrameRect:toScreen:
is an instance method we need a window, any window, to make our code work.
Here is one way to code this as a function:
CGFloat menuBarHeight(NSScreen *screen)
{
// A dummy window so we can call constrainFrameRect:toScreen
NSWindow *dummy = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered defer:YES];
// create a small rectangle at the top left corner of the screen
NSRect screenFrame = screen.frame;
NSRect testFrame = NSMakeRect(NSMinX(screenFrame), NSMaxY(screenFrame)-30, 30, 30);
// constrain the rectangle to be visible
NSRect constrainedFrame = [dummy constrainFrameRect:testFrame toScreen:screen];
// did the top edge move? delta = 0 -> no, delta > 0 - yes and by the height of the menubar
CGFloat delta = NSMaxY(testFrame) - NSMaxY(constrainedFrame);
return delta;
}
So now we can tell if a particular screen has a menubar. How about more than one screen?
Well NSScreen
's class method screens
returns an array of all the available screens, so all we need to do is call our menuBarHeight
function on each screen and see how many menubars we find.
If we find more than 1 then we've determined that displays have separate spaces.
Here is one way to code that, again as a function:
BOOL haveIndepenantScreens()
{
BOOL foundMenuBar = NO;
for (NSScreen *aScreen in NSScreen.screens)
{
if (menuBarHeight(aScreen) > 0)
{
if (foundMenuBar)
// second menu bar found
return YES;
else
// record found first menubar
foundMenuBar = YES;
}
}
return NO; // did not find multiple menubars
}
Job done :-)