xprScreen.c revision 8223e2f2
1/* 2 * Xplugin rootless implementation screen functions 3 * 4 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. 5 * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Except as contained in this notice, the name(s) of the above copyright 26 * holders shall not be used in advertising or otherwise to promote the sale, 27 * use or other dealings in this Software without prior written authorization. 28 */ 29 30#include "sanitizedCarbon.h" 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include "quartzCommon.h" 37#include "inputstr.h" 38#include "quartz.h" 39#include "quartzRandR.h" 40#include "xpr.h" 41#include "xprEvent.h" 42#include "pseudoramiX.h" 43#include "darwin.h" 44#include "darwinEvents.h" 45#include "rootless.h" 46#include "dri.h" 47#include "globals.h" 48#include <Xplugin.h> 49#include "applewmExt.h" 50#include "micmap.h" 51 52#include "rootlessCommon.h" 53 54#ifdef DAMAGE 55# include "damage.h" 56#endif 57 58/* 10.4's deferred update makes X slower.. have to live with the tearing 59 for now.. */ 60#define XP_NO_DEFERRED_UPDATES 8 61 62// Name of GLX bundle for native OpenGL 63static const char *xprOpenGLBundle = "glxCGL.bundle"; 64 65/* 66 * eventHandler 67 * Callback handler for Xplugin events. 68 */ 69static void eventHandler(unsigned int type, const void *arg, 70 unsigned int arg_size, void *data) { 71 72 switch (type) { 73 case XP_EVENT_DISPLAY_CHANGED: 74 DEBUG_LOG("XP_EVENT_DISPLAY_CHANGED\n"); 75 DarwinSendDDXEvent(kXquartzDisplayChanged, 0); 76 break; 77 78 case XP_EVENT_WINDOW_STATE_CHANGED: 79 if (arg_size >= sizeof(xp_window_state_event)) { 80 const xp_window_state_event *ws_arg = arg; 81 82 DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: id=%d, state=%d\n", ws_arg->id, ws_arg->state); 83 DarwinSendDDXEvent(kXquartzWindowState, 2, 84 ws_arg->id, ws_arg->state); 85 } else { 86 DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: ignored\n"); 87 } 88 break; 89 90 case XP_EVENT_WINDOW_MOVED: 91 DEBUG_LOG("XP_EVENT_WINDOW_MOVED\n"); 92 if (arg_size == sizeof(xp_window_id)) { 93 xp_window_id id = * (xp_window_id *) arg; 94 DarwinSendDDXEvent(kXquartzWindowMoved, 1, id); 95 } 96 break; 97 98 case XP_EVENT_SURFACE_DESTROYED: 99 DEBUG_LOG("XP_EVENT_SURFACE_DESTROYED\n"); 100 case XP_EVENT_SURFACE_CHANGED: 101 DEBUG_LOG("XP_EVENT_SURFACE_CHANGED\n"); 102 if (arg_size == sizeof(xp_surface_id)) { 103 int kind; 104 105 if (type == XP_EVENT_SURFACE_DESTROYED) 106 kind = AppleDRISurfaceNotifyDestroyed; 107 else 108 kind = AppleDRISurfaceNotifyChanged; 109 110 DRISurfaceNotify(*(xp_surface_id *) arg, kind); 111 } 112 break; 113#ifdef XP_EVENT_SPACE_CHANGED 114 case XP_EVENT_SPACE_CHANGED: 115 DEBUG_LOG("XP_EVENT_SPACE_CHANGED\n"); 116 if(arg_size == sizeof(uint32_t)) { 117 uint32_t space_id = *(uint32_t *)arg; 118 DarwinSendDDXEvent(kXquartzSpaceChanged, 1, space_id); 119 } 120 break; 121#endif 122 default: 123 ErrorF("Unknown XP_EVENT type (%d) in xprScreen:eventHandler\n", type); 124 } 125} 126 127/* 128 * displayAtIndex 129 * Return the display ID for a particular display index. 130 */ 131static CGDirectDisplayID 132displayAtIndex(int index) 133{ 134 CGError err; 135 CGDisplayCount cnt; 136 CGDirectDisplayID dpy[index+1]; 137 138 err = CGGetActiveDisplayList(index + 1, dpy, &cnt); 139 if (err == kCGErrorSuccess && cnt == index + 1) 140 return dpy[index]; 141 else 142 return kCGNullDirectDisplay; 143} 144 145/* 146 * displayScreenBounds 147 * Return the bounds of a particular display. 148 */ 149static CGRect 150displayScreenBounds(CGDirectDisplayID id) 151{ 152 CGRect frame; 153 154 frame = CGDisplayBounds(id); 155 156 DEBUG_LOG(" %dx%d @ (%d,%d).\n", 157 (int)frame.size.width, (int)frame.size.height, 158 (int)frame.origin.x, (int)frame.origin.y); 159 160 /* Remove menubar to help standard X11 window managers. */ 161 if (XQuartzIsRootless && 162 frame.origin.x == 0 && frame.origin.y == 0) { 163 frame.origin.y += aquaMenuBarHeight; 164 frame.size.height -= aquaMenuBarHeight; 165 } 166 167 DEBUG_LOG(" %dx%d @ (%d,%d).\n", 168 (int)frame.size.width, (int)frame.size.height, 169 (int)frame.origin.x, (int)frame.origin.y); 170 171 return frame; 172} 173 174/* 175 * xprAddPseudoramiXScreens 176 * Add a single virtual screen encompassing all the physical screens 177 * with PseudoramiX. 178 */ 179static void 180xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height, ScreenPtr pScreen) 181{ 182 CGDisplayCount i, displayCount; 183 CGDirectDisplayID *displayList = NULL; 184 CGRect unionRect = CGRectNull, frame; 185 186 // Find all the CoreGraphics displays 187 CGGetActiveDisplayList(0, NULL, &displayCount); 188 DEBUG_LOG("displayCount: %d\n", (int)displayCount); 189 190 if(!displayCount) { 191 ErrorF("CoreGraphics has reported no connected displays. Creating a stub 800x600 display.\n"); 192 *x = *y = 0; 193 *width = 800; 194 *height = 600; 195 PseudoramiXAddScreen(*x, *y, *width, *height); 196 return; 197 } 198 199 /* If the displays are captured, we are in a RandR game mode 200 * on the primary display, so we only want to include the first 201 * display. The others are covered by the shield window. 202 */ 203 if (CGDisplayIsCaptured(kCGDirectMainDisplay)) 204 displayCount = 1; 205 206 displayList = malloc(displayCount * sizeof(CGDirectDisplayID)); 207 if(!displayList) 208 FatalError("Unable to allocate memory for list of displays.\n"); 209 CGGetActiveDisplayList(displayCount, displayList, &displayCount); 210 QuartzCopyDisplayIDs(pScreen, displayCount, displayList); 211 212 /* Get the union of all screens */ 213 for (i = 0; i < displayCount; i++) { 214 CGDirectDisplayID dpy = displayList[i]; 215 frame = displayScreenBounds(dpy); 216 unionRect = CGRectUnion(unionRect, frame); 217 } 218 219 /* Use unionRect as the screen size for the X server. */ 220 *x = unionRect.origin.x; 221 *y = unionRect.origin.y; 222 *width = unionRect.size.width; 223 *height = unionRect.size.height; 224 225 DEBUG_LOG(" screen union origin: (%d,%d) size: (%d,%d).\n", 226 *x, *y, *width, *height); 227 228 /* Tell PseudoramiX about the real screens. */ 229 for (i = 0; i < displayCount; i++) 230 { 231 CGDirectDisplayID dpy = displayList[i]; 232 233 frame = displayScreenBounds(dpy); 234 frame.origin.x -= unionRect.origin.x; 235 frame.origin.y -= unionRect.origin.y; 236 237 DEBUG_LOG(" placed at X11 coordinate (%d,%d).\n", 238 (int)frame.origin.x, (int)frame.origin.y); 239 240 PseudoramiXAddScreen(frame.origin.x, frame.origin.y, 241 frame.size.width, frame.size.height); 242 } 243 244 free(displayList); 245} 246 247/* 248 * xprDisplayInit 249 * Find number of CoreGraphics displays and initialize Xplugin. 250 */ 251static void 252xprDisplayInit(void) 253{ 254 CGDisplayCount displayCount; 255 256 DEBUG_LOG(""); 257 258 CGGetActiveDisplayList(0, NULL, &displayCount); 259 260 /* With PseudoramiX, the X server only sees one screen; only PseudoramiX 261 itself knows about all of the screens. */ 262 263 if (noPseudoramiXExtension) 264 darwinScreensFound = displayCount; 265 else 266 darwinScreensFound = 1; 267 268 if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success) 269 FatalError("Could not initialize the Xplugin library."); 270 271 xp_select_events(XP_EVENT_DISPLAY_CHANGED 272 | XP_EVENT_WINDOW_STATE_CHANGED 273 | XP_EVENT_WINDOW_MOVED 274#ifdef XP_EVENT_SPACE_CHANGED 275 | XP_EVENT_SPACE_CHANGED 276#endif 277 | XP_EVENT_SURFACE_CHANGED 278 | XP_EVENT_SURFACE_DESTROYED, 279 eventHandler, NULL); 280 281 AppleDRIExtensionInit(); 282 xprAppleWMInit(); 283 284 XQuartzIsRootless = XQuartzRootlessDefault; 285 if (!XQuartzIsRootless) 286 RootlessHideAllWindows(); 287} 288 289/* 290 * xprAddScreen 291 * Init the framebuffer and record pixmap parameters for the screen. 292 */ 293static Bool 294xprAddScreen(int index, ScreenPtr pScreen) 295{ 296 DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); 297 int depth = darwinDesiredDepth; 298 299 DEBUG_LOG("index=%d depth=%d\n", index, depth); 300 301 if(depth == -1) { 302#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 303 depth = CGDisplaySamplesPerPixel(kCGDirectMainDisplay) * CGDisplayBitsPerSample(kCGDirectMainDisplay); 304#else 305 CGDisplayModeRef modeRef; 306 CFStringRef encStrRef; 307 308 modeRef = CGDisplayCopyDisplayMode(kCGDirectMainDisplay); 309 if(!modeRef) 310 goto have_depth; 311 312 encStrRef = CGDisplayModeCopyPixelEncoding(modeRef); 313 CFRelease(modeRef); 314 if(!encStrRef) 315 goto have_depth; 316 317 if(CFStringCompare(encStrRef, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 318 depth = 24; 319 } else if(CFStringCompare(encStrRef, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 320 depth = 15; 321 } else if(CFStringCompare(encStrRef, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 322 depth = 8; 323 } 324 325 CFRelease(encStrRef); 326#endif 327 } 328 329have_depth: 330 switch(depth) { 331 case 8: // pseudo-working 332 dfb->visuals = PseudoColorMask; 333 dfb->preferredCVC = PseudoColor; 334 dfb->depth = 8; 335 dfb->bitsPerRGB = 8; 336 dfb->bitsPerPixel = 8; 337 dfb->redMask = 0; 338 dfb->greenMask = 0; 339 dfb->blueMask = 0; 340 break; 341 case 15: 342 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 343 dfb->preferredCVC = TrueColor; 344 dfb->depth = 15; 345 dfb->bitsPerRGB = 5; 346 dfb->bitsPerPixel = 16; 347 dfb->redMask = RM_ARGB(0,5,5,5); 348 dfb->greenMask = GM_ARGB(0,5,5,5); 349 dfb->blueMask = BM_ARGB(0,5,5,5); 350 break; 351// case 24: 352 default: 353 if(depth != 24) 354 ErrorF("Unsupported color depth requested. Defaulting to 24bit. (depth=%d darwinDesiredDepth=%d)\n", depth, darwinDesiredDepth); 355 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 356 dfb->preferredCVC = TrueColor; 357 dfb->depth = 24; 358 dfb->bitsPerRGB = 8; 359 dfb->bitsPerPixel = 32; 360 dfb->redMask = RM_ARGB(0,8,8,8); 361 dfb->greenMask = GM_ARGB(0,8,8,8); 362 dfb->blueMask = BM_ARGB(0,8,8,8); 363 break; 364 } 365 366 if (noPseudoramiXExtension) 367 { 368 CGDirectDisplayID dpy; 369 CGRect frame; 370 371 ErrorF("Warning: noPseudoramiXExtension!\n"); 372 373 dpy = displayAtIndex(index); 374 QuartzCopyDisplayIDs(pScreen, 1, &dpy); 375 376 frame = displayScreenBounds(dpy); 377 378 dfb->x = frame.origin.x; 379 dfb->y = frame.origin.y; 380 dfb->width = frame.size.width; 381 dfb->height = frame.size.height; 382 } 383 else 384 { 385 xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height, pScreen); 386 } 387 388 /* Passing zero width (pitch) makes miCreateScreenResources set the 389 screen pixmap to the framebuffer pointer, i.e. NULL. The generic 390 rootless code takes care of making this work. */ 391 dfb->pitch = 0; 392 dfb->framebuffer = NULL; 393 394 DRIScreenInit(pScreen); 395 396 return TRUE; 397} 398 399/* 400 * xprSetupScreen 401 * Setup the screen for rootless access. 402 */ 403static Bool 404xprSetupScreen(int index, ScreenPtr pScreen) 405{ 406 // Initialize accelerated rootless drawing 407 // Note that this must be done before DamageSetup(). 408 409 // These are crashing ugly... better to be stable and not crash for now. 410 //RootlessAccelInit(pScreen); 411 412#ifdef DAMAGE 413 // The Damage extension needs to wrap underneath the 414 // generic rootless layer, so do it now. 415 if (!DamageSetup(pScreen)) 416 return FALSE; 417#endif 418 419 // Initialize generic rootless code 420 if (!xprInit(pScreen)) 421 return FALSE; 422 423 return DRIFinishScreenInit(pScreen); 424} 425 426/* 427 * xprUpdateScreen 428 * Update screen after configuation change. 429 */ 430static void 431xprUpdateScreen(ScreenPtr pScreen) 432{ 433 rootlessGlobalOffsetX = darwinMainScreenX; 434 rootlessGlobalOffsetY = darwinMainScreenY; 435 436 AppleWMSetScreenOrigin(pScreen->root); 437 438 RootlessRepositionWindows(pScreen); 439 RootlessUpdateScreenPixmap(pScreen); 440} 441 442/* 443 * xprInitInput 444 * Finalize xpr specific setup. 445 */ 446static void 447xprInitInput(int argc, char **argv) 448{ 449 int i; 450 451 rootlessGlobalOffsetX = darwinMainScreenX; 452 rootlessGlobalOffsetY = darwinMainScreenY; 453 454 for (i = 0; i < screenInfo.numScreens; i++) 455 AppleWMSetScreenOrigin(screenInfo.screens[i]->root); 456} 457 458/* 459 * Quartz display mode function list. 460 */ 461static QuartzModeProcsRec xprModeProcs = { 462 xprDisplayInit, 463 xprAddScreen, 464 xprSetupScreen, 465 xprInitInput, 466 QuartzInitCursor, 467 QuartzSuspendXCursor, 468 QuartzResumeXCursor, 469 xprAddPseudoramiXScreens, 470 xprUpdateScreen, 471 xprIsX11Window, 472 xprHideWindows, 473 RootlessFrameForWindow, 474 TopLevelParent, 475 DRICreateSurface, 476 DRIDestroySurface 477}; 478 479/* 480 * QuartzModeBundleInit 481 * Initialize the display mode bundle after loading. 482 */ 483Bool 484QuartzModeBundleInit(void) 485{ 486 quartzProcs = &xprModeProcs; 487 quartzOpenGLBundle = xprOpenGLBundle; 488 return TRUE; 489} 490