Cocoa - resize window to full screen. Dual display - objective-c

I'm try resize window for two display.
On yosemite much depends on the [NSScreen screensHaveSeparateSpaces] - "Displays have separate Spaces" setting.
If screensHaveSeparateSpaces is set to NO, I can resize NSWindow to all screens, and set [window setLevel:CGShieldingWindowLevel()], and this will work.
But if screensHaveSeparateSpaces is set to YES, I only see half of the window. I'm trying:
NSDictionary *opts = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSFullScreenModeAllScreens,
nil];
NSView *view = [window contentView];
[view enterFullScreenMode:[NSScreen mainScreen] withOptions:opts];
NSRect frame = [view.window frame];
frame.size.width *= 2;
[view.window setContentSize:frame.size];
NSView resize to all screen this is true, but NSView fills my left-hand primary display - the secondary (right hand) display stays black.
How can I resize NSView to fullscreen (dual display) if screensHaveSeparateSpaces is returning YES?

You can't. A window exists in one space only. If each screen has a separate space, then you can't have one window on both screens. Your best bet would be to try to fake it by having two windows, one in each space, but I'm not even sure that would be possible. Assuming you can even have an app with windows in multiple spaces, it'd be non-trivial to try and keep the two windows in sync with each other.

Related

OSX Fullscreen (Kiosk) Application with Custom Resolution

