Question

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!

Was it helpful?

Solution

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 :-)

OTHER TIPS

use

NSScreen.screensHaveSeparateSpaces

Not sure when this appeared in the documents, but it is there as of 2021! One advantage of this over @CRD's excellent answer is that it works even if the user has selected 'Automatically hide and show the menu bar'

credit for the answer to @chockenberry

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top