quartz.c revision 6747b715
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 66#include <rootlessCommon.h> 67#include <Xplugin.h> 68 69DevPrivateKeyRec quartzScreenKeyRec; 70int aquaMenuBarHeight = 0; 71QuartzModeProcsPtr quartzProcs = NULL; 72const char *quartzOpenGLBundle = NULL; 73 74Bool XQuartzFullscreenDisableHotkeys = TRUE; 75Bool XQuartzOptionSendsAlt = FALSE; 76Bool XQuartzEnableKeyEquivalents = TRUE; 77Bool XQuartzFullscreenVisible = FALSE; 78Bool XQuartzRootlessDefault = TRUE; 79Bool XQuartzIsRootless = TRUE; 80Bool XQuartzServerVisible = FALSE; 81Bool XQuartzFullscreenMenu = FALSE; 82Bool XQuartzUseSysBeep = FALSE; 83 84/* 85=========================================================================== 86 87 Screen functions 88 89=========================================================================== 90*/ 91 92/* 93 * QuartzAddScreen 94 * Do mode dependent initialization of each screen for Quartz. 95 */ 96Bool QuartzAddScreen( 97 int index, 98 ScreenPtr pScreen) 99{ 100 // allocate space for private per screen Quartz specific storage 101 QuartzScreenPtr displayInfo = calloc(sizeof(QuartzScreenRec), 1); 102 103 // QUARTZ_PRIV(pScreen) = displayInfo; 104 dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo); 105 106 // do Quartz mode specific initialization 107 return quartzProcs->AddScreen(index, pScreen); 108} 109 110 111/* 112 * QuartzSetupScreen 113 * Finalize mode specific setup of each screen. 114 */ 115Bool QuartzSetupScreen( 116 int index, 117 ScreenPtr pScreen) 118{ 119 // do Quartz mode specific setup 120 if (! quartzProcs->SetupScreen(index, pScreen)) 121 return FALSE; 122 123 // setup cursor support 124 if (! quartzProcs->InitCursor(pScreen)) 125 return FALSE; 126 127#if defined(RANDR) 128 if(!QuartzRandRInit(pScreen)) { 129 DEBUG_LOG("Failed to init RandR extension.\n"); 130 return FALSE; 131 } 132#endif 133 134 return TRUE; 135} 136 137 138/* 139 * QuartzInitOutput 140 * Quartz display initialization. 141 */ 142void QuartzInitOutput( 143 int argc, 144 char **argv ) 145{ 146 if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler, 147 QuartzWakeupHandler, 148 NULL)) 149 { 150 FatalError("Could not register block and wakeup handlers."); 151 } 152 153 if (!dixRegisterPrivateKey(&quartzScreenKeyRec, PRIVATE_SCREEN, 0)) 154 FatalError("Failed to alloc quartz screen private.\n"); 155 156 // Do display mode specific initialization 157 quartzProcs->DisplayInit(); 158} 159 160 161/* 162 * QuartzInitInput 163 * Inform the main thread the X server is ready to handle events. 164 */ 165void QuartzInitInput( 166 int argc, 167 char **argv ) 168{ 169 X11ApplicationSetCanQuit(0); 170 X11ApplicationServerReady(); 171 // Do final display mode specific initialization before handling events 172 if (quartzProcs->InitInput) 173 quartzProcs->InitInput(argc, argv); 174} 175 176 177void QuartzUpdateScreens(void) { 178 ScreenPtr pScreen; 179 WindowPtr pRoot; 180 int x, y, width, height, sx, sy; 181 xEvent e; 182 BoxRec bounds; 183 184 if (noPseudoramiXExtension || screenInfo.numScreens != 1) 185 { 186 /* FIXME: if not using Xinerama, we have multiple screens, and 187 to do this properly may need to add or remove screens. Which 188 isn't possible. So don't do anything. Another reason why 189 we default to running with Xinerama. */ 190 191 return; 192 } 193 194 pScreen = screenInfo.screens[0]; 195 196 PseudoramiXResetScreens(); 197 quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height, pScreen); 198 199 pScreen->x = x; 200 pScreen->y = y; 201 pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width); 202 pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height); 203 pScreen->width = width; 204 pScreen->height = height; 205 206 DarwinAdjustScreenOrigins(&screenInfo); 207 208 /* DarwinAdjustScreenOrigins or UpdateScreen may change pScreen->x/y, 209 * so use it rather than x/y 210 */ 211 sx = pScreen->x + darwinMainScreenX; 212 sy = pScreen->y + darwinMainScreenY; 213 214 /* Adjust the root window. */ 215 pRoot = pScreen->root; 216 AppleWMSetScreenOrigin(pRoot); 217 pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL); 218 219 miPaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); 220 221 /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration 222 * http://xquartz.macosforge.org/trac/ticket/346 223 */ 224 bounds.x1 = 0; 225 bounds.x2 = width; 226 bounds.y1 = 0; 227 bounds.y2 = height; 228 pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds); 229 inputInfo.pointer->spriteInfo->sprite->physLimits = bounds; 230 inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds; 231 232 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); 233 234 /* Send an event for the root reconfigure */ 235 e.u.u.type = ConfigureNotify; 236 e.u.configureNotify.window = pRoot->drawable.id; 237 e.u.configureNotify.aboveSibling = None; 238 e.u.configureNotify.x = x - sx; 239 e.u.configureNotify.y = y - sy; 240 e.u.configureNotify.width = width; 241 e.u.configureNotify.height = height; 242 e.u.configureNotify.borderWidth = wBorderWidth(pRoot); 243 e.u.configureNotify.override = pRoot->overrideRedirect; 244 DeliverEvents(pRoot, &e, 1, NullWindow); 245 246 quartzProcs->UpdateScreen(pScreen); 247} 248 249void QuartzShowFullscreen(int state) { 250 int i; 251 252 DEBUG_LOG("QuartzShowFullscreen: state=%d\n", state); 253 254 if(XQuartzIsRootless) { 255 ErrorF("QuartzShowFullscreen called while in rootless mode.\n"); 256 return; 257 } 258 259 if(XQuartzFullscreenVisible == state) 260 return; 261 262 XQuartzFullscreenVisible = state; 263 264 xp_disable_update (); 265 266 if (!XQuartzFullscreenVisible) 267 RootlessHideAllWindows(); 268 269 RootlessUpdateRooted(XQuartzFullscreenVisible); 270 271 if (XQuartzFullscreenVisible) { 272 RootlessShowAllWindows (); 273 for (i=0; i < screenInfo.numScreens; i++) { 274 ScreenPtr pScreen = screenInfo.screens[i]; 275 RootlessRepositionWindows(pScreen); 276 // JH: I don't think this is necessary, but keeping it here as a reminder 277 //RootlessUpdateScreenPixmap(pScreen); 278 } 279 } 280 281 /* Somehow the menubar manages to interfere with our event stream 282 * in fullscreen mode, even though it's not visible. 283 */ 284 X11ApplicationShowHideMenubar(!XQuartzFullscreenVisible); 285 286 xp_reenable_update (); 287 288 if (XQuartzFullscreenDisableHotkeys) 289 xp_disable_hot_keys(XQuartzFullscreenVisible); 290} 291 292void QuartzSetRootless(Bool state) { 293 DEBUG_LOG("QuartzSetRootless state=%d\n", state); 294 295 if(XQuartzIsRootless == state) 296 return; 297 298 if(state) 299 QuartzShowFullscreen(FALSE); 300 301 XQuartzIsRootless = state; 302 303 xp_disable_update(); 304 305 /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */ 306 QuartzUpdateScreens(); 307 308 if(XQuartzIsRootless) { 309 RootlessShowAllWindows(); 310 } else { 311 RootlessHideAllWindows(); 312 } 313 314 X11ApplicationShowHideMenubar(TRUE); 315 316 xp_reenable_update(); 317 318 xp_disable_hot_keys(FALSE); 319} 320 321/* 322 * QuartzShow 323 * Show the X server on screen. Does nothing if already shown. 324 * Calls mode specific screen resume to restore the X clip regions 325 * (if needed) and the X server cursor state. 326 */ 327void QuartzShow(void) { 328 int i; 329 330 if (XQuartzServerVisible) 331 return; 332 333 XQuartzServerVisible = TRUE; 334 for (i = 0; i < screenInfo.numScreens; i++) { 335 if (screenInfo.screens[i]) { 336 quartzProcs->ResumeScreen(screenInfo.screens[i]); 337 } 338 } 339 340 if (!XQuartzIsRootless) 341 QuartzShowFullscreen(TRUE); 342} 343 344 345/* 346 * QuartzHide 347 * Remove the X server display from the screen. Does nothing if already 348 * hidden. Calls mode specific screen suspend to set X clip regions to 349 * prevent drawing (if needed) and restore the Aqua cursor. 350 */ 351void QuartzHide(void) 352{ 353 int i; 354 355 if (XQuartzServerVisible) { 356 for (i = 0; i < screenInfo.numScreens; i++) { 357 if (screenInfo.screens[i]) { 358 quartzProcs->SuspendScreen(screenInfo.screens[i]); 359 } 360 } 361 } 362 363 if(!XQuartzIsRootless) 364 QuartzShowFullscreen(FALSE); 365 XQuartzServerVisible = FALSE; 366} 367 368 369/* 370 * QuartzSetRootClip 371 * Enable or disable rendering to the X screen. 372 */ 373void QuartzSetRootClip( 374 BOOL enable) 375{ 376 int i; 377 378 if (!XQuartzServerVisible) 379 return; 380 381 for (i = 0; i < screenInfo.numScreens; i++) { 382 if (screenInfo.screens[i]) { 383 xf86SetRootClip(screenInfo.screens[i], enable); 384 } 385 } 386} 387 388/* 389 * QuartzSpaceChanged 390 * Unmap offscreen windows, map onscreen windows 391 */ 392void QuartzSpaceChanged(uint32_t space_id) { 393 /* Do something special here, so we don't depend on quartz-wm for spaces to work... */ 394 DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id); 395} 396 397/* 398 * QuartzCopyDisplayIDs 399 * Associate an X11 screen with one or more CoreGraphics display IDs by copying 400 * the list into a private array. Free the previously copied array, if present. 401 */ 402void QuartzCopyDisplayIDs(ScreenPtr pScreen, 403 int displayCount, CGDirectDisplayID *displayIDs) { 404 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 405 int size = displayCount * sizeof(CGDirectDisplayID); 406 407 free(pQuartzScreen->displayIDs); 408 pQuartzScreen->displayIDs = malloc(size); 409 memcpy(pQuartzScreen->displayIDs, displayIDs, size); 410 pQuartzScreen->displayCount = displayCount; 411} 412