If you want to take over the entire screen for your drawing, you can do so from a Cocoa application. Entering full-screen drawing mode is a two-step process:
Capture the desired screen (or screens) for drawing.
Configure your drawing environment.
After capturing the screen, the way you configure your drawing environment depends on whether you are using Cocoa or OpenGL to draw. In OpenGL, you create an NSOpenGLContext object and invoke several of its methods to enter full-screen mode. In Cocoa, you have to create a window that fills the screen and configure that window.
Capturing the Screen
Full-Screen Drawing in OpenGL
Full-Screen Drawing in Cocoa
Disabling Screen Updates
Cocoa does not provide direct support for capturing and releasing screens. The NSScreen class provides read-only access to information about the available screens. To capture or manipulate a screen, you must use the functions found in Quartz Services.
To capture all of the available screens, you can simply call the CGCaptureAllDisplays function. To capture an individual display, you must get the ID of the desired display and call the CGDisplayCapture function to capture it. The following example shows how to use information provided by an NSScreen object to capture the main screen of a system.
- (BOOL) captureMainScreen |
{ |
// Get the ID of the main screen. |
NSScreen* mainScreen = [NSScreen mainScreen]; |
NSDictionary* screenInfo = [mainScreen deviceDescription]; |
NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; |
// Capture the display. |
CGDisplayErr err = CGDisplayCapture([screenID longValue]); |
if (err != CGDisplayNoErr) |
return NO; |
return YES; |
} |
To release a display you previously captured, use the CGDisplayRelease function. If you captured all of the active displays, you can release them all by calling the CGReleaseAllDisplays function.
For more information about capturing and manipulating screens, see Quartz Display Services Reference.
Applications that do full-screen drawing tend to be graphics intensive and thus use OpenGL to improve rendering speed. Creating a full-screen context using OpenGL is easy to do from Cocoa. After capturing the desired displays, create and configure an NSOpenGLContext object and then invoke its setFullScreen and makeCurrentContext methods. After invoking these methods, your application goes immediately to full-screen mode and you can start drawing content.
When requesting a full-screen context in OpenGL, the pixel format for your context should include the following attributes:
NSOpenGLPFAFullScreen
NSOpenGLPFAScreenMask
NSOpenGLPFAAccelerated
NSOpenGLPFANoRecovery (only if your OpenGL graphics context is shared)
Listing 8-4 shows the basic steps for capturing all displays and setting up the OpenGL context for full-screen drawing. For information on how to create an NSOpenGLContext object, see “Creating an OpenGL Graphics Context.”
Listing 8-4 Creating an OpenGL full-screen context
NSOpenGLContext* CreateScreenContext() |
{ |
CGDisplayErr err; |
err = CGCaptureAllDisplays(); |
if (err != CGDisplayNoErr) |
return nil; |
// Create the context object. |
NSOpenGLContext* glContext = CreateMyGLContext(); |
// If the context is bad, release the displays. |
if (!glContext) |
{ |
CGReleaseAllDisplays(); |
return nil; |
} |
// Go to full screen mode. |
[glContext setFullScreen]; |
// Make this context current so that it receives OpenGL calls. |
[glContext makeCurrentContext]; |
return glContext; |
} |
Once you go into full-screen mode with your graphics context, your application has full control of the screen. To exit full-screen mode, invoke the clearDrawable method of your OpenGL context and call the CGReleaseAllDisplays function to release the screens back to the system.
For detailed sample code showing you how to enter full-screen mode using OpenGL and Cocoa, see the NSOpenGL Fullscreen sample in Sample Code > Graphics & Imaging > OpenGL.
All Cocoa drawing occurs in a window, but for full screen drawing, the window you create is a little different. Instead of a bordered window with a title bar, you need to create a borderless window that spans the entire screen area.
Although you create a full-screen window using Cocoa classes, you still have to use Quartz Services to capture the display and configure the window properly. The capture process is described in “Capturing the Screen.” Once you capture the screen, the window server puts up a shield window that hides most other content. To make your full-screen window visible, you must adjust its level to sit above this shield. You can get the shield level using the CGShieldingWindowLevel function and pass the returned value to the setLevel: method of your window.
Listing 8-5 shows an action method defined in a subclass of NSDocument. The document object uses this method to capture the main display and create the window to fill that screen space. The window itself contains a single view (of type MyFullScreenView) for drawing content. (In your own code, you would replace this view with your own custom drawing view.) A reference to the window is stored in the myScreenWindow class instance variable, which is initialized to nil when the class is first instantiated.
Listing 8-5 Creating a Cocoa full-screen context
- (IBAction)goFullScreen:(id)sender |
{ |
// Get the screen information. |
NSScreen* mainScreen = [NSScreen mainScreen]; |
NSDictionary* screenInfo = [mainScreen deviceDescription]; |
NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; |
// Capture the screen. |
CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; |
CGDisplayErr err = CGDisplayCapture(displayID); |
if (err == CGDisplayNoErr) |
{ |
// Create the full-screen window if it doesn’t already exist. |
if (!myScreenWindow) |
{ |
// Create the full-screen window. |
NSRect winRect = [mainScreen frame]; |
myScreenWindow = [[NSWindow alloc] initWithContentRect:winRect |
styleMask:NSBorderlessWindowMask |
backing:NSBackingStoreBuffered |
defer:NO |
screen:[NSScreen mainScreen]]; |
// Establish the window attributes. |
[myScreenWindow setReleasedWhenClosed:NO]; |
[myScreenWindow setDisplaysWhenScreenProfileChanges:YES]; |
[myScreenWindow setDelegate:self]; |
// Create the custom view for the window. |
MyFullScreenView* theView = [[MyFullScreenView alloc] |
initWithFrame:winRect]; |
[myScreenWindow setContentView:theView]; |
[theView setNeedsDisplay:YES]; |
[theView release]; |
} |
// Make the screen window the current document window. |
// Be sure to retain the previous window if you want to use it again. |
NSWindowController* winController = [[self windowControllers] |
objectAtIndex:0]; |
[winController setWindow:myScreenWindow]; |
// The window has to be above the level of the shield window. |
int32_t shieldLevel = CGShieldingWindowLevel(); |
[myScreenWindow setLevel:shieldLevel]; |
// Show the window. |
[myScreenWindow makeKeyAndOrderFront:self]; |
} |
} |
To exit full screen mode using Cocoa, simply release the captured display, resize your window so that it does not occupy the entire screen, and set its level back to NSNormalWindowLevel. For more information about the shield window, see Quartz Display Services Reference.
You can disable and reenable all screen flushes using the NSDisableScreenUpdates and NSEnableScreenUpdates functions. (In Mac OS X v10.4 and later, you can also use the disableScreenUpdatesUntilFlush method of NSWindow.) You can use this technique to synchronize flushes to both a parent and child window. As soon as you reenable screen updates, all windows are flushed simultaneously (or at least close to it).
To prevent the system from appearing frozen, the system may automatically reenable screen updates if your application leaves them disabled for a prolonged period of time. If you leave screen updates disabled for more than 1 second, the system automatically reenables them.
Last updated: 2007-10-31