quartzRandR.c revision 35c4bbdf
1/* 2 * Quartz-specific support for the XRandR extension 3 * 4 * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons, 5 * 2010 Jan Hauffa. 6 * 2010-2012 Apple Inc. 7 * All Rights Reserved. 8 * 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: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 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. 26 * 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. 30 */ 31 32#include "sanitizedCarbon.h" 33 34#ifdef HAVE_DIX_CONFIG_H 35#include <dix-config.h> 36#endif 37 38#include "quartzCommon.h" 39#include "quartzRandR.h" 40#include "quartz.h" 41#include "darwin.h" 42 43#include "X11Application.h" 44 45#include <AvailabilityMacros.h> 46 47#include <X11/extensions/randr.h> 48#include <randrstr.h> 49#include <IOKit/graphics/IOGraphicsTypes.h> 50 51/* TODO: UGLY, find a better way! 52 * We want to ignore kXquartzDisplayChanged which are generated by us 53 */ 54static Bool ignore_next_fake_mode_update = FALSE; 55 56#define FAKE_REFRESH_ROOTLESS 1 57#define FAKE_REFRESH_FULLSCREEN 2 58 59#define DEFAULT_REFRESH 60 60#define kDisplayModeUsableFlags (kDisplayModeValidFlag | kDisplayModeSafeFlag) 61 62#define CALLBACK_SUCCESS 0 63#define CALLBACK_CONTINUE 1 64#define CALLBACK_ERROR -1 65 66typedef int (*QuartzModeCallback) 67 (ScreenPtr, QuartzModeInfoPtr, void *); 68 69#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 70 71static long 72getDictLong(CFDictionaryRef dictRef, CFStringRef key) 73{ 74 long value; 75 76 CFNumberRef numRef = (CFNumberRef)CFDictionaryGetValue(dictRef, key); 77 if (!numRef) 78 return 0; 79 80 if (!CFNumberGetValue(numRef, kCFNumberLongType, &value)) 81 return 0; 82 return value; 83} 84 85static double 86getDictDouble(CFDictionaryRef dictRef, CFStringRef key) 87{ 88 double value; 89 90 CFNumberRef numRef = (CFNumberRef)CFDictionaryGetValue(dictRef, key); 91 if (!numRef) 92 return 0.0; 93 94 if (!CFNumberGetValue(numRef, kCFNumberDoubleType, &value)) 95 return 0.0; 96 return value; 97} 98 99static void 100QuartzRandRGetModeInfo(CFDictionaryRef modeRef, 101 QuartzModeInfoPtr pMode) 102{ 103 pMode->width = (size_t)getDictLong(modeRef, kCGDisplayWidth); 104 pMode->height = (size_t)getDictLong(modeRef, kCGDisplayHeight); 105 pMode->refresh = 106 (int)(getDictDouble(modeRef, kCGDisplayRefreshRate) + 0.5); 107 if (pMode->refresh == 0) 108 pMode->refresh = DEFAULT_REFRESH; 109 pMode->ref = NULL; 110 pMode->pSize = NULL; 111} 112 113static Bool 114QuartzRandRCopyCurrentModeInfo(CGDirectDisplayID screenId, 115 QuartzModeInfoPtr pMode) 116{ 117 CFDictionaryRef curModeRef = CGDisplayCurrentMode(screenId); 118 if (!curModeRef) 119 return FALSE; 120 121 QuartzRandRGetModeInfo(curModeRef, pMode); 122 pMode->ref = (void *)curModeRef; 123 CFRetain(pMode->ref); 124 return TRUE; 125} 126 127static Bool 128QuartzRandRSetCGMode(CGDirectDisplayID screenId, 129 QuartzModeInfoPtr pMode) 130{ 131 CFDictionaryRef modeRef = (CFDictionaryRef)pMode->ref; 132 return (CGDisplaySwitchToMode(screenId, modeRef) == kCGErrorSuccess); 133} 134 135static Bool 136QuartzRandREnumerateModes(ScreenPtr pScreen, 137 QuartzModeCallback callback, 138 void *data) 139{ 140 Bool retval = FALSE; 141 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 142 143 /* Just an 800x600 fallback if we have no attached heads */ 144 if (pQuartzScreen->displayIDs) { 145 CFDictionaryRef curModeRef, modeRef; 146 long curBpp; 147 CFArrayRef modes; 148 QuartzModeInfo modeInfo; 149 int i; 150 CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0]; 151 152 curModeRef = CGDisplayCurrentMode(screenId); 153 if (!curModeRef) 154 return FALSE; 155 curBpp = getDictLong(curModeRef, kCGDisplayBitsPerPixel); 156 157 modes = CGDisplayAvailableModes(screenId); 158 if (!modes) 159 return FALSE; 160 for (i = 0; i < CFArrayGetCount(modes); i++) { 161 int cb; 162 modeRef = (CFDictionaryRef)CFArrayGetValueAtIndex(modes, i); 163 164 /* Skip modes that are not usable on the current display or have a 165 different pixel encoding than the current mode. */ 166 if (((unsigned long)getDictLong(modeRef, kCGDisplayIOFlags) & 167 kDisplayModeUsableFlags) != kDisplayModeUsableFlags) 168 continue; 169 if (getDictLong(modeRef, kCGDisplayBitsPerPixel) != curBpp) 170 continue; 171 172 QuartzRandRGetModeInfo(modeRef, &modeInfo); 173 modeInfo.ref = (void *)modeRef; 174 cb = callback(pScreen, &modeInfo, data); 175 if (cb == CALLBACK_CONTINUE) 176 retval = TRUE; 177 else if (cb == CALLBACK_SUCCESS) 178 return TRUE; 179 else if (cb == CALLBACK_ERROR) 180 return FALSE; 181 } 182 } 183 184 switch (callback(pScreen, &pQuartzScreen->rootlessMode, data)) { 185 case CALLBACK_SUCCESS: 186 return TRUE; 187 188 case CALLBACK_ERROR: 189 return FALSE; 190 191 case CALLBACK_CONTINUE: 192 retval = TRUE; 193 194 default: 195 break; 196 } 197 198 switch (callback(pScreen, &pQuartzScreen->fullscreenMode, data)) { 199 case CALLBACK_SUCCESS: 200 return TRUE; 201 202 case CALLBACK_ERROR: 203 return FALSE; 204 205 case CALLBACK_CONTINUE: 206 retval = TRUE; 207 208 default: 209 break; 210 } 211 212 return retval; 213} 214 215#else /* we have the new CG APIs from Snow Leopard */ 216 217static void 218QuartzRandRGetModeInfo(CGDisplayModeRef modeRef, 219 QuartzModeInfoPtr pMode) 220{ 221 pMode->width = CGDisplayModeGetWidth(modeRef); 222 pMode->height = CGDisplayModeGetHeight(modeRef); 223 pMode->refresh = (int)(CGDisplayModeGetRefreshRate(modeRef) + 0.5); 224 if (pMode->refresh == 0) 225 pMode->refresh = DEFAULT_REFRESH; 226 pMode->ref = NULL; 227 pMode->pSize = NULL; 228} 229 230static Bool 231QuartzRandRCopyCurrentModeInfo(CGDirectDisplayID screenId, 232 QuartzModeInfoPtr pMode) 233{ 234 CGDisplayModeRef curModeRef = CGDisplayCopyDisplayMode(screenId); 235 if (!curModeRef) 236 return FALSE; 237 238 QuartzRandRGetModeInfo(curModeRef, pMode); 239 pMode->ref = curModeRef; 240 return TRUE; 241} 242 243static Bool 244QuartzRandRSetCGMode(CGDirectDisplayID screenId, 245 QuartzModeInfoPtr pMode) 246{ 247 CGDisplayModeRef modeRef = (CGDisplayModeRef)pMode->ref; 248 if (!modeRef) 249 return FALSE; 250 251 return (CGDisplaySetDisplayMode(screenId, modeRef, 252 NULL) == kCGErrorSuccess); 253} 254 255static Bool 256QuartzRandREnumerateModes(ScreenPtr pScreen, 257 QuartzModeCallback callback, 258 void *data) 259{ 260 Bool retval = FALSE; 261 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 262 263 /* Just an 800x600 fallback if we have no attached heads */ 264 if (pQuartzScreen->displayIDs) { 265 CGDisplayModeRef curModeRef, modeRef; 266 CFStringRef curPixelEnc, pixelEnc; 267 CFComparisonResult pixelEncEqual; 268 CFArrayRef modes; 269 QuartzModeInfo modeInfo; 270 int i; 271 CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0]; 272 273 curModeRef = CGDisplayCopyDisplayMode(screenId); 274 if (!curModeRef) 275 return FALSE; 276 curPixelEnc = CGDisplayModeCopyPixelEncoding(curModeRef); 277 CGDisplayModeRelease(curModeRef); 278 279 modes = CGDisplayCopyAllDisplayModes(screenId, NULL); 280 if (!modes) { 281 CFRelease(curPixelEnc); 282 return FALSE; 283 } 284 for (i = 0; i < CFArrayGetCount(modes); i++) { 285 int cb; 286 modeRef = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); 287 288 /* Skip modes that are not usable on the current display or have a 289 different pixel encoding than the current mode. */ 290 if ((CGDisplayModeGetIOFlags(modeRef) & 291 kDisplayModeUsableFlags) != 292 kDisplayModeUsableFlags) 293 continue; 294 pixelEnc = CGDisplayModeCopyPixelEncoding(modeRef); 295 pixelEncEqual = CFStringCompare(pixelEnc, curPixelEnc, 0); 296 CFRelease(pixelEnc); 297 if (pixelEncEqual != kCFCompareEqualTo) 298 continue; 299 300 QuartzRandRGetModeInfo(modeRef, &modeInfo); 301 modeInfo.ref = modeRef; 302 cb = callback(pScreen, &modeInfo, data); 303 if (cb == CALLBACK_CONTINUE) { 304 retval = TRUE; 305 } 306 else if (cb == CALLBACK_SUCCESS) { 307 CFRelease(modes); 308 CFRelease(curPixelEnc); 309 return TRUE; 310 } 311 else if (cb == CALLBACK_ERROR) { 312 CFRelease(modes); 313 CFRelease(curPixelEnc); 314 return FALSE; 315 } 316 } 317 318 CFRelease(modes); 319 CFRelease(curPixelEnc); 320 } 321 322 switch (callback(pScreen, &pQuartzScreen->rootlessMode, data)) { 323 case CALLBACK_SUCCESS: 324 return TRUE; 325 326 case CALLBACK_ERROR: 327 return FALSE; 328 329 case CALLBACK_CONTINUE: 330 retval = TRUE; 331 332 default: 333 break; 334 } 335 336 switch (callback(pScreen, &pQuartzScreen->fullscreenMode, data)) { 337 case CALLBACK_SUCCESS: 338 return TRUE; 339 340 case CALLBACK_ERROR: 341 return FALSE; 342 343 case CALLBACK_CONTINUE: 344 retval = TRUE; 345 346 default: 347 break; 348 } 349 350 return retval; 351} 352 353#endif /* Snow Leopard CoreGraphics APIs */ 354 355static Bool 356QuartzRandRModesEqual(QuartzModeInfoPtr pMode1, 357 QuartzModeInfoPtr pMode2) 358{ 359 return (pMode1->width == pMode2->width) && 360 (pMode1->height == pMode2->height) && 361 (pMode1->refresh == pMode2->refresh); 362} 363 364static Bool 365QuartzRandRRegisterMode(ScreenPtr pScreen, 366 QuartzModeInfoPtr pMode) 367{ 368 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 369 Bool isCurrentMode = QuartzRandRModesEqual(&pQuartzScreen->currentMode, 370 pMode); 371 372 /* TODO: DPI */ 373 pMode->pSize = 374 RRRegisterSize(pScreen, pMode->width, pMode->height, pScreen->mmWidth, 375 pScreen->mmHeight); 376 if (pMode->pSize) { 377 //DEBUG_LOG("registering: %d x %d @ %d %s\n", (int)pMode->width, (int)pMode->height, (int)pMode->refresh, isCurrentMode ? "*" : ""); 378 RRRegisterRate(pScreen, pMode->pSize, pMode->refresh); 379 380 if (isCurrentMode) 381 RRSetCurrentConfig(pScreen, RR_Rotate_0, pMode->refresh, 382 pMode->pSize); 383 384 return TRUE; 385 } 386 return FALSE; 387} 388 389static int 390QuartzRandRRegisterModeCallback(ScreenPtr pScreen, 391 QuartzModeInfoPtr pMode, 392 void *data __unused) 393{ 394 if (QuartzRandRRegisterMode(pScreen, pMode)) { 395 return CALLBACK_CONTINUE; 396 } 397 else { 398 return CALLBACK_ERROR; 399 } 400} 401 402static Bool 403QuartzRandRSetMode(ScreenPtr pScreen, QuartzModeInfoPtr pMode, 404 BOOL doRegister) 405{ 406 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 407 Bool captureDisplay = 408 (pMode->refresh != FAKE_REFRESH_FULLSCREEN && pMode->refresh != 409 FAKE_REFRESH_ROOTLESS); 410 CGDirectDisplayID screenId; 411 412 if (pQuartzScreen->displayIDs == NULL) 413 return FALSE; 414 415 screenId = pQuartzScreen->displayIDs[0]; 416 if (XQuartzShieldingWindowLevel == 0 && captureDisplay) { 417 if (!X11ApplicationCanEnterRandR()) 418 return FALSE; 419 CGCaptureAllDisplays(); 420 XQuartzShieldingWindowLevel = CGShieldingWindowLevel(); // 2147483630 421 DEBUG_LOG("Display captured. ShieldWindowID: %u, Shield level: %d\n", 422 CGShieldingWindowID(screenId), XQuartzShieldingWindowLevel); 423 } 424 425 if (pQuartzScreen->currentMode.ref && 426 CFEqual(pMode->ref, pQuartzScreen->currentMode.ref)) { 427 DEBUG_LOG("Requested RandR resolution matches current CG mode\n"); 428 } 429 if (QuartzRandRSetCGMode(screenId, pMode)) { 430 ignore_next_fake_mode_update = TRUE; 431 } 432 else { 433 DEBUG_LOG("Error while requesting CG resolution change.\n"); 434 return FALSE; 435 } 436 437 /* If the client requested the fake rootless mode, switch to rootless. 438 * Otherwise, force fullscreen mode. 439 */ 440 QuartzSetRootless(pMode->refresh == FAKE_REFRESH_ROOTLESS); 441 if (pMode->refresh != FAKE_REFRESH_ROOTLESS) { 442 QuartzShowFullscreen(TRUE); 443 } 444 445 if (pQuartzScreen->currentMode.ref) 446 CFRelease(pQuartzScreen->currentMode.ref); 447 pQuartzScreen->currentMode = *pMode; 448 if (pQuartzScreen->currentMode.ref) 449 CFRetain(pQuartzScreen->currentMode.ref); 450 451 if (XQuartzShieldingWindowLevel != 0 && !captureDisplay) { 452 CGReleaseAllDisplays(); 453 XQuartzShieldingWindowLevel = 0; 454 } 455 456 return TRUE; 457} 458 459static int 460QuartzRandRSetModeCallback(ScreenPtr pScreen, 461 QuartzModeInfoPtr pMode, 462 void *data) 463{ 464 QuartzModeInfoPtr pReqMode = (QuartzModeInfoPtr)data; 465 466 if (!QuartzRandRModesEqual(pMode, pReqMode)) 467 return CALLBACK_CONTINUE; /* continue enumeration */ 468 469 DEBUG_LOG("Found a match for requested RandR resolution (%dx%d@%d).\n", 470 (int)pMode->width, (int)pMode->height, (int)pMode->refresh); 471 472 if (QuartzRandRSetMode(pScreen, pMode, FALSE)) 473 return CALLBACK_SUCCESS; 474 else 475 return CALLBACK_ERROR; 476} 477 478static Bool 479QuartzRandRGetInfo(ScreenPtr pScreen, Rotation *rotations) 480{ 481 *rotations = RR_Rotate_0; /* TODO: support rotation */ 482 483 return QuartzRandREnumerateModes(pScreen, QuartzRandRRegisterModeCallback, 484 NULL); 485} 486 487static Bool 488QuartzRandRSetConfig(ScreenPtr pScreen, 489 Rotation randr, 490 int rate, 491 RRScreenSizePtr pSize) 492{ 493 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 494 QuartzModeInfo reqMode; 495 496 reqMode.width = pSize->width; 497 reqMode.height = pSize->height; 498 reqMode.refresh = rate; 499 500 /* Do not switch modes if requested mode is equal to current mode. */ 501 if (QuartzRandRModesEqual(&reqMode, &pQuartzScreen->currentMode)) 502 return TRUE; 503 504 if (QuartzRandREnumerateModes(pScreen, QuartzRandRSetModeCallback, 505 &reqMode)) { 506 return TRUE; 507 } 508 509 DEBUG_LOG("Unable to find a matching config: %d x %d @ %d\n", 510 (int)reqMode.width, (int)reqMode.height, 511 (int)reqMode.refresh); 512 return FALSE; 513} 514 515static Bool 516_QuartzRandRUpdateFakeModes(ScreenPtr pScreen) 517{ 518 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 519 QuartzModeInfo activeMode; 520 521 if (pQuartzScreen->displayCount > 0) { 522 if (!QuartzRandRCopyCurrentModeInfo(pQuartzScreen->displayIDs[0], 523 &activeMode)) { 524 ErrorF("Unable to determine current display mode.\n"); 525 return FALSE; 526 } 527 } 528 else { 529 memset(&activeMode, 0, sizeof(activeMode)); 530 activeMode.width = 800; 531 activeMode.height = 600; 532 activeMode.refresh = 60; 533 } 534 535 if (pQuartzScreen->fullscreenMode.ref) 536 CFRelease(pQuartzScreen->fullscreenMode.ref); 537 if (pQuartzScreen->currentMode.ref) 538 CFRelease(pQuartzScreen->currentMode.ref); 539 540 if (pQuartzScreen->displayCount > 1) { 541 activeMode.width = pScreen->width; 542 activeMode.height = pScreen->height; 543 if (XQuartzIsRootless) 544 activeMode.height += aquaMenuBarHeight; 545 } 546 547 pQuartzScreen->fullscreenMode = activeMode; 548 pQuartzScreen->fullscreenMode.refresh = FAKE_REFRESH_FULLSCREEN; 549 550 pQuartzScreen->rootlessMode = activeMode; 551 pQuartzScreen->rootlessMode.refresh = FAKE_REFRESH_ROOTLESS; 552 pQuartzScreen->rootlessMode.height -= aquaMenuBarHeight; 553 554 if (XQuartzIsRootless) { 555 pQuartzScreen->currentMode = pQuartzScreen->rootlessMode; 556 } 557 else { 558 pQuartzScreen->currentMode = pQuartzScreen->fullscreenMode; 559 } 560 561 /* This extra retain is for currentMode's copy. 562 * fullscreen and rootless share a retain. 563 */ 564 if (pQuartzScreen->currentMode.ref) 565 CFRetain(pQuartzScreen->currentMode.ref); 566 567 DEBUG_LOG("rootlessMode: %d x %d\n", 568 (int)pQuartzScreen->rootlessMode.width, 569 (int)pQuartzScreen->rootlessMode.height); 570 DEBUG_LOG("fullscreenMode: %d x %d\n", 571 (int)pQuartzScreen->fullscreenMode.width, 572 (int)pQuartzScreen->fullscreenMode.height); 573 DEBUG_LOG("currentMode: %d x %d\n", (int)pQuartzScreen->currentMode.width, 574 (int)pQuartzScreen->currentMode.height); 575 576 return TRUE; 577} 578 579Bool 580QuartzRandRUpdateFakeModes(BOOL force_update) 581{ 582 ScreenPtr pScreen = screenInfo.screens[0]; 583 584 if (ignore_next_fake_mode_update) { 585 DEBUG_LOG( 586 "Ignoring update request caused by RandR resolution change.\n"); 587 ignore_next_fake_mode_update = FALSE; 588 return TRUE; 589 } 590 591 if (!_QuartzRandRUpdateFakeModes(pScreen)) 592 return FALSE; 593 594 if (force_update) 595 RRGetInfo(pScreen, TRUE); 596 597 return TRUE; 598} 599 600Bool 601QuartzRandRInit(ScreenPtr pScreen) 602{ 603 rrScrPrivPtr pScrPriv; 604 605 if (!RRScreenInit(pScreen)) return FALSE; 606 if (!_QuartzRandRUpdateFakeModes(pScreen)) return FALSE; 607 608 pScrPriv = rrGetScrPriv(pScreen); 609 pScrPriv->rrGetInfo = QuartzRandRGetInfo; 610 pScrPriv->rrSetConfig = QuartzRandRSetConfig; 611 return TRUE; 612} 613 614void 615QuartzRandRSetFakeRootless(void) 616{ 617 int i; 618 619 DEBUG_LOG("QuartzRandRSetFakeRootless called.\n"); 620 621 for (i = 0; i < screenInfo.numScreens; i++) { 622 ScreenPtr pScreen = screenInfo.screens[i]; 623 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 624 625 QuartzRandRSetMode(pScreen, &pQuartzScreen->rootlessMode, TRUE); 626 } 627} 628 629void 630QuartzRandRSetFakeFullscreen(BOOL state) 631{ 632 int i; 633 634 DEBUG_LOG("QuartzRandRSetFakeFullscreen called.\n"); 635 636 for (i = 0; i < screenInfo.numScreens; i++) { 637 ScreenPtr pScreen = screenInfo.screens[i]; 638 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 639 640 QuartzRandRSetMode(pScreen, &pQuartzScreen->fullscreenMode, TRUE); 641 } 642 643 QuartzShowFullscreen(state); 644} 645 646/* Toggle fullscreen mode. If "fake" fullscreen is the current mode, 647 * this will just show/hide the X11 windows. If we are in a RandR fullscreen 648 * mode, this will toggles us to the default fake mode and hide windows if 649 * it is fullscreen 650 */ 651void 652QuartzRandRToggleFullscreen(void) 653{ 654 ScreenPtr pScreen = screenInfo.screens[0]; 655 QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 656 657 if (pQuartzScreen->currentMode.ref == NULL) { 658 ErrorF( 659 "Ignoring QuartzRandRToggleFullscreen because don't have a current mode set.\n"); 660 } 661 else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_ROOTLESS) { 662 ErrorF( 663 "Ignoring QuartzRandRToggleFullscreen because we are in rootless mode.\n"); 664 } 665 else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_FULLSCREEN) { 666 /* Legacy fullscreen mode. Hide/Show */ 667 QuartzShowFullscreen(!XQuartzFullscreenVisible); 668 } 669 else { 670 /* RandR fullscreen mode. Return to default mode and hide if it is fullscreen. */ 671 if (XQuartzRootlessDefault) { 672 QuartzRandRSetFakeRootless(); 673 } 674 else { 675 QuartzRandRSetFakeFullscreen(FALSE); 676 } 677 } 678} 679