I have an OS X Metal application that I would like to run in fullscreen at a non-native resolution, e.g. my native resolution is 1920x1080 and I would like to render the app in fullscreen at 1024x768. (I don't believe that using Metal to draw things impacts this question other than I am unable to use the OpenGL-specific NSView functions.)
My renderer uses a back buffer with a hard-coded size of 1024x768.
When I create my window with bounds = 1024x768 I get a fullscreen window, but my content is drawn centered and it does not stretch to fill the whole screen.
When I create my window with bounds = 1920x1080 I get a fullscreen window, but my content is drawn in the upper-left corner and incorrectly scaled (because of the ratio mismatch between the two resolutions).
Using [NSView - enterFullScreenMode:withOptions:] yielded the same results. Setting [NSView autoresizingMask] didn't change anything either.
Ideally I want the window to be the size of the screen and have the low-resolution back buffer be stretched to fill the whole window. What am I missing that would allow me to do that?
The relevant app initialization from my NSResponder <NSApplicationDelegate>:
// Create the window
self.Window = [NSWindow alloc];
[self.Window initWithContentRect:bounds
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:YES];
// Create the view
self.View = [NSView alloc];
[self.View initWithFrame:bounds];
[self.View setWantsLayer:YES]; // The generated layer is CAMetalLayer
// Associate the view with the window
[self.Window setContentView:self.View];
// Misc
[self.Window makeKeyAndOrderFront:self.Window];
[self.Window setAcceptsMouseMovedEvents:YES];
[self.Window setHidesOnDeactivate:YES];
// Fullscreen
[self.Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
[self.Window toggleFullScreen:nil];
[self.Window makeFirstResponder:self.View];
Thanks.
The layer that backs a view is constrained to have its frame equal to that view's bounds. By default, the drawableSize of a CAMetalLayer is equal to its bounds times its contents scale. However, you can set it to any size you desire by explicitly setting the layer's drawableSize.

NSLayoutConstraint Prevents NSWindow Resizing

I am adding some simple constraints to an NSView that I have in my main NSWindow but it is causing problems.
Normally I can resize my application window (just like any Safari/Finder window etc.). I add a simple NSView to my window like so:
[self.blackDimOverlay setFrame:NSMakeRect(0, 0, self.window.frame.size.width, self.window.frame.size.height)];
[self.blackDimOverlay setAlphaValue:0.5f];
[self.window.contentView addSubview:self.blackDimOverlay];
This works as expected. I then add two constraints to this view so that it stays the full size of the window when resized.
NSDictionary *viewsDict = NSDictionaryOfVariableBindings(_blackDimOverlay);
NSArray *constraintHorizontalOverlay = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[_blackDimOverlay]-0-|" options:0 metrics:nil views:viewsDict];
NSArray *constraintVerticalOverlay = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[_blackDimOverlay]-0-|" options:0 metrics:nil views:viewsDict];
[self.window.contentView addConstraints:constraintHorizontalOverlay];
[self.window.contentView addConstraints:constraintVerticalOverlay];
However, after adding these two constraints, they lock my window up, so I can't resize it anymore. Everything else works as normal, but the constraints block any window resizing.
How can I keep my subview the full-size of my window while being able to resize my window?
Thanks.
There are additional constraints on _blackDimOverlay which dictate its size and are of higher priority than NSLayoutPriorityDragThatCanResizeWindow. You can investigate using:
NSLog(#"%#", [self.window.contentView constraintsAffectingLayoutForOrientation:NSLayoutConstraintOrientationHorizontal]);
NSLog(#"%#", [self.window.contentView constraintsAffectingLayoutForOrientation:NSLayoutConstraintOrientationVertical]);
Most likely, you forgot to do [_blackDimOverlay setTranslatesAutoresizingMaskIntoConstraints:NO].
Alternatively, the view class of which _blackDimOverlay is an instance defines an intrinsic size and its hugging and compression-resistance priorities are higher than NSLayoutPriorityDragThatCanResizeWindow. You would need to reduce those priorities using -setContentHuggingPriority:forOrientation: and -setContentCompressionResistancePriority:forOrientation:.

How to display on dual screens on Mac OS X Lion

I want my app to be displayed on both laptop screen and an external screen with two separated NSWindow, I can't find any document about how to implement it. Any hint?
Thanks
The OS X OpenGL Programming Guide shows the old way of making a full-screen window:
Create a screen-sized window on the display you want to take over:
NSRect mainDisplayRect = [[NSScreen mainScreen] frame];
NSWindow *fullScreenWindow = [[NSWindow alloc] initWithContentRect: mainDisplayRect styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered defer:YES];
Set the window level to be above the menu bar.:
[fullScreenWindow setLevel:NSMainMenuWindowLevel+1];
Perform any other window configuration you desire:
[fullScreenWindow setOpaque:YES];
[fullScreenWindow setHidesOnDeactivate:YES];
Create a view with a double-buffered OpenGL context and attach it to the window:
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
0
};
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
NSRect viewRect = NSMakeRect(0.0, 0.0, mainDisplayRect.size.width, mainDisplayRect.size.height);
MyOpenGLView *fullScreenView = [[MyOpenGLView alloc] initWithFrame:viewRect pixelFormat: pixelFormat];
[fullScreenWindow setContentView: fullScreenView];
Show the window:
[fullScreenWindow makeKeyAndOrderFront:self];
You can use this method to create windows on each screen that you want to draw to. If you use this to create a window on only one screen, the other screen will continue to function normally, instead of being blacked out or covered in a stupid linen texture. Depending on your use, you may not want to setHidesOnDeactivate.
There are also lower-level APIs to take control of a screen completely and prevent the OS or any other application from drawing to the screen, but their use is seldom justified.
EDIT: If you want to have one GL context with the render spanning multiple screens, you need to create a single window with a NSRect that spans all the screens. If the screen resolutions aren't matched, this may result in part of your window not being visible, and low-end graphics chips may have some problems.

Resizing NSWindow to fit child NSView

I have one main NSWindow which is empty, and 5 NSViews. The NSViews have different buttons and labels etc, and the window is empty. The first view displayed is a menu, linking to the other views and back. This works fine and the views switch well.
However if the NSWindow is a certain size, and the NSView is bigger, then it spills out of the NSWindow and gets cut off.
Is there any way such that when I do:
[_window setContentView: theNewView];
to also have _window resize to fit the new view? If this is possible, can this be done with an animation?
-[NSWindow setContentSize:] does this (without animation). Give it the desired size of the content view and it will resize both content view and the window appropriately, e.g.
[_window setContentSize:theNewView.frame.size];
[_window setContentView:theNewView];
For animation, you need to compute window size manually using frameRectForContentRect: and then change window's frame with animate:YES:
[_window setContentView:theNewView];
NSRect viewScreenFrame = /*translate theNewView.frame to screen coordinates*/;
NSRect wndFrame = [_window frameRectForContentRect:viewScreenFrame];
[_window setFrame:wndFrame display:YES animate:YES];

Is there Any way to imitate Lion's Launchpad?

I have been struggling to imitate Launchpad.
At the beginning I thought about making NSWindow bgcolor transparent:
//make NSWindow's bgcolor transparent
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];
But now I realized it's way more ideal to
capture wallpaper
blur it and make it bg-image for NSWindow or a view
Rather than hiding all the opened windows and menubar, which was the first idea I had have come with (Still not sure with better, if you had any better idea...).
Capture & blur wallpaper used by a user
Make it background image for nswindow or a view
Fade-in to fullscreen view
Click somewhere blank or press ESC to fade-out
Are those possible to achieve without using private APIs?
Sorry if it's not clear my poor English.
Simply I'm trying to imitate Launchpad-styled full screen.
Thanks for any advice.
To get an image of the desktop background, use:
NSURL *imageURL = [[NSWorkspace sharedWorkspace] desktopImageuRLForScreen:[NSScreen mainScreen]
NSImage *theDekstopImage = [[NSImage alloc] initWithContentsOfURL:imageURL];
You can blur the image using CIFilter. Here's a Apple doc describing how to apply filters.
And then you can load that image into a color and set that as the background color for the window. Additionally, set the window to have no style mask (no close buttons, title frame, etc.), cover the screen, and be in front of everything except the dock:
[yourWindow setBackgroundColor:[NSColor colorWithPatternImage:theDesktopImage]];
[yourWindow setStyleMask:NSBorderlessWindowMask];
[yourWindow setLevel:kCGDockWindowLevel - 1];
[yourWindow setFrame:[[NSScreen mainScreen] frame] display:YES];
To have the window fade in, you can use NSWindow's animator proxy. (Replace 1.0 with 0.0 to make it fade out.)
[[yourWindow animator] setAlphaValue:1.0];
Of course you could customize that a bit more with things like CoreAnimation, but this should work just fine.
To handle background clicking, I suggest making a subclass of NSView where you -orderOut: your window on -mouseDown:. Then put an instance of that subclass that spans the entire frame of your window.
Also, NSViews sometimes don't respond to key events, so you can add an event listener to detect any time the escape key is pressed while your app is active:
[NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:(NSEvent *ev)^ {
if([ev keyCode] == 0x53) {
[yourWindow orderOut:self];
}
return ev;
}