xprScreen.c revision c8548ba8
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 darwinScreensFound = 1; 288 289 if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success) 290 FatalError("Could not initialize the Xplugin library."); 291 292 xp_select_events(XP_EVENT_DISPLAY_CHANGED 293 | XP_EVENT_WINDOW_STATE_CHANGED 294 | XP_EVENT_WINDOW_MOVED 295#ifdef XP_EVENT_SPACE_CHANGED 296 | XP_EVENT_SPACE_CHANGED 297#endif 298 | XP_EVENT_SURFACE_CHANGED 299 | XP_EVENT_SURFACE_DESTROYED, 300 eventHandler, NULL); 301 302 AppleDRIExtensionInit(); 303 xprAppleWMInit(); 304 305 XQuartzIsRootless = XQuartzRootlessDefault; 306 if (!XQuartzIsRootless) 307 RootlessHideAllWindows(); 308} 309 310/* 311 * xprAddScreen 312 * Init the framebuffer and record pixmap parameters for the screen. 313 */ 314static Bool 315xprAddScreen(int index, ScreenPtr pScreen) 316{ 317 DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); 318 int depth = darwinDesiredDepth; 319 320 DEBUG_LOG("index=%d depth=%d\n", index, depth); 321 322 if (depth == -1) { 323 CGDisplayModeRef modeRef; 324 CFStringRef encStrRef; 325 326 modeRef = CGDisplayCopyDisplayMode(kCGDirectMainDisplay); 327 if (!modeRef) 328 goto have_depth; 329 330 encStrRef = CGDisplayModeCopyPixelEncoding(modeRef); 331 CFRelease(modeRef); 332 if (!encStrRef) 333 goto have_depth; 334 335 if (CFStringCompare(encStrRef, CFSTR(IO32BitDirectPixels), 336 kCFCompareCaseInsensitive) == 337 kCFCompareEqualTo) { 338 depth = 24; 339 } 340 else if (CFStringCompare(encStrRef, CFSTR(IO16BitDirectPixels), 341 kCFCompareCaseInsensitive) == 342 kCFCompareEqualTo) { 343 depth = 15; 344 } 345 else if (CFStringCompare(encStrRef, CFSTR(IO8BitIndexedPixels), 346 kCFCompareCaseInsensitive) == 347 kCFCompareEqualTo) { 348 depth = 8; 349 } 350 351 CFRelease(encStrRef); 352 } 353 354have_depth: 355 switch (depth) { 356 case 8: // pseudo-working 357 dfb->visuals = PseudoColorMask; 358 dfb->preferredCVC = PseudoColor; 359 dfb->depth = 8; 360 dfb->bitsPerRGB = 8; 361 dfb->bitsPerPixel = 8; 362 dfb->redMask = 0; 363 dfb->greenMask = 0; 364 dfb->blueMask = 0; 365 break; 366 367#if 0 368 // Removed because Mountain Lion removed support for 369 // 15bit backing stores. We can possibly re-add 370 // this once libXplugin is updated to work around it. 371 case 15: 372 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 373 dfb->preferredCVC = TrueColor; 374 dfb->depth = 15; 375 dfb->bitsPerRGB = 5; 376 dfb->bitsPerPixel = 16; 377 dfb->redMask = RM_ARGB(0, 5, 5, 5); 378 dfb->greenMask = GM_ARGB(0, 5, 5, 5); 379 dfb->blueMask = BM_ARGB(0, 5, 5, 5); 380 break; 381#endif 382 383 // case 24: 384 default: 385 if (depth != 24) 386 ErrorF( 387 "Unsupported color depth requested. Defaulting to 24bit. (depth=%d darwinDesiredDepth=%d)\n", 388 depth, darwinDesiredDepth); 389 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 390 dfb->preferredCVC = TrueColor; 391 dfb->depth = 24; 392 dfb->bitsPerRGB = 8; 393 dfb->bitsPerPixel = 32; 394 dfb->redMask = RM_ARGB(0, 8, 8, 8); 395 dfb->greenMask = GM_ARGB(0, 8, 8, 8); 396 dfb->blueMask = BM_ARGB(0, 8, 8, 8); 397 break; 398 } 399 400 if (noPseudoramiXExtension) { 401 CGDirectDisplayID dpy; 402 CGRect frame; 403 404 ErrorF("Warning: noPseudoramiXExtension!\n"); 405 406 dpy = displayAtIndex(index); 407 QuartzCopyDisplayIDs(pScreen, 1, &dpy); 408 409 frame = displayScreenBounds(dpy); 410 411 dfb->x = frame.origin.x; 412 dfb->y = frame.origin.y; 413 dfb->width = frame.size.width; 414 dfb->height = frame.size.height; 415 } 416 else { 417 xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height, 418 pScreen); 419 } 420 421 /* Passing zero width (pitch) makes miCreateScreenResources set the 422 screen pixmap to the framebuffer pointer, i.e. NULL. The generic 423 rootless code takes care of making this work. */ 424 dfb->pitch = 0; 425 dfb->framebuffer = NULL; 426 427 DRIScreenInit(pScreen); 428 429 return TRUE; 430} 431 432/* 433 * xprSetupScreen 434 * Setup the screen for rootless access. 435 */ 436static Bool 437xprSetupScreen(int index, ScreenPtr pScreen) 438{ 439#ifdef DAMAGE 440 // The Damage extension needs to wrap underneath the 441 // generic rootless layer, so do it now. 442 if (!DamageSetup(pScreen)) 443 return FALSE; 444#endif 445 446 // Initialize generic rootless code 447 if (!xprInit(pScreen)) 448 return FALSE; 449 450 return DRIFinishScreenInit(pScreen); 451} 452 453/* 454 * xprUpdateScreen 455 * Update screen after configuration change. 456 */ 457static void 458xprUpdateScreen(ScreenPtr pScreen) 459{ 460 rootlessGlobalOffsetX = darwinMainScreenX; 461 rootlessGlobalOffsetY = darwinMainScreenY; 462 463 AppleWMSetScreenOrigin(pScreen->root); 464 465 RootlessRepositionWindows(pScreen); 466 RootlessUpdateScreenPixmap(pScreen); 467} 468 469/* 470 * xprInitInput 471 * Finalize xpr specific setup. 472 */ 473static void 474xprInitInput(int argc, char **argv) 475{ 476 int i; 477 478 rootlessGlobalOffsetX = darwinMainScreenX; 479 rootlessGlobalOffsetY = darwinMainScreenY; 480 481 for (i = 0; i < screenInfo.numScreens; i++) 482 AppleWMSetScreenOrigin(screenInfo.screens[i]->root); 483} 484 485/* 486 * Quartz display mode function list. 487 */ 488static QuartzModeProcsRec xprModeProcs = { 489 xprDisplayInit, 490 xprAddScreen, 491 xprSetupScreen, 492 xprInitInput, 493 QuartzInitCursor, 494 QuartzSuspendXCursor, 495 QuartzResumeXCursor, 496 xprAddPseudoramiXScreens, 497 xprUpdateScreen, 498 xprIsX11Window, 499 xprHideWindows, 500 RootlessFrameForWindow, 501 TopLevelParent, 502 DRICreateSurface, 503 DRIDestroySurface 504}; 505 506/* 507 * QuartzModeBundleInit 508 * Initialize the display mode bundle after loading. 509 */ 510Bool 511QuartzModeBundleInit(void) 512{ 513 quartzProcs = &xprModeProcs; 514 quartzOpenGLBundle = xprOpenGLBundle; 515 return TRUE; 516} 517