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