3 * Quartz-specific support for the Darwin X Server
5 * Copyright (c) 2002-2012 Apple Inc. All rights reserved.
6 * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the sale,
29 * use or other dealings in this Software without prior written authorization.
32 #include "sanitizedCarbon.h"
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
38 #include "quartzCommon.h"
39 #include "quartzRandR.h"
43 #include "darwinEvents.h"
44 #include "pseudoramiX.h"
45 #include "extension.h"
46 #include "glx_extinit.h"
47 #define _APPLEWM_SERVER_
48 #include "applewmExt.h"
50 #include "X11Application.h"
52 #include <X11/extensions/applewmconst.h>
55 #include "scrnintstr.h"
56 #include "windowstr.h"
57 #include "colormapst.h"
64 #include <sys/types.h>
67 #include <IOKit/pwr_mgt/IOPMLib.h>
68 #include <libkern/OSAtomic.h>
71 #include <rootlessCommon.h>
74 /* Work around a bug on Leopard's headers */
75 #if defined (__LP64__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 && MAC_OS_X_VERSION_MAX_ALLOWED < 1060
76 extern OSErr
UpdateSystemActivity(UInt8 activity
);
80 DevPrivateKeyRec quartzScreenKeyRec
;
81 int aquaMenuBarHeight
= 0;
82 QuartzModeProcsPtr quartzProcs
= NULL
;
83 const char *quartzOpenGLBundle
= NULL
;
85 Bool XQuartzFullscreenDisableHotkeys
= TRUE
;
86 Bool XQuartzOptionSendsAlt
= FALSE
;
87 Bool XQuartzEnableKeyEquivalents
= TRUE
;
88 Bool XQuartzFullscreenVisible
= FALSE
;
89 Bool XQuartzRootlessDefault
= TRUE
;
90 Bool XQuartzIsRootless
= TRUE
;
91 Bool XQuartzServerVisible
= FALSE
;
92 Bool XQuartzFullscreenMenu
= FALSE
;
94 int32_t XQuartzShieldingWindowLevel
= 0;
97 ===========================================================================
101 ===========================================================================
106 * Do mode dependent initialization of each screen for Quartz.
109 QuartzAddScreen(int index
,
112 // The clang static analyzer thinks we leak displayInfo here
113 #ifndef __clang_analyzer__
114 // allocate space for private per screen Quartz specific storage
115 QuartzScreenPtr displayInfo
= calloc(sizeof(QuartzScreenRec
), 1);
117 // QUARTZ_PRIV(pScreen) = displayInfo;
118 dixSetPrivate(&pScreen
->devPrivates
, quartzScreenKey
, displayInfo
);
119 #endif /* __clang_analyzer__ */
121 // do Quartz mode specific initialization
122 return quartzProcs
->AddScreen(index
, pScreen
);
127 * Finalize mode specific setup of each screen.
130 QuartzSetupScreen(int index
,
133 // do Quartz mode specific setup
134 if (!quartzProcs
->SetupScreen(index
, pScreen
))
137 // setup cursor support
138 if (!quartzProcs
->InitCursor(pScreen
))
142 if (!QuartzRandRInit(pScreen
)) {
143 DEBUG_LOG("Failed to init RandR extension.\n");
151 static const ExtensionModule quartzExtensions
[] = {
152 /* PseudoramiX needs to be done before RandR, so
153 * it is in miinitext.c until it can be reordered.
154 * { PseudoramiXExtensionInit, "PseudoramiX", &noPseudoramiXExtension },
157 {GlxExtensionInit
, "GLX", &noGlxExtension
},
162 * QuartzExtensionInit
163 * Initialises XQuartz-specific extensions.
165 static void QuartzExtensionInit(void)
169 for (i
= 0; i
< ARRAY_SIZE(quartzExtensions
); i
++)
170 LoadExtension(&quartzExtensions
[i
], TRUE
);
175 * Quartz display initialization.
178 QuartzInitOutput(int argc
,
181 /* For XQuartz, we want to just use the default signal handler to work better with CrashTracer */
182 signal(SIGSEGV
, SIG_DFL
);
183 signal(SIGILL
, SIG_DFL
);
185 signal(SIGEMT
, SIG_DFL
);
187 signal(SIGFPE
, SIG_DFL
);
189 signal(SIGBUS
, SIG_DFL
);
192 signal(SIGSYS
, SIG_DFL
);
195 signal(SIGXCPU
, SIG_DFL
);
198 signal(SIGXFSZ
, SIG_DFL
);
201 if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler
,
204 FatalError("Could not register block and wakeup handlers.");
207 if (!dixRegisterPrivateKey(&quartzScreenKeyRec
, PRIVATE_SCREEN
, 0))
208 FatalError("Failed to alloc quartz screen private.\n");
210 // Do display mode specific initialization
211 quartzProcs
->DisplayInit();
213 QuartzExtensionInit();
218 * Inform the main thread the X server is ready to handle events.
221 QuartzInitInput(int argc
,
224 X11ApplicationSetCanQuit(0);
225 X11ApplicationServerReady();
226 // Do final display mode specific initialization before handling events
227 if (quartzProcs
->InitInput
)
228 quartzProcs
->InitInput(argc
, argv
);
232 QuartzUpdateScreens(void)
236 int x
, y
, width
, height
, sx
, sy
;
240 if (noPseudoramiXExtension
|| screenInfo
.numScreens
!= 1) {
241 /* FIXME: if not using Xinerama, we have multiple screens, and
242 to do this properly may need to add or remove screens. Which
243 isn't possible. So don't do anything. Another reason why
244 we default to running with Xinerama. */
249 pScreen
= screenInfo
.screens
[0];
251 PseudoramiXResetScreens();
252 quartzProcs
->AddPseudoramiXScreens(&x
, &y
, &width
, &height
, pScreen
);
256 pScreen
->mmWidth
= pScreen
->mmWidth
* ((double)width
/ pScreen
->width
);
257 pScreen
->mmHeight
= pScreen
->mmHeight
* ((double)height
/ pScreen
->height
);
258 pScreen
->width
= width
;
259 pScreen
->height
= height
;
261 DarwinAdjustScreenOrigins(&screenInfo
);
263 /* DarwinAdjustScreenOrigins or UpdateScreen may change pScreen->x/y,
264 * so use it rather than x/y
266 sx
= pScreen
->x
+ darwinMainScreenX
;
267 sy
= pScreen
->y
+ darwinMainScreenY
;
269 /* Adjust the root window. */
270 pRoot
= pScreen
->root
;
271 AppleWMSetScreenOrigin(pRoot
);
272 pScreen
->ResizeWindow(pRoot
, x
- sx
, y
- sy
, width
, height
, NULL
);
274 /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration
275 * http://xquartz.macosforge.org/trac/ticket/346
281 pScreen
->ConstrainCursor(inputInfo
.pointer
, pScreen
, &bounds
);
282 inputInfo
.pointer
->spriteInfo
->sprite
->physLimits
= bounds
;
283 inputInfo
.pointer
->spriteInfo
->sprite
->hotLimits
= bounds
;
286 "Root Window: %dx%d @ (%d, %d) darwinMainScreen (%d, %d) xy (%d, %d) dixScreenOrigins (%d, %d)\n",
287 width
, height
, x
- sx
, y
- sy
, darwinMainScreenX
, darwinMainScreenY
,
289 pScreen
->x
, pScreen
->y
);
291 /* Send an event for the root reconfigure */
292 e
.u
.u
.type
= ConfigureNotify
;
293 e
.u
.configureNotify
.window
= pRoot
->drawable
.id
;
294 e
.u
.configureNotify
.aboveSibling
= None
;
295 e
.u
.configureNotify
.x
= x
- sx
;
296 e
.u
.configureNotify
.y
= y
- sy
;
297 e
.u
.configureNotify
.width
= width
;
298 e
.u
.configureNotify
.height
= height
;
299 e
.u
.configureNotify
.borderWidth
= wBorderWidth(pRoot
);
300 e
.u
.configureNotify
.override
= pRoot
->overrideRedirect
;
301 DeliverEvents(pRoot
, &e
, 1, NullWindow
);
303 quartzProcs
->UpdateScreen(pScreen
);
305 /* miPaintWindow needs to be called after RootlessUpdateScreenPixmap (from xprUpdateScreen) */
306 miPaintWindow(pRoot
, &pRoot
->borderClip
, PW_BACKGROUND
);
308 /* Tell RandR about the new size, so new connections get the correct info */
309 RRScreenSizeNotify(pScreen
);
313 pokeActivityCallback(CFRunLoopTimerRef timer
, void *info
)
315 UpdateSystemActivity(OverallAct
);
319 QuartzScreenSaver(int state
)
321 static CFRunLoopTimerRef pokeActivityTimer
= NULL
;
322 static CFRunLoopTimerContext pokeActivityContext
=
323 { 0, NULL
, NULL
, NULL
, NULL
};
324 static OSSpinLock pokeActivitySpinLock
= OS_SPINLOCK_INIT
;
326 OSSpinLockLock(&pokeActivitySpinLock
);
329 if (pokeActivityTimer
== NULL
)
330 goto QuartzScreenSaverEnd
;
332 CFRunLoopTimerInvalidate(pokeActivityTimer
);
333 CFRelease(pokeActivityTimer
);
334 pokeActivityTimer
= NULL
;
337 if (pokeActivityTimer
!= NULL
)
338 goto QuartzScreenSaverEnd
;
340 pokeActivityTimer
= CFRunLoopTimerCreate(NULL
,
341 CFAbsoluteTimeGetCurrent(),
343 pokeActivityCallback
,
344 &pokeActivityContext
);
345 if (pokeActivityTimer
== NULL
) {
346 ErrorF("Unable to create pokeActivityTimer.\n");
347 goto QuartzScreenSaverEnd
;
351 CFRunLoopGetMain(), pokeActivityTimer
, kCFRunLoopCommonModes
);
353 QuartzScreenSaverEnd
:
354 OSSpinLockUnlock(&pokeActivitySpinLock
);
358 QuartzShowFullscreen(int state
)
362 DEBUG_LOG("QuartzShowFullscreen: state=%d\n", state
);
364 if (XQuartzIsRootless
) {
365 ErrorF("QuartzShowFullscreen called while in rootless mode.\n");
369 QuartzScreenSaver(!state
);
371 if (XQuartzFullscreenVisible
== state
)
374 XQuartzFullscreenVisible
= state
;
378 if (!XQuartzFullscreenVisible
)
379 RootlessHideAllWindows();
381 RootlessUpdateRooted(XQuartzFullscreenVisible
);
383 if (XQuartzFullscreenVisible
) {
384 RootlessShowAllWindows();
385 for (i
= 0; i
< screenInfo
.numScreens
; i
++) {
386 ScreenPtr pScreen
= screenInfo
.screens
[i
];
387 RootlessRepositionWindows(pScreen
);
388 // JH: I don't think this is necessary, but keeping it here as a reminder
389 //RootlessUpdateScreenPixmap(pScreen);
393 /* Somehow the menubar manages to interfere with our event stream
394 * in fullscreen mode, even though it's not visible.
396 X11ApplicationShowHideMenubar(!XQuartzFullscreenVisible
);
398 xp_reenable_update();
400 if (XQuartzFullscreenDisableHotkeys
)
401 xp_disable_hot_keys(XQuartzFullscreenVisible
);
405 QuartzSetRootless(Bool state
)
407 DEBUG_LOG("QuartzSetRootless state=%d\n", state
);
409 if (XQuartzIsRootless
== state
)
413 QuartzShowFullscreen(FALSE
);
415 XQuartzIsRootless
= state
;
419 /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */
420 QuartzUpdateScreens();
422 if (XQuartzIsRootless
) {
423 RootlessShowAllWindows();
426 RootlessHideAllWindows();
429 X11ApplicationShowHideMenubar(TRUE
);
431 xp_reenable_update();
433 xp_disable_hot_keys(FALSE
);
438 * Show the X server on screen. Does nothing if already shown.
439 * Calls mode specific screen resume to restore the X clip regions
440 * (if needed) and the X server cursor state.
447 if (XQuartzServerVisible
)
450 XQuartzServerVisible
= TRUE
;
451 for (i
= 0; i
< screenInfo
.numScreens
; i
++) {
452 if (screenInfo
.screens
[i
]) {
453 quartzProcs
->ResumeScreen(screenInfo
.screens
[i
]);
457 if (!XQuartzIsRootless
)
458 QuartzShowFullscreen(TRUE
);
463 * Remove the X server display from the screen. Does nothing if already
464 * hidden. Calls mode specific screen suspend to set X clip regions to
465 * prevent drawing (if needed) and restore the Aqua cursor.
472 if (XQuartzServerVisible
) {
473 for (i
= 0; i
< screenInfo
.numScreens
; i
++) {
474 if (screenInfo
.screens
[i
]) {
475 quartzProcs
->SuspendScreen(screenInfo
.screens
[i
]);
480 if (!XQuartzIsRootless
)
481 QuartzShowFullscreen(FALSE
);
482 XQuartzServerVisible
= FALSE
;
487 * Enable or disable rendering to the X screen.
490 QuartzSetRootClip(BOOL enable
)
494 if (!XQuartzServerVisible
)
497 for (i
= 0; i
< screenInfo
.numScreens
; i
++) {
498 if (screenInfo
.screens
[i
]) {
499 SetRootClip(screenInfo
.screens
[i
], enable
);
506 * Unmap offscreen windows, map onscreen windows
509 QuartzSpaceChanged(uint32_t space_id
)
511 /* Do something special here, so we don't depend on quartz-wm for spaces to work... */
512 DEBUG_LOG("Space Changed (%u) ... do something interesting...\n",
517 * QuartzCopyDisplayIDs
518 * Associate an X11 screen with one or more CoreGraphics display IDs by copying
519 * the list into a private array. Free the previously copied array, if present.
522 QuartzCopyDisplayIDs(ScreenPtr pScreen
,
523 int displayCount
, CGDirectDisplayID
*displayIDs
)
525 QuartzScreenPtr pQuartzScreen
= QUARTZ_PRIV(pScreen
);
527 free(pQuartzScreen
->displayIDs
);
529 size_t size
= displayCount
* sizeof(CGDirectDisplayID
);
530 pQuartzScreen
->displayIDs
= malloc(size
);
531 memcpy(pQuartzScreen
->displayIDs
, displayIDs
, size
);
534 pQuartzScreen
->displayIDs
= NULL
;
536 pQuartzScreen
->displayCount
= displayCount
;
542 DDXRingBell(int volume
, // volume is % of max
543 int pitch
, // pitch is Hz
544 int duration
) // duration is milliseconds