xprScreen.c revision ed6184df
1/* 2 * Xplugin rootless implementation screen functions 3 * 4 * Copyright (c) 2002-2012 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 "inputstr.h" 37#include "quartz.h" 38#include "quartzRandR.h" 39#include "xpr.h" 40#include "xprEvent.h" 41#include "pseudoramiX.h" 42#include "darwinEvents.h" 43#include "rootless.h" 44#include "dri.h" 45#include "globals.h" 46#include <Xplugin.h> 47#include "applewmExt.h" 48#include "micmap.h" 49 50#include "rootlessCommon.h" 51 52#ifdef DAMAGE 53#include "damage.h" 54#endif 55 56#include "nonsdk_extinit.h" 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 70eventHandler(unsigned int type, const void *arg, 71 unsigned int arg_size, void *data) 72{ 73 74 switch (type) { 75 case XP_EVENT_DISPLAY_CHANGED: 76 DEBUG_LOG("XP_EVENT_DISPLAY_CHANGED\n"); 77 DarwinSendDDXEvent(kXquartzDisplayChanged, 0); 78 break; 79 80 case XP_EVENT_WINDOW_STATE_CHANGED: 81 if (arg_size >= sizeof(xp_window_state_event)) { 82 const xp_window_state_event *ws_arg = arg; 83 84 DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: id=%d, state=%d\n", 85 ws_arg->id, 86 ws_arg->state); 87 DarwinSendDDXEvent(kXquartzWindowState, 2, 88 ws_arg->id, ws_arg->state); 89 } 90 else { 91 DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: ignored\n"); 92 } 93 break; 94 95 case XP_EVENT_WINDOW_MOVED: 96 DEBUG_LOG("XP_EVENT_WINDOW_MOVED\n"); 97 if (arg_size == sizeof(xp_window_id)) { 98 xp_window_id id = *(xp_window_id *)arg; 99 DarwinSendDDXEvent(kXquartzWindowMoved, 1, id); 100 } 101 break; 102 103 case XP_EVENT_SURFACE_DESTROYED: 104 DEBUG_LOG("XP_EVENT_SURFACE_DESTROYED\n"); 105 106 case XP_EVENT_SURFACE_CHANGED: 107 DEBUG_LOG("XP_EVENT_SURFACE_CHANGED\n"); 108 if (arg_size == sizeof(xp_surface_id)) { 109 int kind; 110 111 if (type == XP_EVENT_SURFACE_DESTROYED) 112 kind = AppleDRISurfaceNotifyDestroyed; 113 else 114 kind = AppleDRISurfaceNotifyChanged; 115 116 DRISurfaceNotify(*(xp_surface_id *)arg, kind); 117 } 118 break; 119 120#ifdef XP_EVENT_SPACE_CHANGED 121 case XP_EVENT_SPACE_CHANGED: 122 DEBUG_LOG("XP_EVENT_SPACE_CHANGED\n"); 123 if (arg_size == sizeof(uint32_t)) { 124 uint32_t space_id = *(uint32_t *)arg; 125 DarwinSendDDXEvent(kXquartzSpaceChanged, 1, space_id); 126 } 127 break; 128 129#endif 130 default: 131 ErrorF("Unknown XP_EVENT type (%d) in xprScreen:eventHandler\n", type); 132 } 133} 134 135/* 136 * displayAtIndex 137 * Return the display ID for a particular display index. 138 */ 139static CGDirectDisplayID 140displayAtIndex(int index) 141{ 142 CGError err; 143 CGDisplayCount cnt; 144 CGDirectDisplayID dpy[index + 1]; 145 146 err = CGGetActiveDisplayList(index + 1, dpy, &cnt); 147 if (err == kCGErrorSuccess && cnt == index + 1) 148 return dpy[index]; 149 else 150 return kCGNullDirectDisplay; 151} 152 153/* 154 * displayScreenBounds 155 * Return the bounds of a particular display. 156 */ 157static CGRect 158displayScreenBounds(CGDirectDisplayID id) 159{ 160 CGRect frame; 161 162 frame = CGDisplayBounds(id); 163 164 DEBUG_LOG(" %dx%d @ (%d,%d).\n", 165 (int)frame.size.width, (int)frame.size.height, 166 (int)frame.origin.x, (int)frame.origin.y); 167 168 Boolean spacePerDisplay = false; 169 Boolean ok; 170 (void)CFPreferencesAppSynchronize(CFSTR("com.apple.spaces")); 171 spacePerDisplay = ! CFPreferencesGetAppBooleanValue(CFSTR("spans-displays"), 172 CFSTR("com.apple.spaces"), 173 &ok); 174 if (!ok) 175 spacePerDisplay = true; 176 177 /* Remove menubar to help standard X11 window managers. 178 * On Mavericks and later, the menu bar is on all displays when spans-displays is false or unset. 179 */ 180 if (XQuartzIsRootless && 181 (spacePerDisplay || (frame.origin.x == 0 && frame.origin.y == 0))) { 182 frame.origin.y += aquaMenuBarHeight; 183 frame.size.height -= aquaMenuBarHeight; 184 } 185 186 DEBUG_LOG(" %dx%d @ (%d,%d).\n", 187 (int)frame.size.width, (int)frame.size.height, 188 (int)frame.origin.x, (int)frame.origin.y); 189 190 return frame; 191} 192 193/* 194 * xprAddPseudoramiXScreens 195 * Add a single virtual screen encompassing all the physical screens 196 * with PseudoramiX. 197 */ 198static void 199xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height, 200 ScreenPtr pScreen) 201{ 202 CGDisplayCount i, displayCount; 203 CGDirectDisplayID *displayList = NULL; 204 CGRect unionRect = CGRectNull, frame; 205 206 // Find all the CoreGraphics displays 207 CGGetActiveDisplayList(0, NULL, &displayCount); 208 DEBUG_LOG("displayCount: %d\n", (int)displayCount); 209 210 if (!displayCount) { 211 ErrorF( 212 "CoreGraphics has reported no connected displays. Creating a stub 800x600 display.\n"); 213 *x = *y = 0; 214 *width = 800; 215 *height = 600; 216 PseudoramiXAddScreen(*x, *y, *width, *height); 217 QuartzCopyDisplayIDs(pScreen, 0, NULL); 218 return; 219 } 220 221 /* If the displays are captured, we are in a RandR game mode 222 * on the primary display, so we only want to include the first 223 * display. The others are covered by the shield window. 224 */ 225 if (CGDisplayIsCaptured(kCGDirectMainDisplay)) 226 displayCount = 1; 227 228 displayList = malloc(displayCount * sizeof(CGDirectDisplayID)); 229 if (!displayList) 230 FatalError("Unable to allocate memory for list of displays.\n"); 231 CGGetActiveDisplayList(displayCount, displayList, &displayCount); 232 QuartzCopyDisplayIDs(pScreen, displayCount, displayList); 233 234 /* Get the union of all screens */ 235 for (i = 0; i < displayCount; i++) { 236 CGDirectDisplayID dpy = displayList[i]; 237 frame = displayScreenBounds(dpy); 238 unionRect = CGRectUnion(unionRect, frame); 239 } 240 241 /* Use unionRect as the screen size for the X server. */ 242 *x = unionRect.origin.x; 243 *y = unionRect.origin.y; 244 *width = unionRect.size.width; 245 *height = unionRect.size.height; 246 247 DEBUG_LOG(" screen union origin: (%d,%d) size: (%d,%d).\n", 248 *x, *y, *width, *height); 249 250 /* Tell PseudoramiX about the real screens. */ 251 for (i = 0; i < displayCount; i++) { 252 CGDirectDisplayID dpy = displayList[i]; 253 254 frame = displayScreenBounds(dpy); 255 frame.origin.x -= unionRect.origin.x; 256 frame.origin.y -= unionRect.origin.y; 257 258 DEBUG_LOG(" placed at X11 coordinate (%d,%d).\n", 259 (int)frame.origin.x, (int)frame.origin.y); 260 261 PseudoramiXAddScreen(frame.origin.x, frame.origin.y, 262 frame.size.width, frame.size.height); 263 } 264 265 free(displayList); 266} 267 268/* 269 * xprDisplayInit 270 * Find number of CoreGraphics displays and initialize Xplugin. 271 */ 272static void 273xprDisplayInit(void) 274{ 275 CGDisplayCount displayCount; 276 277 TRACE(); 278 279 CGGetActiveDisplayList(0, NULL, &displayCount); 280 281 /* With PseudoramiX, the X server only sees one screen; only PseudoramiX 282 itself knows about all of the screens. */ 283 284 if (noPseudoramiXExtension) { 285 darwinScreensFound = displayCount; 286 } else { 287 PseudoramiXExtensionInit(); 288 darwinScreensFound = 1; 289 } 290 291 if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success) 292 FatalError("Could not initialize the Xplugin library."); 293 294 xp_select_events(XP_EVENT_DISPLAY_CHANGED 295 | XP_EVENT_WINDOW_STATE_CHANGED 296 | XP_EVENT_WINDOW_MOVED 297#ifdef XP_EVENT_SPACE_CHANGED 298 | XP_EVENT_SPACE_CHANGED 299#endif 300 | XP_EVENT_SURFACE_CHANGED 301 | XP_EVENT_SURFACE_DESTROYED, 302 eventHandler, NULL); 303 304 AppleDRIExtensionInit(); 305 xprAppleWMInit(); 306 307 XQuartzIsRootless = XQuartzRootlessDefault; 308 if (!XQuartzIsRootless) 309 RootlessHideAllWindows(); 310} 311 312/* 313 * xprAddScreen 314 * Init the framebuffer and record pixmap parameters for the screen. 315 */ 316static Bool 317xprAddScreen(int index, ScreenPtr pScreen) 318{ 319 DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); 320 int depth = darwinDesiredDepth; 321 322 DEBUG_LOG("index=%d depth=%d\n", index, depth); 323 324 if (depth == -1) { 325 CGDisplayModeRef modeRef; 326 CFStringRef encStrRef; 327 328 modeRef = CGDisplayCopyDisplayMode(kCGDirectMainDisplay); 329 if (!modeRef) 330 goto have_depth; 331 332 encStrRef = CGDisplayModeCopyPixelEncoding(modeRef); 333 CFRelease(modeRef); 334 if (!encStrRef) 335 goto have_depth; 336 337 if (CFStringCompare(encStrRef, CFSTR(IO32BitDirectPixels), 338 kCFCompareCaseInsensitive) == 339 kCFCompareEqualTo) { 340 depth = 24; 341 } 342 else if (CFStringCompare(encStrRef, CFSTR(IO16BitDirectPixels), 343 kCFCompareCaseInsensitive) == 344 kCFCompareEqualTo) { 345 depth = 15; 346 } 347 else if (CFStringCompare(encStrRef, CFSTR(IO8BitIndexedPixels), 348 kCFCompareCaseInsensitive) == 349 kCFCompareEqualTo) { 350 depth = 8; 351 } 352 353 CFRelease(encStrRef); 354 } 355 356have_depth: 357 switch (depth) { 358 case 8: // pseudo-working 359 dfb->visuals = PseudoColorMask; 360 dfb->preferredCVC = PseudoColor; 361 dfb->depth = 8; 362 dfb->bitsPerRGB = 8; 363 dfb->bitsPerPixel = 8; 364 dfb->redMask = 0; 365 dfb->greenMask = 0; 366 dfb->blueMask = 0; 367 break; 368 369#if 0 370 // Removed because Mountain Lion removed support for 371 // 15bit backing stores. We can possibly re-add 372 // this once libXplugin is updated to work around it. 373 case 15: 374 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 375 dfb->preferredCVC = TrueColor; 376 dfb->depth = 15; 377 dfb->bitsPerRGB = 5; 378 dfb->bitsPerPixel = 16; 379 dfb->redMask = RM_ARGB(0, 5, 5, 5); 380 dfb->greenMask = GM_ARGB(0, 5, 5, 5); 381 dfb->blueMask = BM_ARGB(0, 5, 5, 5); 382 break; 383#endif 384 385 // case 24: 386 default: 387 if (depth != 24) 388 ErrorF( 389 "Unsupported color depth requested. Defaulting to 24bit. (depth=%d darwinDesiredDepth=%d)\n", 390 depth, darwinDesiredDepth); 391 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 392 dfb->preferredCVC = TrueColor; 393 dfb->depth = 24; 394 dfb->bitsPerRGB = 8; 395 dfb->bitsPerPixel = 32; 396 dfb->redMask = RM_ARGB(0, 8, 8, 8); 397 dfb->greenMask = GM_ARGB(0, 8, 8, 8); 398 dfb->blueMask = BM_ARGB(0, 8, 8, 8); 399 break; 400 } 401 402 if (noPseudoramiXExtension) { 403 CGDirectDisplayID dpy; 404 CGRect frame; 405 406 ErrorF("Warning: noPseudoramiXExtension!\n"); 407 408 dpy = displayAtIndex(index); 409 QuartzCopyDisplayIDs(pScreen, 1, &dpy); 410 411 frame = displayScreenBounds(dpy); 412 413 dfb->x = frame.origin.x; 414 dfb->y = frame.origin.y; 415 dfb->width = frame.size.width; 416 dfb->height = frame.size.height; 417 } 418 else { 419 xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height, 420 pScreen); 421 } 422 423 /* Passing zero width (pitch) makes miCreateScreenResources set the 424 screen pixmap to the framebuffer pointer, i.e. NULL. The generic 425 rootless code takes care of making this work. */ 426 dfb->pitch = 0; 427 dfb->framebuffer = NULL; 428 429 DRIScreenInit(pScreen); 430 431 return TRUE; 432} 433 434/* 435 * xprSetupScreen 436 * Setup the screen for rootless access. 437 */ 438static Bool 439xprSetupScreen(int index, ScreenPtr pScreen) 440{ 441#ifdef DAMAGE 442 // The Damage extension needs to wrap underneath the 443 // generic rootless layer, so do it now. 444 if (!DamageSetup(pScreen)) 445 return FALSE; 446#endif 447 448 // Initialize generic rootless code 449 if (!xprInit(pScreen)) 450 return FALSE; 451 452 return DRIFinishScreenInit(pScreen); 453} 454 455/* 456 * xprUpdateScreen 457 * Update screen after configuration change. 458 */ 459static void 460xprUpdateScreen(ScreenPtr pScreen) 461{ 462 rootlessGlobalOffsetX = darwinMainScreenX; 463 rootlessGlobalOffsetY = darwinMainScreenY; 464 465 AppleWMSetScreenOrigin(pScreen->root); 466 467 RootlessRepositionWindows(pScreen); 468 RootlessUpdateScreenPixmap(pScreen); 469} 470 471/* 472 * xprInitInput 473 * Finalize xpr specific setup. 474 */ 475static void 476xprInitInput(int argc, char **argv) 477{ 478 int i; 479 480 rootlessGlobalOffsetX = darwinMainScreenX; 481 rootlessGlobalOffsetY = darwinMainScreenY; 482 483 for (i = 0; i < screenInfo.numScreens; i++) 484 AppleWMSetScreenOrigin(screenInfo.screens[i]->root); 485} 486 487/* 488 * Quartz display mode function list. 489 */ 490static QuartzModeProcsRec xprModeProcs = { 491 xprDisplayInit, 492 xprAddScreen, 493 xprSetupScreen, 494 xprInitInput, 495 QuartzInitCursor, 496 QuartzSuspendXCursor, 497 QuartzResumeXCursor, 498 xprAddPseudoramiXScreens, 499 xprUpdateScreen, 500 xprIsX11Window, 501 xprHideWindows, 502 RootlessFrameForWindow, 503 TopLevelParent, 504 DRICreateSurface, 505 DRIDestroySurface 506}; 507 508/* 509 * QuartzModeBundleInit 510 * Initialize the display mode bundle after loading. 511 */ 512Bool 513QuartzModeBundleInit(void) 514{ 515 quartzProcs = &xprModeProcs; 516 quartzOpenGLBundle = xprOpenGLBundle; 517 return TRUE; 518} 519