quartz.c revision 8223e2f2
1/* 2 * 3 * Quartz-specific support for the Darwin X Server 4 * 5 * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 * 26 * Except as contained in this notice, the name(s) of the above copyright 27 * holders shall not be used in advertising or otherwise to promote the sale, 28 * use or other dealings in this Software without prior written authorization. 29 */ 30 31#include "sanitizedCarbon.h" 32 33#ifdef HAVE_DIX_CONFIG_H 34#include <dix-config.h> 35#endif 36 37#include "quartzCommon.h" 38#include "quartzRandR.h" 39#include "inputstr.h" 40#include "quartz.h" 41#include "darwin.h" 42#include "darwinEvents.h" 43#include "pseudoramiX.h" 44#define _APPLEWM_SERVER_ 45#include "applewmExt.h" 46 47#include "X11Application.h" 48 49#include <X11/extensions/applewmconst.h> 50 51// X headers 52#include "scrnintstr.h" 53#include "windowstr.h" 54#include "colormapst.h" 55#include "globals.h" 56#include "mi.h" 57 58// System headers 59#include <stdlib.h> 60#include <string.h> 61#include <sys/types.h> 62#include <sys/stat.h> 63#include <fcntl.h> 64#include <IOKit/pwr_mgt/IOPMLib.h> 65#include <pthread.h> 66#include <signal.h> 67 68#include <rootlessCommon.h> 69#include <Xplugin.h> 70 71DevPrivateKeyRec quartzScreenKeyRec; 72int aquaMenuBarHeight = 0; 73QuartzModeProcsPtr quartzProcs = NULL; 74const char *quartzOpenGLBundle = NULL; 75 76Bool XQuartzFullscreenDisableHotkeys = TRUE; 77Bool XQuartzOptionSendsAlt = FALSE; 78Bool XQuartzEnableKeyEquivalents = TRUE; 79Bool XQuartzFullscreenVisible = FALSE; 80Bool XQuartzRootlessDefault = TRUE; 81Bool XQuartzIsRootless = TRUE; 82Bool XQuartzServerVisible = FALSE; 83Bool XQuartzFullscreenMenu = FALSE; 84 85int32_t XQuartzShieldingWindowLevel = 0; 86 87/* 88=========================================================================== 89 90 Screen functions 91 92=========================================================================== 93*/ 94 95/* 96 * QuartzAddScreen 97 * Do mode dependent initialization of each screen for Quartz. 98 */ 99Bool QuartzAddScreen( 100 int index, 101 ScreenPtr pScreen) 102{ 103 // allocate space for private per screen Quartz specific storage 104 QuartzScreenPtr displayInfo = calloc(sizeof(QuartzScreenRec), 1); 105 106 // QUARTZ_PRIV(pScreen) = displayInfo; 107 dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo); 108 109 // do Quartz mode specific initialization 110 return quartzProcs->AddScreen(index, pScreen); 111} 112 113 114/* 115 * QuartzSetupScreen 116 * Finalize mode specific setup of each screen. 117 */ 118Bool QuartzSetupScreen( 119 int index, 120 ScreenPtr pScreen) 121{ 122 // do Quartz mode specific setup 123 if (! quartzProcs->SetupScreen(index, pScreen)) 124 return FALSE; 125 126 // setup cursor support 127 if (! quartzProcs->InitCursor(pScreen)) 128 return FALSE; 129 130#if defined(RANDR) 131 if(!QuartzRandRInit(pScreen)) { 132 DEBUG_LOG("Failed to init RandR extension.\n"); 133 return FALSE; 134 } 135#endif 136 137 return TRUE; 138} 139 140 141/* 142 * QuartzInitOutput 143 * Quartz display initialization. 144 */ 145void QuartzInitOutput( 146 int argc, 147 char **argv ) 148{ 149 /* For XQuartz, we want to just use the default signal handler to work better with CrashTracer */ 150 signal(SIGSEGV, SIG_DFL); 151 signal(SIGILL, SIG_DFL); 152#ifdef SIGEMT 153 signal(SIGEMT, SIG_DFL); 154#endif 155 signal(SIGFPE, SIG_DFL); 156#ifdef SIGBUS 157 signal(SIGBUS, SIG_DFL); 158#endif 159#ifdef SIGSYS 160 signal(SIGSYS, SIG_DFL); 161#endif 162#ifdef SIGXCPU 163 signal(SIGXCPU, SIG_DFL); 164#endif 165#ifdef SIGXFSZ 166 signal(SIGXFSZ, SIG_DFL); 167#endif 168 169 if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler, 170 QuartzWakeupHandler, 171 NULL)) 172 { 173 FatalError("Could not register block and wakeup handlers."); 174 } 175 176 if (!dixRegisterPrivateKey(&quartzScreenKeyRec, PRIVATE_SCREEN, 0)) 177 FatalError("Failed to alloc quartz screen private.\n"); 178 179 // Do display mode specific initialization 180 quartzProcs->DisplayInit(); 181} 182 183 184/* 185 * QuartzInitInput 186 * Inform the main thread the X server is ready to handle events. 187 */ 188void QuartzInitInput( 189 int argc, 190 char **argv ) 191{ 192 X11ApplicationSetCanQuit(0); 193 X11ApplicationServerReady(); 194 // Do final display mode specific initialization before handling events 195 if (quartzProcs->InitInput) 196 quartzProcs->InitInput(argc, argv); 197} 198 199 200void QuartzUpdateScreens(void) { 201 ScreenPtr pScreen; 202 WindowPtr pRoot; 203 int x, y, width, height, sx, sy; 204 xEvent e; 205 BoxRec bounds; 206 207 if (noPseudoramiXExtension || screenInfo.numScreens != 1) 208 { 209 /* FIXME: if not using Xinerama, we have multiple screens, and 210 to do this properly may need to add or remove screens. Which 211 isn't possible. So don't do anything. Another reason why 212 we default to running with Xinerama. */ 213 214 return; 215 } 216 217 pScreen = screenInfo.screens[0]; 218 219 PseudoramiXResetScreens(); 220 quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height, pScreen); 221 222 pScreen->x = x; 223 pScreen->y = y; 224 pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width); 225 pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height); 226 pScreen->width = width; 227 pScreen->height = height; 228 229 DarwinAdjustScreenOrigins(&screenInfo); 230 231 /* DarwinAdjustScreenOrigins or UpdateScreen may change pScreen->x/y, 232 * so use it rather than x/y 233 */ 234 sx = pScreen->x + darwinMainScreenX; 235 sy = pScreen->y + darwinMainScreenY; 236 237 /* Adjust the root window. */ 238 pRoot = pScreen->root; 239 AppleWMSetScreenOrigin(pRoot); 240 pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL); 241 242 miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); 243 244 /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration 245 * http://xquartz.macosforge.org/trac/ticket/346 246 */ 247 bounds.x1 = 0; 248 bounds.x2 = width; 249 bounds.y1 = 0; 250 bounds.y2 = height; 251 pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds); 252 inputInfo.pointer->spriteInfo->sprite->physLimits = bounds; 253 inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds; 254 255 DEBUG_LOG("Root Window: %dx%d @ (%d, %d) darwinMainScreen (%d, %d) xy (%d, %d) dixScreenOrigins (%d, %d)\n", width, height, x - sx, y - sy, darwinMainScreenX, darwinMainScreenY, x, y, pScreen->x, pScreen->y); 256 257 /* Send an event for the root reconfigure */ 258 e.u.u.type = ConfigureNotify; 259 e.u.configureNotify.window = pRoot->drawable.id; 260 e.u.configureNotify.aboveSibling = None; 261 e.u.configureNotify.x = x - sx; 262 e.u.configureNotify.y = y - sy; 263 e.u.configureNotify.width = width; 264 e.u.configureNotify.height = height; 265 e.u.configureNotify.borderWidth = wBorderWidth(pRoot); 266 e.u.configureNotify.override = pRoot->overrideRedirect; 267 DeliverEvents(pRoot, &e, 1, NullWindow); 268 269 quartzProcs->UpdateScreen(pScreen); 270 271 /* Tell RandR about the new size, so new connections get the correct info */ 272 RRScreenSizeNotify(pScreen); 273} 274 275static void pokeActivityCallback(CFRunLoopTimerRef timer, void *info) { 276 UpdateSystemActivity(OverallAct); 277} 278 279static void QuartzScreenSaver(int state) { 280 static CFRunLoopTimerRef pokeActivityTimer = NULL; 281 static CFRunLoopTimerContext pokeActivityContext = { 0, NULL, NULL, NULL, NULL }; 282 static pthread_mutex_t pokeActivityMutex = PTHREAD_MUTEX_INITIALIZER; 283 284 pthread_mutex_lock(&pokeActivityMutex); 285 286 if(state) { 287 if(pokeActivityTimer == NULL) 288 goto QuartzScreenSaverEnd; 289 290 CFRunLoopTimerInvalidate(pokeActivityTimer); 291 CFRelease(pokeActivityTimer); 292 pokeActivityTimer = NULL; 293 } else { 294 if(pokeActivityTimer != NULL) 295 goto QuartzScreenSaverEnd; 296 297 pokeActivityTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 30, 0, 0, pokeActivityCallback, &pokeActivityContext); 298 if(pokeActivityTimer == NULL) { 299 ErrorF("Unable to create pokeActivityTimer.\n"); 300 goto QuartzScreenSaverEnd; 301 } 302 303 CFRunLoopAddTimer(CFRunLoopGetMain(), pokeActivityTimer, kCFRunLoopCommonModes); 304 } 305QuartzScreenSaverEnd: 306 pthread_mutex_unlock(&pokeActivityMutex); 307} 308 309void QuartzShowFullscreen(int state) { 310 int i; 311 312 DEBUG_LOG("QuartzShowFullscreen: state=%d\n", state); 313 314 if(XQuartzIsRootless) { 315 ErrorF("QuartzShowFullscreen called while in rootless mode.\n"); 316 return; 317 } 318 319 QuartzScreenSaver(!state); 320 321 if(XQuartzFullscreenVisible == state) 322 return; 323 324 XQuartzFullscreenVisible = state; 325 326 xp_disable_update (); 327 328 if (!XQuartzFullscreenVisible) 329 RootlessHideAllWindows(); 330 331 RootlessUpdateRooted(XQuartzFullscreenVisible); 332 333 if (XQuartzFullscreenVisible) { 334 RootlessShowAllWindows (); 335 for (i=0; i < screenInfo.numScreens; i++) { 336 ScreenPtr pScreen = screenInfo.screens[i]; 337 RootlessRepositionWindows(pScreen); 338 // JH: I don't think this is necessary, but keeping it here as a reminder 339 //RootlessUpdateScreenPixmap(pScreen); 340 } 341 } 342 343 /* Somehow the menubar manages to interfere with our event stream 344 * in fullscreen mode, even though it's not visible. 345 */ 346 X11ApplicationShowHideMenubar(!XQuartzFullscreenVisible); 347 348 xp_reenable_update (); 349 350 if (XQuartzFullscreenDisableHotkeys) 351 xp_disable_hot_keys(XQuartzFullscreenVisible); 352} 353 354void QuartzSetRootless(Bool state) { 355 DEBUG_LOG("QuartzSetRootless state=%d\n", state); 356 357 if(XQuartzIsRootless == state) 358 return; 359 360 if(state) 361 QuartzShowFullscreen(FALSE); 362 363 XQuartzIsRootless = state; 364 365 xp_disable_update(); 366 367 /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */ 368 QuartzUpdateScreens(); 369 370 if(XQuartzIsRootless) { 371 RootlessShowAllWindows(); 372 } else { 373 RootlessHideAllWindows(); 374 } 375 376 X11ApplicationShowHideMenubar(TRUE); 377 378 xp_reenable_update(); 379 380 xp_disable_hot_keys(FALSE); 381} 382 383/* 384 * QuartzShow 385 * Show the X server on screen. Does nothing if already shown. 386 * Calls mode specific screen resume to restore the X clip regions 387 * (if needed) and the X server cursor state. 388 */ 389void QuartzShow(void) { 390 int i; 391 392 if (XQuartzServerVisible) 393 return; 394 395 XQuartzServerVisible = TRUE; 396 for (i = 0; i < screenInfo.numScreens; i++) { 397 if (screenInfo.screens[i]) { 398 quartzProcs->ResumeScreen(screenInfo.screens[i]); 399 } 400 } 401 402 if (!XQuartzIsRootless) 403 QuartzShowFullscreen(TRUE); 404} 405 406 407/* 408 * QuartzHide 409 * Remove the X server display from the screen. Does nothing if already 410 * hidden. Calls mode specific screen suspend to set X clip regions to 411 * prevent drawing (if needed) and restore the Aqua cursor. 412 */ 413void QuartzHide(void) 414{ 415 int i; 416 417 if (XQuartzServerVisible) { 418 for (i = 0; i < screenInfo.numScreens; i++) { 419 if (screenInfo.screens[i]) { 420 quartzProcs->SuspendScreen(screenInfo.screens[i]); 421 } 422 } 423 } 424 425 if(!XQuartzIsRootless) 426 QuartzShowFullscreen(FALSE); 427 XQuartzServerVisible = FALSE; 428} 429 430 431/* 432 * QuartzSetRootClip 433 * Enable or disable rendering to the X screen. 434 */ 435void QuartzSetRootClip( 436 BOOL enable) 437{ 438 int i; 439 440 if (!XQuartzServerVisible) 441 return; 442 443 for (i = 0; i < screenInfo.numScreens; i++) { 444 if (screenInfo.screens[i]) { 445 xf86SetRootClip(screenInfo.screens[i], enable); 446 } 447 } 448} 449 450/* 451 * QuartzSpaceChanged 452 * Unmap offscreen windows, map onscreen windows 453 */ 454void QuartzSpaceChanged(uint32_t space_id) { 455 /* Do something special here, so we don't depend on quartz-wm for spaces to work... */ 456 DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id); 457} 458 459/* 460 * QuartzCopyDisplayIDs 461 * Associate an X11 screen with one or more CoreGraphics display IDs by copying 462 * the list into a private array. Free the previously copied array, if present. 463 */ 464void QuartzCopyDisplayIDs(ScreenPtr pScreen, 465 int displayCount, CGDirectDisplayID *displayIDs) { 466 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 467 int size = displayCount * sizeof(CGDirectDisplayID); 468 469 free(pQuartzScreen->displayIDs); 470 pQuartzScreen->displayIDs = malloc(size); 471 memcpy(pQuartzScreen->displayIDs, displayIDs, size); 472 pQuartzScreen->displayCount = displayCount; 473} 474 475void NSBeep(void); 476void DDXRingBell( 477 int volume, // volume is % of max 478 int pitch, // pitch is Hz 479 int duration) // duration is milliseconds 480{ 481 if (volume) 482 NSBeep(); 483} 484