1706f2543Smrg/* 2706f2543Smrg * 3706f2543Smrg * Quartz-specific support for the Darwin X Server 4706f2543Smrg * 5706f2543Smrg * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons. 6706f2543Smrg * All Rights Reserved. 7706f2543Smrg * 8706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9706f2543Smrg * copy of this software and associated documentation files (the "Software"), 10706f2543Smrg * to deal in the Software without restriction, including without limitation 11706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 13706f2543Smrg * Software is furnished to do so, subject to the following conditions: 14706f2543Smrg * 15706f2543Smrg * The above copyright notice and this permission notice shall be included in 16706f2543Smrg * all copies or substantial portions of the Software. 17706f2543Smrg * 18706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 22706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24706f2543Smrg * DEALINGS IN THE SOFTWARE. 25706f2543Smrg * 26706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright 27706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale, 28706f2543Smrg * use or other dealings in this Software without prior written authorization. 29706f2543Smrg */ 30706f2543Smrg 31706f2543Smrg#include "sanitizedCarbon.h" 32706f2543Smrg 33706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 34706f2543Smrg#include <dix-config.h> 35706f2543Smrg#endif 36706f2543Smrg 37706f2543Smrg#include "quartzCommon.h" 38706f2543Smrg#include "quartzRandR.h" 39706f2543Smrg#include "inputstr.h" 40706f2543Smrg#include "quartz.h" 41706f2543Smrg#include "darwin.h" 42706f2543Smrg#include "darwinEvents.h" 43706f2543Smrg#include "pseudoramiX.h" 44706f2543Smrg#define _APPLEWM_SERVER_ 45706f2543Smrg#include "applewmExt.h" 46706f2543Smrg 47706f2543Smrg#include "X11Application.h" 48706f2543Smrg 49706f2543Smrg#include <X11/extensions/applewmconst.h> 50706f2543Smrg 51706f2543Smrg// X headers 52706f2543Smrg#include "scrnintstr.h" 53706f2543Smrg#include "windowstr.h" 54706f2543Smrg#include "colormapst.h" 55706f2543Smrg#include "globals.h" 56706f2543Smrg#include "mi.h" 57706f2543Smrg 58706f2543Smrg// System headers 59706f2543Smrg#include <stdlib.h> 60706f2543Smrg#include <string.h> 61706f2543Smrg#include <sys/types.h> 62706f2543Smrg#include <sys/stat.h> 63706f2543Smrg#include <fcntl.h> 64706f2543Smrg#include <IOKit/pwr_mgt/IOPMLib.h> 65706f2543Smrg#include <pthread.h> 66706f2543Smrg#include <signal.h> 67706f2543Smrg 68706f2543Smrg#include <rootlessCommon.h> 69706f2543Smrg#include <Xplugin.h> 70706f2543Smrg 71706f2543SmrgDevPrivateKeyRec quartzScreenKeyRec; 72706f2543Smrgint aquaMenuBarHeight = 0; 73706f2543SmrgQuartzModeProcsPtr quartzProcs = NULL; 74706f2543Smrgconst char *quartzOpenGLBundle = NULL; 75706f2543Smrg 76706f2543SmrgBool XQuartzFullscreenDisableHotkeys = TRUE; 77706f2543SmrgBool XQuartzOptionSendsAlt = FALSE; 78706f2543SmrgBool XQuartzEnableKeyEquivalents = TRUE; 79706f2543SmrgBool XQuartzFullscreenVisible = FALSE; 80706f2543SmrgBool XQuartzRootlessDefault = TRUE; 81706f2543SmrgBool XQuartzIsRootless = TRUE; 82706f2543SmrgBool XQuartzServerVisible = FALSE; 83706f2543SmrgBool XQuartzFullscreenMenu = FALSE; 84706f2543Smrg 85706f2543Smrgint32_t XQuartzShieldingWindowLevel = 0; 86706f2543Smrg 87706f2543Smrg/* 88706f2543Smrg=========================================================================== 89706f2543Smrg 90706f2543Smrg Screen functions 91706f2543Smrg 92706f2543Smrg=========================================================================== 93706f2543Smrg*/ 94706f2543Smrg 95706f2543Smrg/* 96706f2543Smrg * QuartzAddScreen 97706f2543Smrg * Do mode dependent initialization of each screen for Quartz. 98706f2543Smrg */ 99706f2543SmrgBool QuartzAddScreen( 100706f2543Smrg int index, 101706f2543Smrg ScreenPtr pScreen) 102706f2543Smrg{ 103706f2543Smrg // allocate space for private per screen Quartz specific storage 104706f2543Smrg QuartzScreenPtr displayInfo = calloc(sizeof(QuartzScreenRec), 1); 105706f2543Smrg 106706f2543Smrg // QUARTZ_PRIV(pScreen) = displayInfo; 107706f2543Smrg dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo); 108706f2543Smrg 109706f2543Smrg // do Quartz mode specific initialization 110706f2543Smrg return quartzProcs->AddScreen(index, pScreen); 111706f2543Smrg} 112706f2543Smrg 113706f2543Smrg 114706f2543Smrg/* 115706f2543Smrg * QuartzSetupScreen 116706f2543Smrg * Finalize mode specific setup of each screen. 117706f2543Smrg */ 118706f2543SmrgBool QuartzSetupScreen( 119706f2543Smrg int index, 120706f2543Smrg ScreenPtr pScreen) 121706f2543Smrg{ 122706f2543Smrg // do Quartz mode specific setup 123706f2543Smrg if (! quartzProcs->SetupScreen(index, pScreen)) 124706f2543Smrg return FALSE; 125706f2543Smrg 126706f2543Smrg // setup cursor support 127706f2543Smrg if (! quartzProcs->InitCursor(pScreen)) 128706f2543Smrg return FALSE; 129706f2543Smrg 130706f2543Smrg#if defined(RANDR) 131706f2543Smrg if(!QuartzRandRInit(pScreen)) { 132706f2543Smrg DEBUG_LOG("Failed to init RandR extension.\n"); 133706f2543Smrg return FALSE; 134706f2543Smrg } 135706f2543Smrg#endif 136706f2543Smrg 137706f2543Smrg return TRUE; 138706f2543Smrg} 139706f2543Smrg 140706f2543Smrg 141706f2543Smrg/* 142706f2543Smrg * QuartzInitOutput 143706f2543Smrg * Quartz display initialization. 144706f2543Smrg */ 145706f2543Smrgvoid QuartzInitOutput( 146706f2543Smrg int argc, 147706f2543Smrg char **argv ) 148706f2543Smrg{ 149706f2543Smrg /* For XQuartz, we want to just use the default signal handler to work better with CrashTracer */ 150706f2543Smrg signal(SIGSEGV, SIG_DFL); 151706f2543Smrg signal(SIGILL, SIG_DFL); 152706f2543Smrg#ifdef SIGEMT 153706f2543Smrg signal(SIGEMT, SIG_DFL); 154706f2543Smrg#endif 155706f2543Smrg signal(SIGFPE, SIG_DFL); 156706f2543Smrg#ifdef SIGBUS 157706f2543Smrg signal(SIGBUS, SIG_DFL); 158706f2543Smrg#endif 159706f2543Smrg#ifdef SIGSYS 160706f2543Smrg signal(SIGSYS, SIG_DFL); 161706f2543Smrg#endif 162706f2543Smrg#ifdef SIGXCPU 163706f2543Smrg signal(SIGXCPU, SIG_DFL); 164706f2543Smrg#endif 165706f2543Smrg#ifdef SIGXFSZ 166706f2543Smrg signal(SIGXFSZ, SIG_DFL); 167706f2543Smrg#endif 168706f2543Smrg 169706f2543Smrg if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler, 170706f2543Smrg QuartzWakeupHandler, 171706f2543Smrg NULL)) 172706f2543Smrg { 173706f2543Smrg FatalError("Could not register block and wakeup handlers."); 174706f2543Smrg } 175706f2543Smrg 176706f2543Smrg if (!dixRegisterPrivateKey(&quartzScreenKeyRec, PRIVATE_SCREEN, 0)) 177706f2543Smrg FatalError("Failed to alloc quartz screen private.\n"); 178706f2543Smrg 179706f2543Smrg // Do display mode specific initialization 180706f2543Smrg quartzProcs->DisplayInit(); 181706f2543Smrg} 182706f2543Smrg 183706f2543Smrg 184706f2543Smrg/* 185706f2543Smrg * QuartzInitInput 186706f2543Smrg * Inform the main thread the X server is ready to handle events. 187706f2543Smrg */ 188706f2543Smrgvoid QuartzInitInput( 189706f2543Smrg int argc, 190706f2543Smrg char **argv ) 191706f2543Smrg{ 192706f2543Smrg X11ApplicationSetCanQuit(0); 193706f2543Smrg X11ApplicationServerReady(); 194706f2543Smrg // Do final display mode specific initialization before handling events 195706f2543Smrg if (quartzProcs->InitInput) 196706f2543Smrg quartzProcs->InitInput(argc, argv); 197706f2543Smrg} 198706f2543Smrg 199706f2543Smrg 200706f2543Smrgvoid QuartzUpdateScreens(void) { 201706f2543Smrg ScreenPtr pScreen; 202706f2543Smrg WindowPtr pRoot; 203706f2543Smrg int x, y, width, height, sx, sy; 204706f2543Smrg xEvent e; 205706f2543Smrg BoxRec bounds; 206706f2543Smrg 207706f2543Smrg if (noPseudoramiXExtension || screenInfo.numScreens != 1) 208706f2543Smrg { 209706f2543Smrg /* FIXME: if not using Xinerama, we have multiple screens, and 210706f2543Smrg to do this properly may need to add or remove screens. Which 211706f2543Smrg isn't possible. So don't do anything. Another reason why 212706f2543Smrg we default to running with Xinerama. */ 213706f2543Smrg 214706f2543Smrg return; 215706f2543Smrg } 216706f2543Smrg 217706f2543Smrg pScreen = screenInfo.screens[0]; 218706f2543Smrg 219706f2543Smrg PseudoramiXResetScreens(); 220706f2543Smrg quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height, pScreen); 221706f2543Smrg 222706f2543Smrg pScreen->x = x; 223706f2543Smrg pScreen->y = y; 224706f2543Smrg pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width); 225706f2543Smrg pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height); 226706f2543Smrg pScreen->width = width; 227706f2543Smrg pScreen->height = height; 228706f2543Smrg 229706f2543Smrg DarwinAdjustScreenOrigins(&screenInfo); 230706f2543Smrg 231706f2543Smrg /* DarwinAdjustScreenOrigins or UpdateScreen may change pScreen->x/y, 232706f2543Smrg * so use it rather than x/y 233706f2543Smrg */ 234706f2543Smrg sx = pScreen->x + darwinMainScreenX; 235706f2543Smrg sy = pScreen->y + darwinMainScreenY; 236706f2543Smrg 237706f2543Smrg /* Adjust the root window. */ 238706f2543Smrg pRoot = pScreen->root; 239706f2543Smrg AppleWMSetScreenOrigin(pRoot); 240706f2543Smrg pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL); 241706f2543Smrg 242706f2543Smrg /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration 243706f2543Smrg * http://xquartz.macosforge.org/trac/ticket/346 244706f2543Smrg */ 245706f2543Smrg bounds.x1 = 0; 246706f2543Smrg bounds.x2 = width; 247706f2543Smrg bounds.y1 = 0; 248706f2543Smrg bounds.y2 = height; 249706f2543Smrg pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds); 250706f2543Smrg inputInfo.pointer->spriteInfo->sprite->physLimits = bounds; 251706f2543Smrg inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds; 252706f2543Smrg 253706f2543Smrg 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); 254706f2543Smrg 255706f2543Smrg /* Send an event for the root reconfigure */ 256706f2543Smrg e.u.u.type = ConfigureNotify; 257706f2543Smrg e.u.configureNotify.window = pRoot->drawable.id; 258706f2543Smrg e.u.configureNotify.aboveSibling = None; 259706f2543Smrg e.u.configureNotify.x = x - sx; 260706f2543Smrg e.u.configureNotify.y = y - sy; 261706f2543Smrg e.u.configureNotify.width = width; 262706f2543Smrg e.u.configureNotify.height = height; 263706f2543Smrg e.u.configureNotify.borderWidth = wBorderWidth(pRoot); 264706f2543Smrg e.u.configureNotify.override = pRoot->overrideRedirect; 265706f2543Smrg DeliverEvents(pRoot, &e, 1, NullWindow); 266706f2543Smrg 267706f2543Smrg quartzProcs->UpdateScreen(pScreen); 268706f2543Smrg 269706f2543Smrg /* miPaintWindow needs to be called after RootlessUpdateScreenPixmap (from xprUpdateScreen) */ 270706f2543Smrg miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); 271706f2543Smrg 272706f2543Smrg /* Tell RandR about the new size, so new connections get the correct info */ 273706f2543Smrg RRScreenSizeNotify(pScreen); 274706f2543Smrg} 275706f2543Smrg 276706f2543Smrgstatic void pokeActivityCallback(CFRunLoopTimerRef timer, void *info) { 277706f2543Smrg UpdateSystemActivity(OverallAct); 278706f2543Smrg} 279706f2543Smrg 280706f2543Smrgstatic void QuartzScreenSaver(int state) { 281706f2543Smrg static CFRunLoopTimerRef pokeActivityTimer = NULL; 282706f2543Smrg static CFRunLoopTimerContext pokeActivityContext = { 0, NULL, NULL, NULL, NULL }; 283706f2543Smrg static pthread_mutex_t pokeActivityMutex = PTHREAD_MUTEX_INITIALIZER; 284706f2543Smrg 285706f2543Smrg pthread_mutex_lock(&pokeActivityMutex); 286706f2543Smrg 287706f2543Smrg if(state) { 288706f2543Smrg if(pokeActivityTimer == NULL) 289706f2543Smrg goto QuartzScreenSaverEnd; 290706f2543Smrg 291706f2543Smrg CFRunLoopTimerInvalidate(pokeActivityTimer); 292706f2543Smrg CFRelease(pokeActivityTimer); 293706f2543Smrg pokeActivityTimer = NULL; 294706f2543Smrg } else { 295706f2543Smrg if(pokeActivityTimer != NULL) 296706f2543Smrg goto QuartzScreenSaverEnd; 297706f2543Smrg 298706f2543Smrg pokeActivityTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 30, 0, 0, pokeActivityCallback, &pokeActivityContext); 299706f2543Smrg if(pokeActivityTimer == NULL) { 300706f2543Smrg ErrorF("Unable to create pokeActivityTimer.\n"); 301706f2543Smrg goto QuartzScreenSaverEnd; 302706f2543Smrg } 303706f2543Smrg 304706f2543Smrg CFRunLoopAddTimer(CFRunLoopGetMain(), pokeActivityTimer, kCFRunLoopCommonModes); 305706f2543Smrg } 306706f2543SmrgQuartzScreenSaverEnd: 307706f2543Smrg pthread_mutex_unlock(&pokeActivityMutex); 308706f2543Smrg} 309706f2543Smrg 310706f2543Smrgvoid QuartzShowFullscreen(int state) { 311706f2543Smrg int i; 312706f2543Smrg 313706f2543Smrg DEBUG_LOG("QuartzShowFullscreen: state=%d\n", state); 314706f2543Smrg 315706f2543Smrg if(XQuartzIsRootless) { 316706f2543Smrg ErrorF("QuartzShowFullscreen called while in rootless mode.\n"); 317706f2543Smrg return; 318706f2543Smrg } 319706f2543Smrg 320706f2543Smrg QuartzScreenSaver(!state); 321706f2543Smrg 322706f2543Smrg if(XQuartzFullscreenVisible == state) 323706f2543Smrg return; 324706f2543Smrg 325706f2543Smrg XQuartzFullscreenVisible = state; 326706f2543Smrg 327706f2543Smrg xp_disable_update (); 328706f2543Smrg 329706f2543Smrg if (!XQuartzFullscreenVisible) 330706f2543Smrg RootlessHideAllWindows(); 331706f2543Smrg 332706f2543Smrg RootlessUpdateRooted(XQuartzFullscreenVisible); 333706f2543Smrg 334706f2543Smrg if (XQuartzFullscreenVisible) { 335706f2543Smrg RootlessShowAllWindows (); 336706f2543Smrg for (i=0; i < screenInfo.numScreens; i++) { 337706f2543Smrg ScreenPtr pScreen = screenInfo.screens[i]; 338706f2543Smrg RootlessRepositionWindows(pScreen); 339706f2543Smrg // JH: I don't think this is necessary, but keeping it here as a reminder 340706f2543Smrg //RootlessUpdateScreenPixmap(pScreen); 341706f2543Smrg } 342706f2543Smrg } 343706f2543Smrg 344706f2543Smrg /* Somehow the menubar manages to interfere with our event stream 345706f2543Smrg * in fullscreen mode, even though it's not visible. 346706f2543Smrg */ 347706f2543Smrg X11ApplicationShowHideMenubar(!XQuartzFullscreenVisible); 348706f2543Smrg 349706f2543Smrg xp_reenable_update (); 350706f2543Smrg 351706f2543Smrg if (XQuartzFullscreenDisableHotkeys) 352706f2543Smrg xp_disable_hot_keys(XQuartzFullscreenVisible); 353706f2543Smrg} 354706f2543Smrg 355706f2543Smrgvoid QuartzSetRootless(Bool state) { 356706f2543Smrg DEBUG_LOG("QuartzSetRootless state=%d\n", state); 357706f2543Smrg 358706f2543Smrg if(XQuartzIsRootless == state) 359706f2543Smrg return; 360706f2543Smrg 361706f2543Smrg if(state) 362706f2543Smrg QuartzShowFullscreen(FALSE); 363706f2543Smrg 364706f2543Smrg XQuartzIsRootless = state; 365706f2543Smrg 366706f2543Smrg xp_disable_update(); 367706f2543Smrg 368706f2543Smrg /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */ 369706f2543Smrg QuartzUpdateScreens(); 370706f2543Smrg 371706f2543Smrg if(XQuartzIsRootless) { 372706f2543Smrg RootlessShowAllWindows(); 373706f2543Smrg } else { 374706f2543Smrg RootlessHideAllWindows(); 375706f2543Smrg } 376706f2543Smrg 377706f2543Smrg X11ApplicationShowHideMenubar(TRUE); 378706f2543Smrg 379706f2543Smrg xp_reenable_update(); 380706f2543Smrg 381706f2543Smrg xp_disable_hot_keys(FALSE); 382706f2543Smrg} 383706f2543Smrg 384706f2543Smrg/* 385706f2543Smrg * QuartzShow 386706f2543Smrg * Show the X server on screen. Does nothing if already shown. 387706f2543Smrg * Calls mode specific screen resume to restore the X clip regions 388706f2543Smrg * (if needed) and the X server cursor state. 389706f2543Smrg */ 390706f2543Smrgvoid QuartzShow(void) { 391706f2543Smrg int i; 392706f2543Smrg 393706f2543Smrg if (XQuartzServerVisible) 394706f2543Smrg return; 395706f2543Smrg 396706f2543Smrg XQuartzServerVisible = TRUE; 397706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) { 398706f2543Smrg if (screenInfo.screens[i]) { 399706f2543Smrg quartzProcs->ResumeScreen(screenInfo.screens[i]); 400706f2543Smrg } 401706f2543Smrg } 402706f2543Smrg 403706f2543Smrg if (!XQuartzIsRootless) 404706f2543Smrg QuartzShowFullscreen(TRUE); 405706f2543Smrg} 406706f2543Smrg 407706f2543Smrg 408706f2543Smrg/* 409706f2543Smrg * QuartzHide 410706f2543Smrg * Remove the X server display from the screen. Does nothing if already 411706f2543Smrg * hidden. Calls mode specific screen suspend to set X clip regions to 412706f2543Smrg * prevent drawing (if needed) and restore the Aqua cursor. 413706f2543Smrg */ 414706f2543Smrgvoid QuartzHide(void) 415706f2543Smrg{ 416706f2543Smrg int i; 417706f2543Smrg 418706f2543Smrg if (XQuartzServerVisible) { 419706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) { 420706f2543Smrg if (screenInfo.screens[i]) { 421706f2543Smrg quartzProcs->SuspendScreen(screenInfo.screens[i]); 422706f2543Smrg } 423706f2543Smrg } 424706f2543Smrg } 425706f2543Smrg 426706f2543Smrg if(!XQuartzIsRootless) 427706f2543Smrg QuartzShowFullscreen(FALSE); 428706f2543Smrg XQuartzServerVisible = FALSE; 429706f2543Smrg} 430706f2543Smrg 431706f2543Smrg 432706f2543Smrg/* 433706f2543Smrg * QuartzSetRootClip 434706f2543Smrg * Enable or disable rendering to the X screen. 435706f2543Smrg */ 436706f2543Smrgvoid QuartzSetRootClip( 437706f2543Smrg BOOL enable) 438706f2543Smrg{ 439706f2543Smrg int i; 440706f2543Smrg 441706f2543Smrg if (!XQuartzServerVisible) 442706f2543Smrg return; 443706f2543Smrg 444706f2543Smrg for (i = 0; i < screenInfo.numScreens; i++) { 445706f2543Smrg if (screenInfo.screens[i]) { 446706f2543Smrg xf86SetRootClip(screenInfo.screens[i], enable); 447706f2543Smrg } 448706f2543Smrg } 449706f2543Smrg} 450706f2543Smrg 451706f2543Smrg/* 452706f2543Smrg * QuartzSpaceChanged 453706f2543Smrg * Unmap offscreen windows, map onscreen windows 454706f2543Smrg */ 455706f2543Smrgvoid QuartzSpaceChanged(uint32_t space_id) { 456706f2543Smrg /* Do something special here, so we don't depend on quartz-wm for spaces to work... */ 457706f2543Smrg DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id); 458706f2543Smrg} 459706f2543Smrg 460706f2543Smrg/* 461706f2543Smrg * QuartzCopyDisplayIDs 462706f2543Smrg * Associate an X11 screen with one or more CoreGraphics display IDs by copying 463706f2543Smrg * the list into a private array. Free the previously copied array, if present. 464706f2543Smrg */ 465706f2543Smrgvoid QuartzCopyDisplayIDs(ScreenPtr pScreen, 466706f2543Smrg int displayCount, CGDirectDisplayID *displayIDs) { 467706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 468706f2543Smrg 469706f2543Smrg free(pQuartzScreen->displayIDs); 470706f2543Smrg if(displayCount) { 471706f2543Smrg size_t size = displayCount * sizeof(CGDirectDisplayID); 472706f2543Smrg pQuartzScreen->displayIDs = malloc(size); 473706f2543Smrg memcpy(pQuartzScreen->displayIDs, displayIDs, size); 474706f2543Smrg } else { 475706f2543Smrg pQuartzScreen->displayIDs = NULL; 476706f2543Smrg } 477706f2543Smrg pQuartzScreen->displayCount = displayCount; 478706f2543Smrg} 479706f2543Smrg 480706f2543Smrgvoid NSBeep(void); 481706f2543Smrgvoid DDXRingBell( 482706f2543Smrg int volume, // volume is % of max 483706f2543Smrg int pitch, // pitch is Hz 484706f2543Smrg int duration) // duration is milliseconds 485706f2543Smrg{ 486706f2543Smrg if (volume) 487706f2543Smrg NSBeep(); 488706f2543Smrg} 489