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