2 * Screen routines for full screen Quartz mode
4 * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * TORREY T. LYONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
21 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * Except as contained in this notice, the name(s) of the above copyright
25 * holders shall not be used in advertising or otherwise to promote the sale,
26 * use or other dealings in this Software without prior written authorization.
28 #ifdef HAVE_XORG_CONFIG_H
29 #include <xorg-config.h>
31 #include "quartz/quartzCommon.h"
33 #include "quartz/quartz.h"
34 #include "quartz/quartzCursor.h"
35 #include "colormapst.h"
36 #include "scrnintstr.h"
40 // Full screen specific per screen storage structure
42 CGDirectDisplayID displayID
;
43 CFDictionaryRef xDisplayMode
;
44 CFDictionaryRef aquaDisplayMode
;
45 CGDirectPaletteRef xPalette
;
46 CGDirectPaletteRef aquaPalette
;
47 unsigned char *framebuffer
;
48 unsigned char *shadowPtr
;
49 } FSScreenRec
, *FSScreenPtr
;
51 #define FULLSCREEN_PRIV(pScreen) \
52 ((FSScreenPtr)pScreen->devPrivates[fsScreenIndex].ptr)
54 static int fsScreenIndex
;
55 static CGDirectDisplayID
*quartzDisplayList
= NULL
;
56 static int quartzNumScreens
= 0;
57 static FSScreenPtr quartzScreens
[MAXSCREENS
];
59 static int darwinCmapPrivateIndex
= -1;
60 static unsigned long darwinCmapGeneration
= 0;
62 #define CMAP_PRIV(pCmap) \
63 ((CGDirectPaletteRef) (pCmap)->devPrivates[darwinCmapPrivateIndex].ptr)
66 =============================================================================
70 =============================================================================
75 * Colormap privates may be allocated after the default colormap has
76 * already been created for some screens. This initialization procedure
77 * is called for each default colormap that is found.
89 * This is a callback from X after a new colormap is created.
90 * We allocate a new CoreGraphics pallete for each colormap.
96 CGDirectPaletteRef pallete
;
98 // Allocate private storage for the hardware dependent colormap info.
99 if (darwinCmapGeneration
!= serverGeneration
) {
100 if ((darwinCmapPrivateIndex
=
101 AllocateColormapPrivateIndex(FSInitCmapPrivates
)) < 0)
105 darwinCmapGeneration
= serverGeneration
;
108 pallete
= CGPaletteCreateDefaultColorPalette();
109 if (!pallete
) return FALSE
;
111 CMAP_PRIV(pCmap
) = pallete
;
118 * This is called by DIX FreeColormap after it has uninstalled a colormap
119 * and notified all interested parties. We deallocated the corresponding
120 * CoreGraphics pallete.
126 CGPaletteRelease( CMAP_PRIV(pCmap
) );
132 * Set the current CoreGraphics pallete to the pallete corresponding
133 * to the provided colormap.
139 CGDirectPaletteRef palette
= CMAP_PRIV(pCmap
);
140 ScreenPtr pScreen
= pCmap
->pScreen
;
141 FSScreenPtr fsDisplayInfo
= FULLSCREEN_PRIV(pScreen
);
143 // Inform all interested parties that the map is being changed.
144 miInstallColormap(pCmap
);
146 if (quartzServerVisible
)
147 CGDisplaySetPalette(fsDisplayInfo
->displayID
, palette
);
149 fsDisplayInfo
->xPalette
= palette
;
155 * This is a callback from X to change the hardware colormap
156 * when using PsuedoColor in full screen mode.
164 CGDirectPaletteRef palette
= CMAP_PRIV(pCmap
);
165 ScreenPtr pScreen
= pCmap
->pScreen
;
166 FSScreenPtr fsDisplayInfo
= FULLSCREEN_PRIV(pScreen
);
173 for (i
= 0; i
< numEntries
; i
++) {
174 color
.red
= pdefs
[i
].red
/ 65535.0;
175 color
.green
= pdefs
[i
].green
/ 65535.0;
176 color
.blue
= pdefs
[i
].blue
/ 65535.0;
177 CGPaletteSetColorAtIndex(palette
, color
, pdefs
[i
].pixel
);
180 // Update hardware colormap
181 if (quartzServerVisible
)
182 CGDisplaySetPalette(fsDisplayInfo
->displayID
, palette
);
187 =============================================================================
189 Switching between Aqua and X
191 =============================================================================
196 * Capture the screen so we can draw. Called directly from the main thread
197 * to synchronize with hiding the menubar.
199 static void FSCapture(void)
203 if (quartzRootless
) return;
205 for (i
= 0; i
< quartzNumScreens
; i
++) {
206 FSScreenPtr fsDisplayInfo
= quartzScreens
[i
];
207 CGDirectDisplayID cgID
= fsDisplayInfo
->displayID
;
209 if (!CGDisplayIsCaptured(cgID
)) {
210 CGDisplayCapture(cgID
);
211 fsDisplayInfo
->aquaDisplayMode
= CGDisplayCurrentMode(cgID
);
212 if (fsDisplayInfo
->xDisplayMode
!= fsDisplayInfo
->aquaDisplayMode
)
213 CGDisplaySwitchToMode(cgID
, fsDisplayInfo
->xDisplayMode
);
214 if (fsDisplayInfo
->xPalette
)
215 CGDisplaySetPalette(cgID
, fsDisplayInfo
->xPalette
);
223 * Release the screen so others can draw.
225 static void FSRelease(void)
229 if (quartzRootless
) return;
231 for (i
= 0; i
< quartzNumScreens
; i
++) {
232 FSScreenPtr fsDisplayInfo
= quartzScreens
[i
];
233 CGDirectDisplayID cgID
= fsDisplayInfo
->displayID
;
235 if (CGDisplayIsCaptured(cgID
)) {
236 if (fsDisplayInfo
->xDisplayMode
!= fsDisplayInfo
->aquaDisplayMode
)
237 CGDisplaySwitchToMode(cgID
, fsDisplayInfo
->aquaDisplayMode
);
238 if (fsDisplayInfo
->aquaPalette
)
239 CGDisplaySetPalette(cgID
, fsDisplayInfo
->aquaPalette
);
240 CGDisplayRelease(cgID
);
248 * Suspend X11 cursor and drawing to the screen.
250 static void FSSuspendScreen(
253 QuartzSuspendXCursor(pScreen
);
254 xf86SetRootClip(pScreen
, FALSE
);
260 * Resume X11 cursor and drawing to the screen.
262 static void FSResumeScreen(
264 int x
, // cursor location
267 QuartzResumeXCursor(pScreen
, x
, y
);
268 xf86SetRootClip(pScreen
, TRUE
);
273 =============================================================================
275 Screen initialization
277 =============================================================================
282 * Full screen specific initialization called from InitOutput.
284 static void FSDisplayInit(void)
286 static unsigned long generation
= 0;
287 CGDisplayCount quartzDisplayCount
= 0;
289 ErrorF("Display mode: Full screen Quartz -- Direct Display\n");
291 // Allocate private storage for each screen's mode specific info
292 if (generation
!= serverGeneration
) {
293 fsScreenIndex
= AllocateScreenPrivateIndex();
294 generation
= serverGeneration
;
297 // Find all the CoreGraphics displays
298 CGGetActiveDisplayList(0, NULL
, &quartzDisplayCount
);
299 quartzDisplayList
= xalloc(quartzDisplayCount
* sizeof(CGDirectDisplayID
));
300 CGGetActiveDisplayList(quartzDisplayCount
, quartzDisplayList
,
301 &quartzDisplayCount
);
303 darwinScreensFound
= quartzDisplayCount
;
310 * Find the appropriate display mode to use in full screen mode.
311 * If display mode is not the same as the current Aqua mode, switch
314 static Bool
FSFindDisplayMode(
315 FSScreenPtr fsDisplayInfo
)
317 CGDirectDisplayID cgID
= fsDisplayInfo
->displayID
;
318 size_t height
, width
, bpp
;
319 boolean_t exactMatch
;
321 fsDisplayInfo
->aquaDisplayMode
= CGDisplayCurrentMode(cgID
);
323 // If no user options, use current display mode
324 if (darwinDesiredWidth
== 0 && darwinDesiredDepth
== -1 &&
325 darwinDesiredRefresh
== -1)
327 fsDisplayInfo
->xDisplayMode
= fsDisplayInfo
->aquaDisplayMode
;
331 // If the user has no choice for size, use current
332 if (darwinDesiredWidth
== 0) {
333 width
= CGDisplayPixelsWide(cgID
);
334 height
= CGDisplayPixelsHigh(cgID
);
336 width
= darwinDesiredWidth
;
337 height
= darwinDesiredHeight
;
340 switch (darwinDesiredDepth
) {
351 bpp
= CGDisplayBitsPerPixel(cgID
);
354 if (darwinDesiredRefresh
== -1) {
355 fsDisplayInfo
->xDisplayMode
=
356 CGDisplayBestModeForParameters(cgID
, bpp
, width
, height
,
359 fsDisplayInfo
->xDisplayMode
=
360 CGDisplayBestModeForParametersAndRefreshRate(cgID
, bpp
,
361 width
, height
, darwinDesiredRefresh
, &exactMatch
);
364 fsDisplayInfo
->xDisplayMode
= fsDisplayInfo
->aquaDisplayMode
;
368 // Switch to the new display mode
369 CGDisplaySwitchToMode(cgID
, fsDisplayInfo
->xDisplayMode
);
376 * Do initialization of each screen for Quartz in full screen mode.
378 static Bool
FSAddScreen(
382 DarwinFramebufferPtr dfb
= SCREEN_PRIV(pScreen
);
383 QuartzScreenPtr displayInfo
= QUARTZ_PRIV(pScreen
);
384 CGDirectDisplayID cgID
= quartzDisplayList
[index
];
386 FSScreenPtr fsDisplayInfo
;
388 // Allocate space for private per screen fullscreen specific storage.
389 fsDisplayInfo
= xalloc(sizeof(FSScreenRec
));
390 FULLSCREEN_PRIV(pScreen
) = fsDisplayInfo
;
392 displayInfo
->displayCount
= 1;
393 displayInfo
->displayIDs
= xrealloc(displayInfo
->displayIDs
,
394 1 * sizeof(CGDirectDisplayID
));
395 displayInfo
->displayIDs
[0] = cgID
;
397 fsDisplayInfo
->displayID
= cgID
;
398 fsDisplayInfo
->xDisplayMode
= 0;
399 fsDisplayInfo
->aquaDisplayMode
= 0;
400 fsDisplayInfo
->xPalette
= 0;
401 fsDisplayInfo
->aquaPalette
= 0;
403 // Capture full screen because X doesn't like read-only framebuffer.
404 // We need to do this before we (potentially) switch the display mode.
405 CGDisplayCapture(cgID
);
407 if (! FSFindDisplayMode(fsDisplayInfo
)) {
408 ErrorF("Could not support specified display mode on screen %i.\n",
410 xfree(fsDisplayInfo
);
414 // Don't need to flip y-coordinate as CoreGraphics treats (0, 0)
415 // as the top left of main screen.
416 bounds
= CGDisplayBounds(cgID
);
417 dfb
->x
= bounds
.origin
.x
;
418 dfb
->y
= bounds
.origin
.y
;
419 dfb
->width
= bounds
.size
.width
;
420 dfb
->height
= bounds
.size
.height
;
421 dfb
->pitch
= CGDisplayBytesPerRow(cgID
);
422 dfb
->bitsPerPixel
= CGDisplayBitsPerPixel(cgID
);
424 if (dfb
->bitsPerPixel
== 8) {
425 if (CGDisplayCanSetPalette(cgID
)) {
426 dfb
->colorType
= PseudoColor
;
428 dfb
->colorType
= StaticColor
;
430 dfb
->bitsPerComponent
= 8;
431 dfb
->colorBitsPerPixel
= 8;
433 dfb
->colorType
= TrueColor
;
434 dfb
->bitsPerComponent
= CGDisplayBitsPerSample(cgID
);
435 dfb
->colorBitsPerPixel
= CGDisplaySamplesPerPixel(cgID
) *
436 dfb
->bitsPerComponent
;
439 fsDisplayInfo
->framebuffer
= CGDisplayBaseAddress(cgID
);
441 // allocate shadow framebuffer
442 fsDisplayInfo
->shadowPtr
= xalloc(dfb
->pitch
* dfb
->height
);
443 dfb
->framebuffer
= fsDisplayInfo
->shadowPtr
;
451 * Update the damaged regions of the shadow framebuffer on the display.
453 static void FSShadowUpdate(
457 DarwinFramebufferPtr dfb
= SCREEN_PRIV(pScreen
);
458 FSScreenPtr fsDisplayInfo
= FULLSCREEN_PRIV(pScreen
);
459 RegionPtr damage
= &pBuf
->damage
;
460 int numBox
= REGION_NUM_RECTS(damage
);
461 BoxPtr pBox
= REGION_RECTS(damage
);
462 int pitch
= dfb
->pitch
;
463 int bpp
= dfb
->bitsPerPixel
/8;
465 // Don't update if the X server is not visible
466 if (!quartzServerVisible
)
469 // Loop through all the damaged boxes
471 int width
, height
, offset
;
472 unsigned char *src
, *dst
;
474 width
= (pBox
->x2
- pBox
->x1
) * bpp
;
475 height
= pBox
->y2
- pBox
->y1
;
476 offset
= (pBox
->y1
* pitch
) + (pBox
->x1
* bpp
);
477 src
= fsDisplayInfo
->shadowPtr
+ offset
;
478 dst
= fsDisplayInfo
->framebuffer
+ offset
;
481 memcpy(dst
, src
, width
);
494 * Finalize full screen specific setup of each screen.
496 static Bool
FSSetupScreen(
500 DarwinFramebufferPtr dfb
= SCREEN_PRIV(pScreen
);
501 FSScreenPtr fsDisplayInfo
= FULLSCREEN_PRIV(pScreen
);
502 CGDirectDisplayID cgID
= fsDisplayInfo
->displayID
;
504 // Initialize shadow framebuffer support
505 if (! shadowInit(pScreen
, FSShadowUpdate
, NULL
)) {
506 ErrorF("Failed to initalize shadow framebuffer for screen %i.\n",
511 if (dfb
->colorType
== PseudoColor
) {
512 // Initialize colormap handling
515 // If Aqua is using 8 bits we need to keep track of its pallete.
516 CFNumberGetValue(CFDictionaryGetValue(fsDisplayInfo
->aquaDisplayMode
,
517 kCGDisplayBitsPerPixel
), kCFNumberLongType
, &aquaBpp
);
519 fsDisplayInfo
->aquaPalette
= CGPaletteCreateWithDisplay(cgID
);
521 pScreen
->CreateColormap
= FSCreateColormap
;
522 pScreen
->DestroyColormap
= FSDestroyColormap
;
523 pScreen
->InstallColormap
= FSInstallColormap
;
524 pScreen
->StoreColors
= FSStoreColors
;
528 quartzScreens
[quartzNumScreens
++] = fsDisplayInfo
;
534 * Quartz display mode function list.
536 static QuartzModeProcsRec fsModeProcs
= {
542 QuartzReallySetCursor
,
547 NULL
, // No dynamic screen change support
550 NULL
, // No rootless code in fullscreen
554 NULL
, // No support for DRI surfaces
560 * QuartzModeBundleInit
561 * Initialize the display mode bundle after loading.
564 QuartzModeBundleInit(void)
566 quartzProcs
= &fsModeProcs
;
567 quartzOpenGLBundle
= NULL
; // Only Mesa support for now