1706f2543Smrg/* 2706f2543Smrg * Quartz-specific support for the XRandR extension 3706f2543Smrg * 4706f2543Smrg * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons, 5706f2543Smrg * 2010 Jan Hauffa. 6706f2543Smrg * 2010-2011 Apple Inc. 7706f2543Smrg * All Rights Reserved. 8706f2543Smrg * 9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 10706f2543Smrg * copy of this software and associated documentation files (the "Software"), 11706f2543Smrg * to deal in the Software without restriction, including without limitation 12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 14706f2543Smrg * Software is furnished to do so, subject to the following conditions: 15706f2543Smrg * 16706f2543Smrg * The above copyright notice and this permission notice shall be included in 17706f2543Smrg * all copies or substantial portions of the Software. 18706f2543Smrg * 19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25706f2543Smrg * DEALINGS IN THE SOFTWARE. 26706f2543Smrg * 27706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright 28706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale, 29706f2543Smrg * use or other dealings in this Software without prior written authorization. 30706f2543Smrg */ 31706f2543Smrg 32706f2543Smrg#include "sanitizedCarbon.h" 33706f2543Smrg 34706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 35706f2543Smrg#include <dix-config.h> 36706f2543Smrg#endif 37706f2543Smrg 38706f2543Smrg#include "quartzCommon.h" 39706f2543Smrg#include "quartzRandR.h" 40706f2543Smrg#include "quartz.h" 41706f2543Smrg#include "darwin.h" 42706f2543Smrg 43706f2543Smrg#include "X11Application.h" 44706f2543Smrg 45706f2543Smrg#include <AvailabilityMacros.h> 46706f2543Smrg 47706f2543Smrg#include <X11/extensions/randr.h> 48706f2543Smrg#include <randrstr.h> 49706f2543Smrg#include <IOKit/graphics/IOGraphicsTypes.h> 50706f2543Smrg 51706f2543Smrg/* TODO: UGLY, find a better way! 52706f2543Smrg * We want to ignore kXquartzDisplayChanged which are generated by us 53706f2543Smrg */ 54706f2543Smrgstatic Bool ignore_next_fake_mode_update = FALSE; 55706f2543Smrg 56706f2543Smrg#define FAKE_REFRESH_ROOTLESS 1 57706f2543Smrg#define FAKE_REFRESH_FULLSCREEN 2 58706f2543Smrg 59706f2543Smrg#define DEFAULT_REFRESH 60 60706f2543Smrg#define kDisplayModeUsableFlags (kDisplayModeValidFlag | kDisplayModeSafeFlag) 61706f2543Smrg 62706f2543Smrg#define CALLBACK_SUCCESS 0 63706f2543Smrg#define CALLBACK_CONTINUE 1 64706f2543Smrg#define CALLBACK_ERROR -1 65706f2543Smrg 66706f2543Smrgtypedef int (*QuartzModeCallback) 67706f2543Smrg (ScreenPtr, QuartzModeInfoPtr, void *); 68706f2543Smrg 69706f2543Smrg#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 70706f2543Smrg 71706f2543Smrgstatic long getDictLong (CFDictionaryRef dictRef, CFStringRef key) { 72706f2543Smrg long value; 73706f2543Smrg 74706f2543Smrg CFNumberRef numRef = (CFNumberRef) CFDictionaryGetValue(dictRef, key); 75706f2543Smrg if (!numRef) 76706f2543Smrg return 0; 77706f2543Smrg 78706f2543Smrg if (!CFNumberGetValue(numRef, kCFNumberLongType, &value)) 79706f2543Smrg return 0; 80706f2543Smrg return value; 81706f2543Smrg} 82706f2543Smrg 83706f2543Smrgstatic double getDictDouble (CFDictionaryRef dictRef, CFStringRef key) { 84706f2543Smrg double value; 85706f2543Smrg 86706f2543Smrg CFNumberRef numRef = (CFNumberRef) CFDictionaryGetValue(dictRef, key); 87706f2543Smrg if (!numRef) 88706f2543Smrg return 0.0; 89706f2543Smrg 90706f2543Smrg if (!CFNumberGetValue(numRef, kCFNumberDoubleType, &value)) 91706f2543Smrg return 0.0; 92706f2543Smrg return value; 93706f2543Smrg} 94706f2543Smrg 95706f2543Smrgstatic void QuartzRandRGetModeInfo (CFDictionaryRef modeRef, 96706f2543Smrg QuartzModeInfoPtr pMode) { 97706f2543Smrg pMode->width = (size_t) getDictLong(modeRef, kCGDisplayWidth); 98706f2543Smrg pMode->height = (size_t) getDictLong(modeRef, kCGDisplayHeight); 99706f2543Smrg pMode->refresh = (int)(getDictDouble(modeRef, kCGDisplayRefreshRate) + 0.5); 100706f2543Smrg if (pMode->refresh == 0) 101706f2543Smrg pMode->refresh = DEFAULT_REFRESH; 102706f2543Smrg pMode->ref = NULL; 103706f2543Smrg pMode->pSize = NULL; 104706f2543Smrg} 105706f2543Smrg 106706f2543Smrgstatic Bool QuartzRandRCopyCurrentModeInfo (CGDirectDisplayID screenId, 107706f2543Smrg QuartzModeInfoPtr pMode) { 108706f2543Smrg CFDictionaryRef curModeRef = CGDisplayCurrentMode(screenId); 109706f2543Smrg if (!curModeRef) 110706f2543Smrg return FALSE; 111706f2543Smrg 112706f2543Smrg QuartzRandRGetModeInfo(curModeRef, pMode); 113706f2543Smrg pMode->ref = (void *)curModeRef; 114706f2543Smrg CFRetain(pMode->ref); 115706f2543Smrg return TRUE; 116706f2543Smrg} 117706f2543Smrg 118706f2543Smrgstatic Bool QuartzRandRSetCGMode (CGDirectDisplayID screenId, 119706f2543Smrg QuartzModeInfoPtr pMode) { 120706f2543Smrg CFDictionaryRef modeRef = (CFDictionaryRef) pMode->ref; 121706f2543Smrg return (CGDisplaySwitchToMode(screenId, modeRef) == kCGErrorSuccess); 122706f2543Smrg} 123706f2543Smrg 124706f2543Smrgstatic Bool QuartzRandREnumerateModes (ScreenPtr pScreen, 125706f2543Smrg QuartzModeCallback callback, 126706f2543Smrg void *data) { 127706f2543Smrg Bool retval = FALSE; 128706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 129706f2543Smrg 130706f2543Smrg /* Just an 800x600 fallback if we have no attached heads */ 131706f2543Smrg if(pQuartzScreen->displayIDs) { 132706f2543Smrg CFDictionaryRef curModeRef, modeRef; 133706f2543Smrg long curBpp; 134706f2543Smrg CFArrayRef modes; 135706f2543Smrg QuartzModeInfo modeInfo; 136706f2543Smrg int i; 137706f2543Smrg CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0]; 138706f2543Smrg 139706f2543Smrg curModeRef = CGDisplayCurrentMode(screenId); 140706f2543Smrg if (!curModeRef) 141706f2543Smrg return FALSE; 142706f2543Smrg curBpp = getDictLong(curModeRef, kCGDisplayBitsPerPixel); 143706f2543Smrg 144706f2543Smrg modes = CGDisplayAvailableModes(screenId); 145706f2543Smrg if (!modes) 146706f2543Smrg return FALSE; 147706f2543Smrg for (i = 0; i < CFArrayGetCount(modes); i++) { 148706f2543Smrg int cb; 149706f2543Smrg modeRef = (CFDictionaryRef) CFArrayGetValueAtIndex(modes, i); 150706f2543Smrg 151706f2543Smrg /* Skip modes that are not usable on the current display or have a 152706f2543Smrg different pixel encoding than the current mode. */ 153706f2543Smrg if (((unsigned long) getDictLong(modeRef, kCGDisplayIOFlags) & 154706f2543Smrg kDisplayModeUsableFlags) != kDisplayModeUsableFlags) 155706f2543Smrg continue; 156706f2543Smrg if (getDictLong(modeRef, kCGDisplayBitsPerPixel) != curBpp) 157706f2543Smrg continue; 158706f2543Smrg 159706f2543Smrg QuartzRandRGetModeInfo(modeRef, &modeInfo); 160706f2543Smrg modeInfo.ref = (void *)modeRef; 161706f2543Smrg cb = callback(pScreen, &modeInfo, data); 162706f2543Smrg if (cb == CALLBACK_CONTINUE) 163706f2543Smrg retval = TRUE; 164706f2543Smrg else if (cb == CALLBACK_SUCCESS) 165706f2543Smrg return TRUE; 166706f2543Smrg else if (cb == CALLBACK_ERROR) 167706f2543Smrg return FALSE; 168706f2543Smrg } 169706f2543Smrg } 170706f2543Smrg 171706f2543Smrg switch(callback(pScreen, &pQuartzScreen->rootlessMode, data)) { 172706f2543Smrg case CALLBACK_SUCCESS: 173706f2543Smrg return TRUE; 174706f2543Smrg case CALLBACK_ERROR: 175706f2543Smrg return FALSE; 176706f2543Smrg case CALLBACK_CONTINUE: 177706f2543Smrg retval = TRUE; 178706f2543Smrg default: 179706f2543Smrg break; 180706f2543Smrg } 181706f2543Smrg 182706f2543Smrg switch(callback(pScreen, &pQuartzScreen->fullscreenMode, data)) { 183706f2543Smrg case CALLBACK_SUCCESS: 184706f2543Smrg return TRUE; 185706f2543Smrg case CALLBACK_ERROR: 186706f2543Smrg return FALSE; 187706f2543Smrg case CALLBACK_CONTINUE: 188706f2543Smrg retval = TRUE; 189706f2543Smrg default: 190706f2543Smrg break; 191706f2543Smrg } 192706f2543Smrg 193706f2543Smrg return retval; 194706f2543Smrg} 195706f2543Smrg 196706f2543Smrg#else /* we have the new CG APIs from Snow Leopard */ 197706f2543Smrg 198706f2543Smrgstatic void QuartzRandRGetModeInfo (CGDisplayModeRef modeRef, 199706f2543Smrg QuartzModeInfoPtr pMode) { 200706f2543Smrg pMode->width = CGDisplayModeGetWidth(modeRef); 201706f2543Smrg pMode->height = CGDisplayModeGetHeight(modeRef); 202706f2543Smrg pMode->refresh = (int) (CGDisplayModeGetRefreshRate(modeRef) + 0.5); 203706f2543Smrg if (pMode->refresh == 0) 204706f2543Smrg pMode->refresh = DEFAULT_REFRESH; 205706f2543Smrg pMode->ref = NULL; 206706f2543Smrg pMode->pSize = NULL; 207706f2543Smrg} 208706f2543Smrg 209706f2543Smrgstatic Bool QuartzRandRCopyCurrentModeInfo (CGDirectDisplayID screenId, 210706f2543Smrg QuartzModeInfoPtr pMode) { 211706f2543Smrg CGDisplayModeRef curModeRef = CGDisplayCopyDisplayMode(screenId); 212706f2543Smrg if (!curModeRef) 213706f2543Smrg return FALSE; 214706f2543Smrg 215706f2543Smrg QuartzRandRGetModeInfo(curModeRef, pMode); 216706f2543Smrg pMode->ref = curModeRef; 217706f2543Smrg return TRUE; 218706f2543Smrg} 219706f2543Smrg 220706f2543Smrgstatic Bool QuartzRandRSetCGMode (CGDirectDisplayID screenId, 221706f2543Smrg QuartzModeInfoPtr pMode) { 222706f2543Smrg CGDisplayModeRef modeRef = (CGDisplayModeRef) pMode->ref; 223706f2543Smrg if (!modeRef) 224706f2543Smrg return FALSE; 225706f2543Smrg 226706f2543Smrg return (CGDisplaySetDisplayMode(screenId, modeRef, NULL) == kCGErrorSuccess); 227706f2543Smrg} 228706f2543Smrg 229706f2543Smrgstatic Bool QuartzRandREnumerateModes (ScreenPtr pScreen, 230706f2543Smrg QuartzModeCallback callback, 231706f2543Smrg void *data) { 232706f2543Smrg Bool retval = FALSE; 233706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 234706f2543Smrg 235706f2543Smrg /* Just an 800x600 fallback if we have no attached heads */ 236706f2543Smrg if(pQuartzScreen->displayIDs) { 237706f2543Smrg CGDisplayModeRef curModeRef, modeRef; 238706f2543Smrg CFStringRef curPixelEnc, pixelEnc; 239706f2543Smrg CFComparisonResult pixelEncEqual; 240706f2543Smrg CFArrayRef modes; 241706f2543Smrg QuartzModeInfo modeInfo; 242706f2543Smrg int i; 243706f2543Smrg CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0]; 244706f2543Smrg 245706f2543Smrg curModeRef = CGDisplayCopyDisplayMode(screenId); 246706f2543Smrg if (!curModeRef) 247706f2543Smrg return FALSE; 248706f2543Smrg curPixelEnc = CGDisplayModeCopyPixelEncoding(curModeRef); 249706f2543Smrg CGDisplayModeRelease(curModeRef); 250706f2543Smrg 251706f2543Smrg modes = CGDisplayCopyAllDisplayModes(screenId, NULL); 252706f2543Smrg if (!modes) { 253706f2543Smrg CFRelease(curPixelEnc); 254706f2543Smrg return FALSE; 255706f2543Smrg } 256706f2543Smrg for (i = 0; i < CFArrayGetCount(modes); i++) { 257706f2543Smrg int cb; 258706f2543Smrg modeRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); 259706f2543Smrg 260706f2543Smrg /* Skip modes that are not usable on the current display or have a 261706f2543Smrg different pixel encoding than the current mode. */ 262706f2543Smrg if ((CGDisplayModeGetIOFlags(modeRef) & kDisplayModeUsableFlags) != 263706f2543Smrg kDisplayModeUsableFlags) 264706f2543Smrg continue; 265706f2543Smrg pixelEnc = CGDisplayModeCopyPixelEncoding(modeRef); 266706f2543Smrg pixelEncEqual = CFStringCompare(pixelEnc, curPixelEnc, 0); 267706f2543Smrg CFRelease(pixelEnc); 268706f2543Smrg if (pixelEncEqual != kCFCompareEqualTo) 269706f2543Smrg continue; 270706f2543Smrg 271706f2543Smrg QuartzRandRGetModeInfo(modeRef, &modeInfo); 272706f2543Smrg modeInfo.ref = modeRef; 273706f2543Smrg cb = callback(pScreen, &modeInfo, data); 274706f2543Smrg if (cb == CALLBACK_CONTINUE) { 275706f2543Smrg retval = TRUE; 276706f2543Smrg } else if (cb == CALLBACK_SUCCESS) { 277706f2543Smrg CFRelease(modes); 278706f2543Smrg CFRelease(curPixelEnc); 279706f2543Smrg return TRUE; 280706f2543Smrg } else if (cb == CALLBACK_ERROR) { 281706f2543Smrg CFRelease(modes); 282706f2543Smrg CFRelease(curPixelEnc); 283706f2543Smrg return FALSE; 284706f2543Smrg } 285706f2543Smrg } 286706f2543Smrg 287706f2543Smrg CFRelease(modes); 288706f2543Smrg CFRelease(curPixelEnc); 289706f2543Smrg } 290706f2543Smrg 291706f2543Smrg switch(callback(pScreen, &pQuartzScreen->rootlessMode, data)) { 292706f2543Smrg case CALLBACK_SUCCESS: 293706f2543Smrg return TRUE; 294706f2543Smrg case CALLBACK_ERROR: 295706f2543Smrg return FALSE; 296706f2543Smrg case CALLBACK_CONTINUE: 297706f2543Smrg retval = TRUE; 298706f2543Smrg default: 299706f2543Smrg break; 300706f2543Smrg } 301706f2543Smrg 302706f2543Smrg switch(callback(pScreen, &pQuartzScreen->fullscreenMode, data)) { 303706f2543Smrg case CALLBACK_SUCCESS: 304706f2543Smrg return TRUE; 305706f2543Smrg case CALLBACK_ERROR: 306706f2543Smrg return FALSE; 307706f2543Smrg case CALLBACK_CONTINUE: 308706f2543Smrg retval = TRUE; 309706f2543Smrg default: 310706f2543Smrg break; 311706f2543Smrg } 312706f2543Smrg 313706f2543Smrg return retval; 314706f2543Smrg} 315706f2543Smrg 316706f2543Smrg#endif /* Snow Leopard CoreGraphics APIs */ 317706f2543Smrg 318706f2543Smrg 319706f2543Smrgstatic Bool QuartzRandRModesEqual (QuartzModeInfoPtr pMode1, 320706f2543Smrg QuartzModeInfoPtr pMode2) { 321706f2543Smrg return (pMode1->width == pMode2->width) && 322706f2543Smrg (pMode1->height == pMode2->height) && 323706f2543Smrg (pMode1->refresh == pMode2->refresh); 324706f2543Smrg} 325706f2543Smrg 326706f2543Smrgstatic Bool QuartzRandRRegisterMode (ScreenPtr pScreen, 327706f2543Smrg QuartzModeInfoPtr pMode) { 328706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 329706f2543Smrg Bool isCurrentMode = QuartzRandRModesEqual(&pQuartzScreen->currentMode, pMode); 330706f2543Smrg 331706f2543Smrg /* TODO: DPI */ 332706f2543Smrg pMode->pSize = RRRegisterSize(pScreen, pMode->width, pMode->height, pScreen->mmWidth, pScreen->mmHeight); 333706f2543Smrg if (pMode->pSize) { 334706f2543Smrg //DEBUG_LOG("registering: %d x %d @ %d %s\n", (int)pMode->width, (int)pMode->height, (int)pMode->refresh, isCurrentMode ? "*" : ""); 335706f2543Smrg RRRegisterRate(pScreen, pMode->pSize, pMode->refresh); 336706f2543Smrg 337706f2543Smrg if (isCurrentMode) 338706f2543Smrg RRSetCurrentConfig(pScreen, RR_Rotate_0, pMode->refresh, pMode->pSize); 339706f2543Smrg 340706f2543Smrg return TRUE; 341706f2543Smrg } 342706f2543Smrg return FALSE; 343706f2543Smrg} 344706f2543Smrg 345706f2543Smrgstatic int QuartzRandRRegisterModeCallback (ScreenPtr pScreen, 346706f2543Smrg QuartzModeInfoPtr pMode, 347706f2543Smrg void *data __unused) { 348706f2543Smrg if(QuartzRandRRegisterMode(pScreen, pMode)) { 349706f2543Smrg return CALLBACK_CONTINUE; 350706f2543Smrg } else { 351706f2543Smrg return CALLBACK_ERROR; 352706f2543Smrg } 353706f2543Smrg} 354706f2543Smrg 355706f2543Smrgstatic Bool QuartzRandRSetMode(ScreenPtr pScreen, QuartzModeInfoPtr pMode, BOOL doRegister) { 356706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 357706f2543Smrg Bool captureDisplay = (pMode->refresh != FAKE_REFRESH_FULLSCREEN && pMode->refresh != FAKE_REFRESH_ROOTLESS); 358706f2543Smrg CGDirectDisplayID screenId; 359706f2543Smrg 360706f2543Smrg if(pQuartzScreen->displayIDs == NULL) 361706f2543Smrg return FALSE; 362706f2543Smrg 363706f2543Smrg screenId = pQuartzScreen->displayIDs[0]; 364706f2543Smrg if(XQuartzShieldingWindowLevel == 0 && captureDisplay) { 365706f2543Smrg if(!X11ApplicationCanEnterRandR()) 366706f2543Smrg return FALSE; 367706f2543Smrg CGCaptureAllDisplays(); 368706f2543Smrg XQuartzShieldingWindowLevel = CGShieldingWindowLevel(); // 2147483630 369706f2543Smrg DEBUG_LOG("Display captured. ShieldWindowID: %u, Shield level: %d\n", 370706f2543Smrg CGShieldingWindowID(screenId), XQuartzShieldingWindowLevel); 371706f2543Smrg } 372706f2543Smrg 373706f2543Smrg if (pQuartzScreen->currentMode.ref && CFEqual(pMode->ref, pQuartzScreen->currentMode.ref)) { 374706f2543Smrg DEBUG_LOG("Requested RandR resolution matches current CG mode\n"); 375706f2543Smrg } if (QuartzRandRSetCGMode(screenId, pMode)) { 376706f2543Smrg ignore_next_fake_mode_update = TRUE; 377706f2543Smrg } else { 378706f2543Smrg DEBUG_LOG("Error while requesting CG resolution change.\n"); 379706f2543Smrg return FALSE; 380706f2543Smrg } 381706f2543Smrg 382706f2543Smrg /* If the client requested the fake rootless mode, switch to rootless. 383706f2543Smrg * Otherwise, force fullscreen mode. 384706f2543Smrg */ 385706f2543Smrg QuartzSetRootless(pMode->refresh == FAKE_REFRESH_ROOTLESS); 386706f2543Smrg if (pMode->refresh != FAKE_REFRESH_ROOTLESS) { 387706f2543Smrg QuartzShowFullscreen(TRUE); 388706f2543Smrg } 389706f2543Smrg 390706f2543Smrg if(pQuartzScreen->currentMode.ref) 391706f2543Smrg CFRelease(pQuartzScreen->currentMode.ref); 392706f2543Smrg pQuartzScreen->currentMode = *pMode; 393706f2543Smrg if(pQuartzScreen->currentMode.ref) 394706f2543Smrg CFRetain(pQuartzScreen->currentMode.ref); 395706f2543Smrg 396706f2543Smrg if(XQuartzShieldingWindowLevel != 0 && !captureDisplay) { 397706f2543Smrg CGReleaseAllDisplays(); 398706f2543Smrg XQuartzShieldingWindowLevel = 0; 399706f2543Smrg } 400706f2543Smrg 401706f2543Smrg return TRUE; 402706f2543Smrg} 403706f2543Smrg 404706f2543Smrgstatic int QuartzRandRSetModeCallback (ScreenPtr pScreen, 405706f2543Smrg QuartzModeInfoPtr pMode, 406706f2543Smrg void *data) { 407706f2543Smrg QuartzModeInfoPtr pReqMode = (QuartzModeInfoPtr) data; 408706f2543Smrg 409706f2543Smrg if (!QuartzRandRModesEqual(pMode, pReqMode)) 410706f2543Smrg return CALLBACK_CONTINUE; /* continue enumeration */ 411706f2543Smrg 412706f2543Smrg DEBUG_LOG("Found a match for requested RandR resolution (%dx%d@%d).\n", (int)pMode->width, (int)pMode->height, (int)pMode->refresh); 413706f2543Smrg 414706f2543Smrg if(QuartzRandRSetMode(pScreen, pMode, FALSE)) 415706f2543Smrg return CALLBACK_SUCCESS; 416706f2543Smrg else 417706f2543Smrg return CALLBACK_ERROR; 418706f2543Smrg} 419706f2543Smrg 420706f2543Smrgstatic Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { 421706f2543Smrg *rotations = RR_Rotate_0; /* TODO: support rotation */ 422706f2543Smrg 423706f2543Smrg return QuartzRandREnumerateModes(pScreen, QuartzRandRRegisterModeCallback, NULL); 424706f2543Smrg} 425706f2543Smrg 426706f2543Smrgstatic Bool QuartzRandRSetConfig (ScreenPtr pScreen, 427706f2543Smrg Rotation randr, 428706f2543Smrg int rate, 429706f2543Smrg RRScreenSizePtr pSize) { 430706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 431706f2543Smrg QuartzModeInfo reqMode; 432706f2543Smrg 433706f2543Smrg reqMode.width = pSize->width; 434706f2543Smrg reqMode.height = pSize->height; 435706f2543Smrg reqMode.refresh = rate; 436706f2543Smrg 437706f2543Smrg /* Do not switch modes if requested mode is equal to current mode. */ 438706f2543Smrg if (QuartzRandRModesEqual(&reqMode, &pQuartzScreen->currentMode)) 439706f2543Smrg return TRUE; 440706f2543Smrg 441706f2543Smrg if (QuartzRandREnumerateModes(pScreen, QuartzRandRSetModeCallback, &reqMode)) { 442706f2543Smrg return TRUE; 443706f2543Smrg } 444706f2543Smrg 445706f2543Smrg DEBUG_LOG("Unable to find a matching config: %d x %d @ %d\n", (int)reqMode.width, (int)reqMode.height, (int)reqMode.refresh); 446706f2543Smrg return FALSE; 447706f2543Smrg} 448706f2543Smrg 449706f2543Smrgstatic Bool _QuartzRandRUpdateFakeModes (ScreenPtr pScreen) { 450706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 451706f2543Smrg QuartzModeInfo activeMode; 452706f2543Smrg 453706f2543Smrg if(pQuartzScreen->displayCount > 0) { 454706f2543Smrg if(!QuartzRandRCopyCurrentModeInfo(pQuartzScreen->displayIDs[0], &activeMode)) { 455706f2543Smrg ErrorF("Unable to determine current display mode.\n"); 456706f2543Smrg return FALSE; 457706f2543Smrg } 458706f2543Smrg } else { 459706f2543Smrg memset(&activeMode, 0, sizeof(activeMode)); 460706f2543Smrg activeMode.width = 800; 461706f2543Smrg activeMode.height = 600; 462706f2543Smrg activeMode.refresh = 60; 463706f2543Smrg } 464706f2543Smrg 465706f2543Smrg if(pQuartzScreen->fullscreenMode.ref) 466706f2543Smrg CFRelease(pQuartzScreen->fullscreenMode.ref); 467706f2543Smrg if(pQuartzScreen->currentMode.ref) 468706f2543Smrg CFRelease(pQuartzScreen->currentMode.ref); 469706f2543Smrg 470706f2543Smrg if(pQuartzScreen->displayCount > 1) { 471706f2543Smrg activeMode.width = pScreen->width; 472706f2543Smrg activeMode.height = pScreen->height; 473706f2543Smrg if(XQuartzIsRootless) 474706f2543Smrg activeMode.height += aquaMenuBarHeight; 475706f2543Smrg } 476706f2543Smrg 477706f2543Smrg pQuartzScreen->fullscreenMode = activeMode; 478706f2543Smrg pQuartzScreen->fullscreenMode.refresh = FAKE_REFRESH_FULLSCREEN; 479706f2543Smrg 480706f2543Smrg pQuartzScreen->rootlessMode = activeMode; 481706f2543Smrg pQuartzScreen->rootlessMode.refresh = FAKE_REFRESH_ROOTLESS; 482706f2543Smrg pQuartzScreen->rootlessMode.height -= aquaMenuBarHeight; 483706f2543Smrg 484706f2543Smrg if(XQuartzIsRootless) { 485706f2543Smrg pQuartzScreen->currentMode = pQuartzScreen->rootlessMode; 486706f2543Smrg } else { 487706f2543Smrg pQuartzScreen->currentMode = pQuartzScreen->fullscreenMode; 488706f2543Smrg } 489706f2543Smrg 490706f2543Smrg /* This extra retain is for currentMode's copy. 491706f2543Smrg * fullscreen and rootless share a retain. 492706f2543Smrg */ 493706f2543Smrg if(pQuartzScreen->currentMode.ref) 494706f2543Smrg CFRetain(pQuartzScreen->currentMode.ref); 495706f2543Smrg 496706f2543Smrg DEBUG_LOG("rootlessMode: %d x %d\n", (int)pQuartzScreen->rootlessMode.width, (int)pQuartzScreen->rootlessMode.height); 497706f2543Smrg DEBUG_LOG("fullscreenMode: %d x %d\n", (int)pQuartzScreen->fullscreenMode.width, (int)pQuartzScreen->fullscreenMode.height); 498706f2543Smrg DEBUG_LOG("currentMode: %d x %d\n", (int)pQuartzScreen->currentMode.width, (int)pQuartzScreen->currentMode.height); 499706f2543Smrg 500706f2543Smrg return TRUE; 501706f2543Smrg} 502706f2543Smrg 503706f2543SmrgBool QuartzRandRUpdateFakeModes (BOOL force_update) { 504706f2543Smrg ScreenPtr pScreen = screenInfo.screens[0]; 505706f2543Smrg 506706f2543Smrg if(ignore_next_fake_mode_update) { 507706f2543Smrg DEBUG_LOG("Ignoring update request caused by RandR resolution change.\n"); 508706f2543Smrg ignore_next_fake_mode_update = FALSE; 509706f2543Smrg return TRUE; 510706f2543Smrg } 511706f2543Smrg 512706f2543Smrg if(!_QuartzRandRUpdateFakeModes(pScreen)) 513706f2543Smrg return FALSE; 514706f2543Smrg 515706f2543Smrg if(force_update) 516706f2543Smrg RRGetInfo(pScreen, TRUE); 517706f2543Smrg 518706f2543Smrg return TRUE; 519706f2543Smrg} 520706f2543Smrg 521706f2543SmrgBool QuartzRandRInit (ScreenPtr pScreen) { 522706f2543Smrg rrScrPrivPtr pScrPriv; 523706f2543Smrg 524706f2543Smrg if (!RRScreenInit (pScreen)) return FALSE; 525706f2543Smrg if (!_QuartzRandRUpdateFakeModes (pScreen)) return FALSE; 526706f2543Smrg 527706f2543Smrg pScrPriv = rrGetScrPriv(pScreen); 528706f2543Smrg pScrPriv->rrGetInfo = QuartzRandRGetInfo; 529706f2543Smrg pScrPriv->rrSetConfig = QuartzRandRSetConfig; 530706f2543Smrg return TRUE; 531706f2543Smrg} 532706f2543Smrg 533706f2543Smrgvoid QuartzRandRSetFakeRootless (void) { 534706f2543Smrg int i; 535706f2543Smrg 536706f2543Smrg DEBUG_LOG("QuartzRandRSetFakeRootless called.\n"); 537706f2543Smrg 538706f2543Smrg for (i=0; i < screenInfo.numScreens; i++) { 539706f2543Smrg ScreenPtr pScreen = screenInfo.screens[i]; 540706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 541706f2543Smrg 542706f2543Smrg QuartzRandRSetMode(pScreen, &pQuartzScreen->rootlessMode, TRUE); 543706f2543Smrg } 544706f2543Smrg} 545706f2543Smrg 546706f2543Smrgvoid QuartzRandRSetFakeFullscreen (BOOL state) { 547706f2543Smrg int i; 548706f2543Smrg 549706f2543Smrg DEBUG_LOG("QuartzRandRSetFakeFullscreen called.\n"); 550706f2543Smrg 551706f2543Smrg for (i=0; i < screenInfo.numScreens; i++) { 552706f2543Smrg ScreenPtr pScreen = screenInfo.screens[i]; 553706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 554706f2543Smrg 555706f2543Smrg QuartzRandRSetMode(pScreen, &pQuartzScreen->fullscreenMode, TRUE); 556706f2543Smrg } 557706f2543Smrg 558706f2543Smrg QuartzShowFullscreen(state); 559706f2543Smrg} 560706f2543Smrg 561706f2543Smrg/* Toggle fullscreen mode. If "fake" fullscreen is the current mode, 562706f2543Smrg * this will just show/hide the X11 windows. If we are in a RandR fullscreen 563706f2543Smrg * mode, this will toggles us to the default fake mode and hide windows if 564706f2543Smrg * it is fullscreen 565706f2543Smrg */ 566706f2543Smrgvoid QuartzRandRToggleFullscreen (void) { 567706f2543Smrg ScreenPtr pScreen = screenInfo.screens[0]; 568706f2543Smrg QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); 569706f2543Smrg 570706f2543Smrg if (pQuartzScreen->currentMode.ref == NULL) { 571706f2543Smrg ErrorF("Ignoring QuartzRandRToggleFullscreen because don't have a current mode set.\n"); 572706f2543Smrg } else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_ROOTLESS) { 573706f2543Smrg ErrorF("Ignoring QuartzRandRToggleFullscreen because we are in rootless mode.\n"); 574706f2543Smrg } else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_FULLSCREEN) { 575706f2543Smrg /* Legacy fullscreen mode. Hide/Show */ 576706f2543Smrg QuartzShowFullscreen(!XQuartzFullscreenVisible); 577706f2543Smrg } else { 578706f2543Smrg /* RandR fullscreen mode. Return to default mode and hide if it is fullscreen. */ 579706f2543Smrg if(XQuartzRootlessDefault) { 580706f2543Smrg QuartzRandRSetFakeRootless(); 581706f2543Smrg } else { 582706f2543Smrg QuartzRandRSetFakeFullscreen(FALSE); 583706f2543Smrg } 584706f2543Smrg } 585706f2543Smrg} 586