xprScreen.c revision 9ace9065
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 QuartzCopyDisplayIDs(pScreen, 0, NULL); 197 return; 198 } 199 200 /* If the displays are captured, we are in a RandR game mode 201 * on the primary display, so we only want to include the first 202 * display. The others are covered by the shield window. 203 */ 204 if (CGDisplayIsCaptured(kCGDirectMainDisplay)) 205 displayCount = 1; 206 207 displayList = malloc(displayCount * sizeof(CGDirectDisplayID)); 208 if(!displayList) 209 FatalError("Unable to allocate memory for list of displays.\n"); 210 CGGetActiveDisplayList(displayCount, displayList, &displayCount); 211 QuartzCopyDisplayIDs(pScreen, displayCount, displayList); 212 213 /* Get the union of all screens */ 214 for (i = 0; i < displayCount; i++) { 215 CGDirectDisplayID dpy = displayList[i]; 216 frame = displayScreenBounds(dpy); 217 unionRect = CGRectUnion(unionRect, frame); 218 } 219 220 /* Use unionRect as the screen size for the X server. */ 221 *x = unionRect.origin.x; 222 *y = unionRect.origin.y; 223 *width = unionRect.size.width; 224 *height = unionRect.size.height; 225 226 DEBUG_LOG(" screen union origin: (%d,%d) size: (%d,%d).\n", 227 *x, *y, *width, *height); 228 229 /* Tell PseudoramiX about the real screens. */ 230 for (i = 0; i < displayCount; i++) 231 { 232 CGDirectDisplayID dpy = displayList[i]; 233 234 frame = displayScreenBounds(dpy); 235 frame.origin.x -= unionRect.origin.x; 236 frame.origin.y -= unionRect.origin.y; 237 238 DEBUG_LOG(" placed at X11 coordinate (%d,%d).\n", 239 (int)frame.origin.x, (int)frame.origin.y); 240 241 PseudoramiXAddScreen(frame.origin.x, frame.origin.y, 242 frame.size.width, frame.size.height); 243 } 244 245 free(displayList); 246} 247 248/* 249 * xprDisplayInit 250 * Find number of CoreGraphics displays and initialize Xplugin. 251 */ 252static void 253xprDisplayInit(void) 254{ 255 CGDisplayCount displayCount; 256 257 DEBUG_LOG(""); 258 259 CGGetActiveDisplayList(0, NULL, &displayCount); 260 261 /* With PseudoramiX, the X server only sees one screen; only PseudoramiX 262 itself knows about all of the screens. */ 263 264 if (noPseudoramiXExtension) 265 darwinScreensFound = displayCount; 266 else 267 darwinScreensFound = 1; 268 269 if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success) 270 FatalError("Could not initialize the Xplugin library."); 271 272 xp_select_events(XP_EVENT_DISPLAY_CHANGED 273 | XP_EVENT_WINDOW_STATE_CHANGED 274 | XP_EVENT_WINDOW_MOVED 275#ifdef XP_EVENT_SPACE_CHANGED 276 | XP_EVENT_SPACE_CHANGED 277#endif 278 | XP_EVENT_SURFACE_CHANGED 279 | XP_EVENT_SURFACE_DESTROYED, 280 eventHandler, NULL); 281 282 AppleDRIExtensionInit(); 283 xprAppleWMInit(); 284 285 XQuartzIsRootless = XQuartzRootlessDefault; 286 if (!XQuartzIsRootless) 287 RootlessHideAllWindows(); 288} 289 290/* 291 * xprAddScreen 292 * Init the framebuffer and record pixmap parameters for the screen. 293 */ 294static Bool 295xprAddScreen(int index, ScreenPtr pScreen) 296{ 297 DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); 298 int depth = darwinDesiredDepth; 299 300 DEBUG_LOG("index=%d depth=%d\n", index, depth); 301 302 if(depth == -1) { 303#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 304 depth = CGDisplaySamplesPerPixel(kCGDirectMainDisplay) * CGDisplayBitsPerSample(kCGDirectMainDisplay); 305#else 306 CGDisplayModeRef modeRef; 307 CFStringRef encStrRef; 308 309 modeRef = CGDisplayCopyDisplayMode(kCGDirectMainDisplay); 310 if(!modeRef) 311 goto have_depth; 312 313 encStrRef = CGDisplayModeCopyPixelEncoding(modeRef); 314 CFRelease(modeRef); 315 if(!encStrRef) 316 goto have_depth; 317 318 if(CFStringCompare(encStrRef, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 319 depth = 24; 320 } else if(CFStringCompare(encStrRef, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 321 depth = 15; 322 } else if(CFStringCompare(encStrRef, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 323 depth = 8; 324 } 325 326 CFRelease(encStrRef); 327#endif 328 } 329 330have_depth: 331 switch(depth) { 332 case 8: // pseudo-working 333 dfb->visuals = PseudoColorMask; 334 dfb->preferredCVC = PseudoColor; 335 dfb->depth = 8; 336 dfb->bitsPerRGB = 8; 337 dfb->bitsPerPixel = 8; 338 dfb->redMask = 0; 339 dfb->greenMask = 0; 340 dfb->blueMask = 0; 341 break; 342 case 15: 343 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 344 dfb->preferredCVC = TrueColor; 345 dfb->depth = 15; 346 dfb->bitsPerRGB = 5; 347 dfb->bitsPerPixel = 16; 348 dfb->redMask = RM_ARGB(0,5,5,5); 349 dfb->greenMask = GM_ARGB(0,5,5,5); 350 dfb->blueMask = BM_ARGB(0,5,5,5); 351 break; 352// case 24: 353 default: 354 if(depth != 24) 355 ErrorF("Unsupported color depth requested. Defaulting to 24bit. (depth=%d darwinDesiredDepth=%d)\n", depth, darwinDesiredDepth); 356 dfb->visuals = TrueColorMask; //LARGE_VISUALS; 357 dfb->preferredCVC = TrueColor; 358 dfb->depth = 24; 359 dfb->bitsPerRGB = 8; 360 dfb->bitsPerPixel = 32; 361 dfb->redMask = RM_ARGB(0,8,8,8); 362 dfb->greenMask = GM_ARGB(0,8,8,8); 363 dfb->blueMask = BM_ARGB(0,8,8,8); 364 break; 365 } 366 367 if (noPseudoramiXExtension) 368 { 369 CGDirectDisplayID dpy; 370 CGRect frame; 371 372 ErrorF("Warning: noPseudoramiXExtension!\n"); 373 374 dpy = displayAtIndex(index); 375 QuartzCopyDisplayIDs(pScreen, 1, &dpy); 376 377 frame = displayScreenBounds(dpy); 378 379 dfb->x = frame.origin.x; 380 dfb->y = frame.origin.y; 381 dfb->width = frame.size.width; 382 dfb->height = frame.size.height; 383 } 384 else 385 { 386 xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height, pScreen); 387 } 388 389 /* Passing zero width (pitch) makes miCreateScreenResources set the 390 screen pixmap to the framebuffer pointer, i.e. NULL. The generic 391 rootless code takes care of making this work. */ 392 dfb->pitch = 0; 393 dfb->framebuffer = NULL; 394 395 DRIScreenInit(pScreen); 396 397 return TRUE; 398} 399 400/* 401 * xprSetupScreen 402 * Setup the screen for rootless access. 403 */ 404static Bool 405xprSetupScreen(int index, ScreenPtr pScreen) 406{ 407#ifdef DAMAGE 408 // The Damage extension needs to wrap underneath the 409 // generic rootless layer, so do it now. 410 if (!DamageSetup(pScreen)) 411 return FALSE; 412#endif 413 414 // Initialize generic rootless code 415 if (!xprInit(pScreen)) 416 return FALSE; 417 418 return DRIFinishScreenInit(pScreen); 419} 420 421/* 422 * xprUpdateScreen 423 * Update screen after configuation change. 424 */ 425static void 426xprUpdateScreen(ScreenPtr pScreen) 427{ 428 rootlessGlobalOffsetX = darwinMainScreenX; 429 rootlessGlobalOffsetY = darwinMainScreenY; 430 431 AppleWMSetScreenOrigin(pScreen->root); 432 433 RootlessRepositionWindows(pScreen); 434 RootlessUpdateScreenPixmap(pScreen); 435} 436 437/* 438 * xprInitInput 439 * Finalize xpr specific setup. 440 */ 441static void 442xprInitInput(int argc, char **argv) 443{ 444 int i; 445 446 rootlessGlobalOffsetX = darwinMainScreenX; 447 rootlessGlobalOffsetY = darwinMainScreenY; 448 449 for (i = 0; i < screenInfo.numScreens; i++) 450 AppleWMSetScreenOrigin(screenInfo.screens[i]->root); 451} 452 453/* 454 * Quartz display mode function list. 455 */ 456static QuartzModeProcsRec xprModeProcs = { 457 xprDisplayInit, 458 xprAddScreen, 459 xprSetupScreen, 460 xprInitInput, 461 QuartzInitCursor, 462 QuartzSuspendXCursor, 463 QuartzResumeXCursor, 464 xprAddPseudoramiXScreens, 465 xprUpdateScreen, 466 xprIsX11Window, 467 xprHideWindows, 468 RootlessFrameForWindow, 469 TopLevelParent, 470 DRICreateSurface, 471 DRIDestroySurface 472}; 473 474/* 475 * QuartzModeBundleInit 476 * Initialize the display mode bundle after loading. 477 */ 478Bool 479QuartzModeBundleInit(void) 480{ 481 quartzProcs = &xprModeProcs; 482 quartzOpenGLBundle = xprOpenGLBundle; 483 return TRUE; 484} 485