OSX Fullscreen (Kiosk) Application with Custom Resolution - objective-c

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.

Related

Window resizing problems in Xcode example

I've downloaded Apple's example GLEssentials. Then added a programmatically window resizing in a method awakeFromNib in GLEssentialsWindowController class implementation:
-(void) awakeFromNib
{
NSRect rect = [view convertRectToBacking:NSMakeRect(0,0,500,500)];
[self.window setFrame:rect display:YES animate:NO];
}
Here comes the most of fun. When I doing such simple operation on my working iMac there is no problems at all. Window size becomes what I expected.
But when I doing this operation on my MacBook window resizes to value stored in .xib file. Then I manually resize window to some new size and quit from application. Then launch it again. Window resizes to the size that this window had at the last launch right before it was closed.
Any suggestions?
As I understood, NSOpenGLView class calls resize method even after window is initialized, that's why the only solution to do not allow window to resize right after awakeFromNib event is remove resizable mask from window styles:
[window setStyleMask:[window styleMask] & ~NSResizableWindowMask];
So the final solution will look like:
- (void) awakeFromNib
{
[self.window setStyleMask:[self.window styleMask] & ~NSResizableWindowMask];
NSRect rect = [view convertRectToBacking:NSMakeRect(0,0,500,500)];
[self.window setFrame:rect display:YES animate:NO];
}
So the target window will be resized to 500 x 500, and doesn't matter what the size was stored in .xib file.

How to resize Window to dimension in VIew Controller for a OSX app?

I'm fairly new to Mac OSX Apps, but I'm trying to build an app with no status bar, and the dimensions are smaller. So what I did in my AppDelegate.m is:
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[self.window.contentView addSubview:self.mainViewController.view];
[self.window setOpaque:NO];
[self.window setStyleMask:NSBorderlessWindowMask];
[self.window setBackgroundColor:[NSColor clearColor]];
self.mainViewController.view.frame = ((NSView*)self.window.contentView).bounds;
}
Now, what I really want to do, is to get my window to look like, what I've built in my interface builder (can't post pictures yet). I've tried shutting off all the autosizing elements but when I run the simulator I get a clipped version of my interface (the size changes every run). It seem like the frame size is getting miscalculated, but I've done everything from the interface builder. I can programmatically set the shapes of the view, but is there a way to shut off all resizing and simply portray the xib file as what I see in the interface builder?
There are two ways you could approach this problem.
You add an AutoresizingMask to your ViewController:
[self.mainViewController setAutoresizingMask:NSViewAutoresizingFlexibleWidth|NSViewAutoresizingFlexibleHeigt];
You disable window resizing in the Interface builder like by setting its minimum and maximum size. This can also be done in code.
Edit: Thanks to trojanfoe for pointing out that you can also uncheck Resize in the Attributes Inspector.
You can easily resize your window programatically. Here's how:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSRect frame;
frame.size.height = 200;
frame.size.width = 200;
[window setFrame:frame display:YES animate:YES];
}

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.

Create fullscreen UIView on rotatable UIViewController

I have a UIViewController which supports all interface Orientations. The views are created programatically in the loadView() which works so far. All the views added in the loadView() method have the correct size and rotation.
However any views added later on are not rotated correctly. If I add the following UIView
[[[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] applicationFrame].size.width, [[UIScreen mainScreen] applicationFrame].size.height)] autorelease];
it is only fullscreen if the UIViewController was in portrait mode when the UIView was added. If the device was in landscape mode the UIView is only 748 pixels wide, not the 1024 I would expect. [[UIScreen mainScreen] applicationFrame].size.width delivers 768 pixels or 748 pixels depending on the device's rotation.
So how should I create and add the UIView so it is shown with the full screen size? I would also like to init the UIView's content only for one mode (portrait OR landscape) and have it autoresized for the other mode. I basically need to tell the UIView it is a portrait mode view and should be rotated when added to a landscape view controller.
Since I couldn't init the UIView with the correct size, I just left the initialization code like it was (always creating the view in portrait mode) and resized the UIView later to the parent view's bounds property. Unlike the frame property, bounds seems to return the correct size depending on the current rotation.

Drawing a Window at Coordinates or Drawing outside of NSStatus Item

I am trying to display something off the side of a NSStatusItem. I think I could do this in two ways:
Display a transparent window with the image I need at the coordinates of the mouse cursor.
OR
Use a custom NSStatusItem and move the controls/images in the view to the left so they are actually off the status item
The problem is, setting the NSRect frame negative (-200,0,100,50) doesn't seem to actually work. So, how can I render things outside of the bounds of the status item (think the CSS overflow property) or render a transparent window at specific coordinates?
The system will prevent you from drawing outside the status item, but using a transparent window will work.
NSRect rect; //The location of the window
NSWindow *win = [[NSWindow alloc] initWithContentRect:rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
[win setOpaque:NO];
[win setBackgroundColor:[NSColor clearColor]];
//or
[win setContentView:myView];
Here, myView is a custom view which will be the background of the window. In order for the window to be transparent, you either have to set the background color to clear or use a custom content view which only draws where it is not transparent. You will probably want to use a floating window so that it stays on top. Be careful not to cover up something important because your window could intercept events intended for something underneath it.