The Quartz Display Services API provides functionality that is useful for any Mac OS X application using full-screen mode. In other parts of this programming guide, you've seen how to use Quartz Display Services to obtain exclusive access to the display, query the display, and adjust the resolution, depth, and refresh rate of the display. This appendix shows how to perform some additional tasks that are relevant to full-screen OpenGL applications:
“Displays and Display Modes” shows how to obtain information about the display and switch modes.
“Fading the Display” describes how to fade a display to black and then set it to its original state.
“Controlling the Pointer” discusses how to programmatically manage the cursor and disassociate mouse movement from the cursor.
For more information, see Quartz Display Services Reference.
Quartz Display Services functions allow you to enumerate all displays as well as the supported modes for each display. The Quartz Display Services functions CGDisplaySwitchToMode
and CGDisplayBestModeForParameters
use on the Core Foundation CFDictionary
data type. Each display mode has a dictionary whose key-value pairs you can query. You can use accessor functions to query the properties of the current display mode. You can also use Core Foundation functions to access the dictionary associated with a display mode. See CFDictionary Reference.
You can enumerate the display modes for a display by using its display ID. You can obtain an array of display IDs that correspond to all displays in the system by calling the function CGGetActiveDisplayList
. The first display in the list is always the main display. The main display is also represented by the constant kCGDirectMainDisplay
.
These functions also obtain an array of display IDs:
CGGetDisplaysWithPoint
obtains the display IDs for online displays whose bounds include a specified point.
CGGetDisplaysWithRect
obtains the display IDs for online displays whose bounds include a specified rectangle.
CGGetDisplaysWithOpenGLDisplayMask
obtains the display IDs for online displays that correspond to the bits set in an OpenGL display mask.
Typically you use the functions CGGetDisplaysWithPoint
and CGGetDisplaysWithRect
when tracking user interactions. You choose which display to capture based on where the user places the pointer. After capturing the display, you can the obtain the supported modes by calling the function CGDisplayAvailableModes
.
Listing C-1 shows how to switch the last display in a display list into its first mode and then print the height and width of the display. A detailed explanation for each numbered line of code appears following the listing.
Listing C-1 Switching modes for a display in a list
#define MAX_DISPLAYS 32 |
CGDirectDisplayID lastDisplay, displayArray[MAX_DISPLAYS] ; |
CGDisplayCount numDisplays; |
CFArrayRef displayModeArray; |
CFDictionaryRef displayMode; |
CFNumberRef number; |
long height, width; |
CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays); // 1 |
lastDisplay = displayArray [numDisplays - 1]; // 2 |
CGDisplayCapture (lastDisplay); // 3 |
displayModeArray = CGDisplayAvailableModes (lastDisplay); // 4 |
displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, 0); // 5 |
CGDisplaySwitchToMode (lastDisplay, displayMode); // 6 |
/* Run the event loop. */ |
CGReleaseAllDisplays(); // 7 |
Here's what the code does:
Gets the array of active displays, which are the ones available for drawing.
Gets the display ID of the last display in the array. The array is zero-based.
Captures the display associated with the last display in the array.
Gets all the display modes for the display.
Gets the first display mode for the display. Recall that the display mode is stored as a CFDictionary
object that contains key-value pairs for the attributes of the display mode.
Switches the display mode.
Before the application quits, releases all displays.
Quartz Display Services provides simple accessor functions for many properties of the current display mode. For these properties, you don't need to call CFDictionaryGetValue
. Listing C-2 shows how to obtain the properties of the current mode of every display (up to 32) in the system.
Listing C-2 Getting display properties
#define MAX_DISPLAYS 32 |
CGDirectDisplayID displayArray [MAX_DISPLAYS]; |
CGDisplayCount numDisplays; |
CFNumberRef number; |
CFBoolean booleanValue; |
long height, width, refresh, mode, |
bpp, bps, spp, rowBytes, gui, ioflags; |
int i; |
CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays); // 1 |
printf ("Displays installed: %d\n", numDisplays); // 2 |
for(i = 0; i < numDisplays; i++) { // 3 |
width = CGDisplayPixelsWide (displayArray[i]); |
height = CGDisplayPixelsHigh (displayArray[i]); |
bpp = CGDisplayBitsPerPixel (displayArray[i]); |
bps = CGDisplayBitsPerSample (displayArray[i]); |
spp = CGDisplaySamplesPerPixel (displayArray[i]); |
rowBytes = CGDisplayBytesPerRow (displayArray[i]); |
number = CFDictionaryGetValue (CGDisplayCurrentMode (displayArray[i]), |
kCGDisplayMode); |
CFNumberGetValue (number, kCFNumberLongType, &mode); |
number = CFDictionaryGetValue (CGDisplayCurrentMode (displayArray[i]), |
kCGDisplayRefreshRate); |
CFNumberGetValue (number, kCFNumberLongType, &refresh); |
booleanValue = CFDictionaryGetValue (CGDisplayCurrentMode(displayArray[i]), |
kCGDisplayModeUsableForDesktopGUI); |
CFNumberGetValue (number, kCFNumberLongType, &gui); |
number = CFDictionaryGetValue (CGDisplayCurrentMode (displayArray[i]), |
kCGDisplayIOFlags); |
CFNumberGetValue (number, kCFNumberLongType, &ioflags); |
} |
Here's what the code does:
Gets the array of displays.
Prints out the number of displays.
Gets the properties for the current mode of each display. Note that Quartz Display Services provides several functions that obtain properties. For information about the current display mode, you must use the function CFDictionaryGetValue
, along with the appropriate key, to retrieve a value from the display mode dictionary returned by the function CGDisplayCurrentMode
.
Fading a display ensures a smooth transition when entering full-screen mode, especially when switching display modes. There are two options for fading displays:
Call the function CGDisplayFade
to fade all displays connected to the system. See Listing C-3.
Adjust the display gamma value to fade a single display on a system that has more than one display connected. See Listing C-4.
Listing C-3 Fading all displays connected to the system
CGDisplayFadeReservationToken token; |
CGDisplayErr err; |
err = CGAcquireDisplayFadeReservation (kCGMaxDisplayReservationInterval, &token); // 1 |
if (err == kCGErrorSuccess) |
{ |
err = CGDisplayFade (token, 0.5, kCGDisplayBlendNormal, |
kCGDisplayBlendSolidColor, 0, 0, 0, true); // 2 |
// Your code to change the display mode and |
// set the full-screen context. |
err = CGDisplayFade (token, 0.5, kCGDisplayBlendSolidColor, |
kCGDisplayBlendNormal, 0, 0, 0, true); // 3 |
err = CGReleaseDisplayFadeReservation (token); // 4 |
} |
Here's what the code does:
Reserves the display hardware for the maximum amount of time allowable. Your application must perform this step before it can fade the displays. During this time, your application has exclusive rights to use the fade hardware.
Fades displays to black over a duration of 0.5 seconds
Performs a fade-in for all displays, from black to normal, over a duration of 0.5 seconds
Releases the fade reservation and invalidates the fade token.
When you adjust the gamma value to fade a display, you can't assume that the maximum gamma value is 1.0 because the user might have specified a different maximum value in System Preferences. You need to retrieve the current settings and scale them so that they range from 0
to 1
. Listing C-3 shows how to fade the main display to black and back. Note that the code uses a loop is used to obtain a smooth fade. A more robust technique is to use a timer to ensure a fixed fade duration on different systems. A detailed explanation for each numbered line of code appears following the listing.
Listing C-4 Fading a single display on a system with multiple displays
#define kMyFadeTime 1.0 |
#define kMyFadeSteps 100 |
#define kMyFadeInterval ( kMyFadeTime/(double) kMyFadeSteps) |
int step; |
double fadeValue ; |
CGGammaValue redMin, redMax, redGamma, |
greenMin, greenMax, greenGamma, |
blueMin, blueMax, blueGamma; |
CGGetDisplayTransferByFormula (kCGDirectMainDisplay, |
&redMin, &redMax, &redGamma, |
&greenMin, &greenMax, &greenGamma, |
&blueMin, &blueMax, &blueGamma ); // 1 |
for ( step = 0; step < kMyFadeSteps; ++step ) { |
fadeValue = 1.0 - (step * kMyFadeInterval); |
CGSetDisplayTransferByFormula (kCGDirectMainDisplay, |
redMin, fadeValue*redMax, redGamma, |
greenMin, fadeValue*greenMax, greenGamma, |
blueMin, fadeValue*blueMax, blueGamma ); // 2 |
usleep( (useconds_t)(1000000.0 * kMyFadeInterval) ); // 3 |
} |
// Your code to change the display mode and |
// attach the context to a full-screen drawable object. |
// Run the event loop. |
for ( step = 0; step < kMyFadeSteps; ++step ) { |
fadeValue = (step * kMyFadeInterval); |
CGSetDisplayTransferByFormula( kCGDirectMainDisplay, |
redMin, fadeValue*redMax, redGamma, |
greenMin, fadeValue*greenMax, greenGamma, |
blueMin, fadeValue*blueMax, blueGamma ); // 4 |
usleep( (useconds_t)(1000000.0 * kMyFadeInterval) ); // 5 |
} |
CGDisplayRestoreColorSyncSettings() // 6 |
Here's what the code does:
Gets the current coefficients of the gamma transfer formula for a display as the starting gamma values.
Fades from the current gamma by setting the color gamma function for the display, specified as the coefficients of the gamma transfer formula. Starts with the current gamma (multiplying by a factor of 1.0
) and ends with black (multiplying by a factor of 0.0
).
Suspends processing for a short interval. You either need to use a timer or insert a short delay to achieve a fade effect because the call to change the display gamma returns within 100 microseconds or so, and the actual gamma is applied asynchronously during the next vertical blanking period. Without the delay, you'll get what appears as an instantaneous switch to black rather than a fade effect.
Fade from black (multiplying by a factor of 0.0
) back to original gamma (multiplying by a factor of 1.0
).
Suspends processing for a short interval to achieve a smooth fade-in effect.
Finds and applies all ColorSync settings for all attached displays, restoring the gamma tables to the values in the user's ColorSync display profile. It's a good idea to call this function because the operation performed by the function CGSetDisplayTransferByFormula
can't reproduce precisely the color correction data for all displays, particularly LCD panels.
When you use full-screen mode, you may want to hide the pointer, programatically move the pointer, or disassociate mouse movement from pointer position. To hide or show the pointer, use the functions CGDisplayHideCursor
and CGDisplayShowCursor
. These functions control the pointer visibility on all displays.
Quartz Display Services provides a convenient function for disassociating mouse movement from pointer position while an application is in the foreground. By passing false
to the function CGAssociateMouseAndMouseCursorPosition
, you can prevent mouse movement from changing the pointer position. Pass true
to reverse the effect. You should also hide the menu bar because clicking it can cause the pointer to become visible again, even after capturing the display.
You can move the pointer programatically by calling the function CGDisplayMoveCursorToPoint
. This function takes two parameters, a display ID and a point. The location of the point is relative to the display origin (the upper-left corner of the display).
Listing C-5 shows how you would hide and move the cursor on the main display, disassociate the cursor from mouse movement, and restore the cursor and mouse when you are done.
Listing C-5 Controlling the pointer programmatically
CGDisplayHideCursor (kCGDirectMainDisplay); //Hide cursor |
CGDisplayMoveCursorToPoint (kCGDirectMainDisplay,CGPointZero); //Place at display origin |
CGAssociateMouseAndMouseCursorPosition (FALSE); |
// Perform your application's main loop. |
//In the mouse movement notification function, get the motion deltas |
CGAssociateMouseAndMouseCursorPosition (TRUE); |
CGDisplayShowCursor (kCGDirectMainDisplay); |
Quartz Display Services Reference which describes the application programming interface that configures and controls the display hardware.
© 2004, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-06-09)