586 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			586 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Quartz-specific support for the XRandR extension
 | 
						|
 *
 | 
						|
 * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons,
 | 
						|
 *               2010      Jan Hauffa.
 | 
						|
 *               2010-2011 Apple Inc.
 | 
						|
 *                 All Rights Reserved.
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
 * copy of this software and associated documentation files (the "Software"),
 | 
						|
 * to deal in the Software without restriction, including without limitation
 | 
						|
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
						|
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
						|
 * Software is furnished to do so, subject to the following conditions:
 | 
						|
 *
 | 
						|
 * The above copyright notice and this permission notice shall be included in
 | 
						|
 * all copies or substantial portions of the Software.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
						|
 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
						|
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
						|
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
						|
 * DEALINGS IN THE SOFTWARE.
 | 
						|
 *
 | 
						|
 * Except as contained in this notice, the name(s) of the above copyright
 | 
						|
 * holders shall not be used in advertising or otherwise to promote the sale,
 | 
						|
 * use or other dealings in this Software without prior written authorization.
 | 
						|
 */
 | 
						|
 | 
						|
#include "sanitizedCarbon.h"
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "quartzCommon.h"
 | 
						|
#include "quartzRandR.h"
 | 
						|
#include "quartz.h"
 | 
						|
#include "darwin.h"
 | 
						|
 | 
						|
#include "X11Application.h"
 | 
						|
 | 
						|
#include <AvailabilityMacros.h>
 | 
						|
 | 
						|
#include <X11/extensions/randr.h>
 | 
						|
#include <randrstr.h>
 | 
						|
#include <IOKit/graphics/IOGraphicsTypes.h>
 | 
						|
 | 
						|
/* TODO: UGLY, find a better way!
 | 
						|
 * We want to ignore kXquartzDisplayChanged which are generated by us
 | 
						|
 */
 | 
						|
static Bool ignore_next_fake_mode_update = FALSE;
 | 
						|
 | 
						|
#define FAKE_REFRESH_ROOTLESS 1
 | 
						|
#define FAKE_REFRESH_FULLSCREEN 2
 | 
						|
 | 
						|
#define DEFAULT_REFRESH  60
 | 
						|
#define kDisplayModeUsableFlags  (kDisplayModeValidFlag | kDisplayModeSafeFlag)
 | 
						|
 | 
						|
#define CALLBACK_SUCCESS 0
 | 
						|
#define CALLBACK_CONTINUE 1
 | 
						|
#define CALLBACK_ERROR -1
 | 
						|
 | 
						|
typedef int (*QuartzModeCallback)
 | 
						|
    (ScreenPtr, QuartzModeInfoPtr, void *);
 | 
						|
 | 
						|
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
 | 
						|
 | 
						|
static long getDictLong (CFDictionaryRef dictRef, CFStringRef key) {
 | 
						|
    long value;
 | 
						|
 | 
						|
    CFNumberRef numRef = (CFNumberRef) CFDictionaryGetValue(dictRef, key);
 | 
						|
    if (!numRef)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (!CFNumberGetValue(numRef, kCFNumberLongType, &value))
 | 
						|
        return 0;
 | 
						|
    return value;
 | 
						|
}
 | 
						|
 | 
						|
static double getDictDouble (CFDictionaryRef dictRef, CFStringRef key) {
 | 
						|
    double value;
 | 
						|
 | 
						|
    CFNumberRef numRef = (CFNumberRef) CFDictionaryGetValue(dictRef, key);
 | 
						|
    if (!numRef)
 | 
						|
        return 0.0;
 | 
						|
 | 
						|
    if (!CFNumberGetValue(numRef, kCFNumberDoubleType, &value))
 | 
						|
        return 0.0;
 | 
						|
    return value;
 | 
						|
}
 | 
						|
 | 
						|
static void QuartzRandRGetModeInfo (CFDictionaryRef modeRef,
 | 
						|
                                    QuartzModeInfoPtr pMode) {
 | 
						|
    pMode->width = (size_t) getDictLong(modeRef, kCGDisplayWidth);
 | 
						|
    pMode->height = (size_t) getDictLong(modeRef, kCGDisplayHeight);
 | 
						|
    pMode->refresh = (int)(getDictDouble(modeRef, kCGDisplayRefreshRate) + 0.5);
 | 
						|
    if (pMode->refresh == 0)
 | 
						|
        pMode->refresh = DEFAULT_REFRESH;
 | 
						|
    pMode->ref = NULL;
 | 
						|
    pMode->pSize = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRCopyCurrentModeInfo (CGDirectDisplayID screenId,
 | 
						|
                                           QuartzModeInfoPtr pMode) {
 | 
						|
    CFDictionaryRef curModeRef = CGDisplayCurrentMode(screenId);
 | 
						|
    if (!curModeRef)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    QuartzRandRGetModeInfo(curModeRef, pMode);
 | 
						|
    pMode->ref = (void *)curModeRef;
 | 
						|
    CFRetain(pMode->ref);
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRSetCGMode (CGDirectDisplayID screenId,
 | 
						|
                                QuartzModeInfoPtr pMode) {
 | 
						|
    CFDictionaryRef modeRef = (CFDictionaryRef) pMode->ref;
 | 
						|
    return (CGDisplaySwitchToMode(screenId, modeRef) == kCGErrorSuccess);
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandREnumerateModes (ScreenPtr pScreen,
 | 
						|
                                       QuartzModeCallback callback,
 | 
						|
                                       void *data) {
 | 
						|
    Bool retval = FALSE;
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
 | 
						|
    /* Just an 800x600 fallback if we have no attached heads */
 | 
						|
    if(pQuartzScreen->displayIDs) {
 | 
						|
        CFDictionaryRef curModeRef, modeRef;
 | 
						|
        long curBpp;
 | 
						|
        CFArrayRef modes;
 | 
						|
        QuartzModeInfo modeInfo;
 | 
						|
        int i;
 | 
						|
        CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0];
 | 
						|
 | 
						|
        curModeRef = CGDisplayCurrentMode(screenId);
 | 
						|
        if (!curModeRef)
 | 
						|
            return FALSE;
 | 
						|
        curBpp = getDictLong(curModeRef, kCGDisplayBitsPerPixel);
 | 
						|
 | 
						|
        modes = CGDisplayAvailableModes(screenId);
 | 
						|
        if (!modes)
 | 
						|
            return FALSE;
 | 
						|
        for (i = 0; i < CFArrayGetCount(modes); i++) {
 | 
						|
            int cb;
 | 
						|
            modeRef = (CFDictionaryRef) CFArrayGetValueAtIndex(modes, i);
 | 
						|
 | 
						|
            /* Skip modes that are not usable on the current display or have a
 | 
						|
               different pixel encoding than the current mode. */
 | 
						|
            if (((unsigned long) getDictLong(modeRef, kCGDisplayIOFlags) &
 | 
						|
                 kDisplayModeUsableFlags) != kDisplayModeUsableFlags)
 | 
						|
                continue;
 | 
						|
            if (getDictLong(modeRef, kCGDisplayBitsPerPixel) != curBpp)
 | 
						|
                continue;
 | 
						|
 | 
						|
            QuartzRandRGetModeInfo(modeRef, &modeInfo);
 | 
						|
            modeInfo.ref = (void *)modeRef;
 | 
						|
            cb = callback(pScreen, &modeInfo, data);
 | 
						|
            if (cb == CALLBACK_CONTINUE)
 | 
						|
                retval = TRUE;
 | 
						|
            else if (cb == CALLBACK_SUCCESS)
 | 
						|
                return TRUE;
 | 
						|
            else if (cb == CALLBACK_ERROR)
 | 
						|
                return FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    switch(callback(pScreen, &pQuartzScreen->rootlessMode, data)) {
 | 
						|
        case CALLBACK_SUCCESS:
 | 
						|
            return TRUE;
 | 
						|
        case CALLBACK_ERROR:
 | 
						|
            return FALSE;
 | 
						|
        case CALLBACK_CONTINUE:
 | 
						|
            retval = TRUE;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    switch(callback(pScreen, &pQuartzScreen->fullscreenMode, data)) {
 | 
						|
        case CALLBACK_SUCCESS:
 | 
						|
            return TRUE;
 | 
						|
        case CALLBACK_ERROR:
 | 
						|
            return FALSE;
 | 
						|
        case CALLBACK_CONTINUE:
 | 
						|
            retval = TRUE;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return retval;
 | 
						|
}
 | 
						|
 | 
						|
#else /* we have the new CG APIs from Snow Leopard */
 | 
						|
 | 
						|
static void QuartzRandRGetModeInfo (CGDisplayModeRef modeRef,
 | 
						|
                                    QuartzModeInfoPtr pMode) {
 | 
						|
    pMode->width = CGDisplayModeGetWidth(modeRef);
 | 
						|
    pMode->height = CGDisplayModeGetHeight(modeRef);
 | 
						|
    pMode->refresh = (int) (CGDisplayModeGetRefreshRate(modeRef) + 0.5);
 | 
						|
    if (pMode->refresh == 0)
 | 
						|
        pMode->refresh = DEFAULT_REFRESH;
 | 
						|
    pMode->ref = NULL;
 | 
						|
    pMode->pSize = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRCopyCurrentModeInfo (CGDirectDisplayID screenId,
 | 
						|
                                            QuartzModeInfoPtr pMode) {
 | 
						|
    CGDisplayModeRef curModeRef = CGDisplayCopyDisplayMode(screenId);
 | 
						|
    if (!curModeRef)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    QuartzRandRGetModeInfo(curModeRef, pMode);
 | 
						|
    pMode->ref = curModeRef;
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRSetCGMode (CGDirectDisplayID screenId,
 | 
						|
                                QuartzModeInfoPtr pMode) {
 | 
						|
    CGDisplayModeRef modeRef = (CGDisplayModeRef) pMode->ref;
 | 
						|
    if (!modeRef)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    return (CGDisplaySetDisplayMode(screenId, modeRef, NULL) == kCGErrorSuccess);
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandREnumerateModes (ScreenPtr pScreen,
 | 
						|
                                       QuartzModeCallback callback,
 | 
						|
                                       void *data) {
 | 
						|
    Bool retval = FALSE;
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
 | 
						|
    /* Just an 800x600 fallback if we have no attached heads */
 | 
						|
    if(pQuartzScreen->displayIDs) {
 | 
						|
        CGDisplayModeRef curModeRef, modeRef;
 | 
						|
        CFStringRef curPixelEnc, pixelEnc;
 | 
						|
        CFComparisonResult pixelEncEqual;
 | 
						|
        CFArrayRef modes;
 | 
						|
        QuartzModeInfo modeInfo;
 | 
						|
        int i;
 | 
						|
        CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0];
 | 
						|
 | 
						|
        curModeRef = CGDisplayCopyDisplayMode(screenId);
 | 
						|
        if (!curModeRef)
 | 
						|
            return FALSE;
 | 
						|
        curPixelEnc = CGDisplayModeCopyPixelEncoding(curModeRef);
 | 
						|
        CGDisplayModeRelease(curModeRef);
 | 
						|
 | 
						|
        modes = CGDisplayCopyAllDisplayModes(screenId, NULL);
 | 
						|
        if (!modes) {
 | 
						|
            CFRelease(curPixelEnc);
 | 
						|
            return FALSE;
 | 
						|
        }
 | 
						|
        for (i = 0; i < CFArrayGetCount(modes); i++) {
 | 
						|
            int cb;
 | 
						|
            modeRef = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
 | 
						|
 | 
						|
            /* Skip modes that are not usable on the current display or have a
 | 
						|
               different pixel encoding than the current mode. */
 | 
						|
            if ((CGDisplayModeGetIOFlags(modeRef) & kDisplayModeUsableFlags) !=
 | 
						|
                kDisplayModeUsableFlags)
 | 
						|
                continue;
 | 
						|
            pixelEnc = CGDisplayModeCopyPixelEncoding(modeRef);
 | 
						|
            pixelEncEqual = CFStringCompare(pixelEnc, curPixelEnc, 0);
 | 
						|
            CFRelease(pixelEnc);
 | 
						|
            if (pixelEncEqual != kCFCompareEqualTo)
 | 
						|
                continue;
 | 
						|
 | 
						|
            QuartzRandRGetModeInfo(modeRef, &modeInfo);
 | 
						|
            modeInfo.ref = modeRef;
 | 
						|
            cb = callback(pScreen, &modeInfo, data);
 | 
						|
            if (cb == CALLBACK_CONTINUE) {
 | 
						|
                retval = TRUE;
 | 
						|
            } else if (cb == CALLBACK_SUCCESS) {
 | 
						|
                CFRelease(modes);
 | 
						|
                CFRelease(curPixelEnc);
 | 
						|
                return TRUE;
 | 
						|
            } else if (cb == CALLBACK_ERROR) {
 | 
						|
                CFRelease(modes);
 | 
						|
                CFRelease(curPixelEnc);
 | 
						|
                return FALSE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        CFRelease(modes);
 | 
						|
        CFRelease(curPixelEnc);
 | 
						|
    }
 | 
						|
 | 
						|
    switch(callback(pScreen, &pQuartzScreen->rootlessMode, data)) {
 | 
						|
        case CALLBACK_SUCCESS:
 | 
						|
            return TRUE;
 | 
						|
        case CALLBACK_ERROR:
 | 
						|
            return FALSE;
 | 
						|
        case CALLBACK_CONTINUE:
 | 
						|
            retval = TRUE;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    switch(callback(pScreen, &pQuartzScreen->fullscreenMode, data)) {
 | 
						|
        case CALLBACK_SUCCESS:
 | 
						|
            return TRUE;
 | 
						|
        case CALLBACK_ERROR:
 | 
						|
            return FALSE;
 | 
						|
        case CALLBACK_CONTINUE:
 | 
						|
            retval = TRUE;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return retval;
 | 
						|
}
 | 
						|
 | 
						|
#endif  /* Snow Leopard CoreGraphics APIs */
 | 
						|
 | 
						|
 | 
						|
static Bool QuartzRandRModesEqual (QuartzModeInfoPtr pMode1,
 | 
						|
                                   QuartzModeInfoPtr pMode2) {
 | 
						|
    return (pMode1->width == pMode2->width) &&
 | 
						|
           (pMode1->height == pMode2->height) &&
 | 
						|
           (pMode1->refresh == pMode2->refresh);
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRRegisterMode (ScreenPtr pScreen,
 | 
						|
                                     QuartzModeInfoPtr pMode) {
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
    Bool isCurrentMode = QuartzRandRModesEqual(&pQuartzScreen->currentMode, pMode);
 | 
						|
 | 
						|
    /* TODO: DPI */
 | 
						|
    pMode->pSize = RRRegisterSize(pScreen, pMode->width, pMode->height, pScreen->mmWidth, pScreen->mmHeight);
 | 
						|
    if (pMode->pSize) {
 | 
						|
        //DEBUG_LOG("registering: %d x %d @ %d %s\n", (int)pMode->width, (int)pMode->height, (int)pMode->refresh, isCurrentMode ? "*" : "");
 | 
						|
        RRRegisterRate(pScreen, pMode->pSize, pMode->refresh);
 | 
						|
 | 
						|
        if (isCurrentMode)
 | 
						|
            RRSetCurrentConfig(pScreen, RR_Rotate_0, pMode->refresh, pMode->pSize);
 | 
						|
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static int QuartzRandRRegisterModeCallback (ScreenPtr pScreen,
 | 
						|
                                        QuartzModeInfoPtr pMode,
 | 
						|
                                        void *data __unused) {
 | 
						|
    if(QuartzRandRRegisterMode(pScreen, pMode)) {
 | 
						|
        return CALLBACK_CONTINUE;
 | 
						|
    } else {
 | 
						|
        return CALLBACK_ERROR;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRSetMode(ScreenPtr pScreen, QuartzModeInfoPtr pMode, BOOL doRegister) {
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
    Bool captureDisplay = (pMode->refresh != FAKE_REFRESH_FULLSCREEN && pMode->refresh != FAKE_REFRESH_ROOTLESS);
 | 
						|
    CGDirectDisplayID screenId;
 | 
						|
 | 
						|
    if(pQuartzScreen->displayIDs == NULL)
 | 
						|
        return FALSE;
 | 
						|
 | 
						|
    screenId = pQuartzScreen->displayIDs[0];
 | 
						|
    if(XQuartzShieldingWindowLevel == 0 && captureDisplay) {
 | 
						|
        if(!X11ApplicationCanEnterRandR())
 | 
						|
            return FALSE;
 | 
						|
        CGCaptureAllDisplays();
 | 
						|
        XQuartzShieldingWindowLevel = CGShieldingWindowLevel(); // 2147483630
 | 
						|
        DEBUG_LOG("Display captured.  ShieldWindowID: %u, Shield level: %d\n",
 | 
						|
                  CGShieldingWindowID(screenId), XQuartzShieldingWindowLevel);
 | 
						|
    }
 | 
						|
 | 
						|
    if (pQuartzScreen->currentMode.ref && CFEqual(pMode->ref, pQuartzScreen->currentMode.ref)) {
 | 
						|
        DEBUG_LOG("Requested RandR resolution matches current CG mode\n");
 | 
						|
    } if (QuartzRandRSetCGMode(screenId, pMode)) {
 | 
						|
        ignore_next_fake_mode_update = TRUE;
 | 
						|
    } else {
 | 
						|
        DEBUG_LOG("Error while requesting CG resolution change.\n");
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    /* If the client requested the fake rootless mode, switch to rootless.
 | 
						|
     * Otherwise, force fullscreen mode.
 | 
						|
     */
 | 
						|
    QuartzSetRootless(pMode->refresh == FAKE_REFRESH_ROOTLESS);
 | 
						|
    if (pMode->refresh != FAKE_REFRESH_ROOTLESS) {
 | 
						|
        QuartzShowFullscreen(TRUE);
 | 
						|
    }
 | 
						|
 | 
						|
    if(pQuartzScreen->currentMode.ref)
 | 
						|
        CFRelease(pQuartzScreen->currentMode.ref);
 | 
						|
    pQuartzScreen->currentMode = *pMode;
 | 
						|
    if(pQuartzScreen->currentMode.ref)
 | 
						|
        CFRetain(pQuartzScreen->currentMode.ref);
 | 
						|
    
 | 
						|
    if(XQuartzShieldingWindowLevel != 0 && !captureDisplay) {
 | 
						|
        CGReleaseAllDisplays();
 | 
						|
        XQuartzShieldingWindowLevel = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static int QuartzRandRSetModeCallback (ScreenPtr pScreen,
 | 
						|
                                       QuartzModeInfoPtr pMode,
 | 
						|
                                       void *data) {
 | 
						|
    QuartzModeInfoPtr pReqMode = (QuartzModeInfoPtr) data;
 | 
						|
	
 | 
						|
    if (!QuartzRandRModesEqual(pMode, pReqMode))
 | 
						|
        return CALLBACK_CONTINUE;  /* continue enumeration */
 | 
						|
 | 
						|
    DEBUG_LOG("Found a match for requested RandR resolution (%dx%d@%d).\n", (int)pMode->width, (int)pMode->height, (int)pMode->refresh);
 | 
						|
 | 
						|
    if(QuartzRandRSetMode(pScreen, pMode, FALSE))
 | 
						|
        return CALLBACK_SUCCESS;
 | 
						|
    else
 | 
						|
        return CALLBACK_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) {
 | 
						|
    *rotations = RR_Rotate_0;  /* TODO: support rotation */
 | 
						|
 | 
						|
    return QuartzRandREnumerateModes(pScreen, QuartzRandRRegisterModeCallback, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static Bool QuartzRandRSetConfig (ScreenPtr           pScreen,
 | 
						|
                                  Rotation            randr,
 | 
						|
                                  int                 rate,
 | 
						|
                                  RRScreenSizePtr     pSize) {
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
    QuartzModeInfo reqMode;
 | 
						|
 | 
						|
    reqMode.width = pSize->width;
 | 
						|
    reqMode.height = pSize->height;
 | 
						|
    reqMode.refresh = rate;
 | 
						|
 | 
						|
    /* Do not switch modes if requested mode is equal to current mode. */
 | 
						|
    if (QuartzRandRModesEqual(&reqMode, &pQuartzScreen->currentMode))
 | 
						|
        return TRUE;
 | 
						|
        
 | 
						|
    if (QuartzRandREnumerateModes(pScreen, QuartzRandRSetModeCallback, &reqMode)) {
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    
 | 
						|
    DEBUG_LOG("Unable to find a matching config: %d x %d @ %d\n", (int)reqMode.width, (int)reqMode.height, (int)reqMode.refresh);
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static Bool _QuartzRandRUpdateFakeModes (ScreenPtr pScreen) {
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
    QuartzModeInfo activeMode;
 | 
						|
 | 
						|
    if(pQuartzScreen->displayCount > 0) {
 | 
						|
        if(!QuartzRandRCopyCurrentModeInfo(pQuartzScreen->displayIDs[0], &activeMode)) {
 | 
						|
            ErrorF("Unable to determine current display mode.\n");
 | 
						|
            return FALSE;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        memset(&activeMode, 0, sizeof(activeMode));
 | 
						|
        activeMode.width = 800;
 | 
						|
        activeMode.height = 600;
 | 
						|
        activeMode.refresh = 60;
 | 
						|
    }
 | 
						|
 | 
						|
    if(pQuartzScreen->fullscreenMode.ref)
 | 
						|
        CFRelease(pQuartzScreen->fullscreenMode.ref);
 | 
						|
    if(pQuartzScreen->currentMode.ref)
 | 
						|
        CFRelease(pQuartzScreen->currentMode.ref);
 | 
						|
 | 
						|
    if(pQuartzScreen->displayCount > 1) {
 | 
						|
        activeMode.width = pScreen->width;
 | 
						|
        activeMode.height = pScreen->height;
 | 
						|
        if(XQuartzIsRootless)
 | 
						|
            activeMode.height += aquaMenuBarHeight;
 | 
						|
    }
 | 
						|
 | 
						|
    pQuartzScreen->fullscreenMode = activeMode; 
 | 
						|
    pQuartzScreen->fullscreenMode.refresh = FAKE_REFRESH_FULLSCREEN;
 | 
						|
 | 
						|
    pQuartzScreen->rootlessMode = activeMode;
 | 
						|
    pQuartzScreen->rootlessMode.refresh = FAKE_REFRESH_ROOTLESS;
 | 
						|
    pQuartzScreen->rootlessMode.height -= aquaMenuBarHeight;
 | 
						|
 | 
						|
    if(XQuartzIsRootless) {
 | 
						|
        pQuartzScreen->currentMode = pQuartzScreen->rootlessMode;
 | 
						|
    } else {
 | 
						|
        pQuartzScreen->currentMode = pQuartzScreen->fullscreenMode;
 | 
						|
    }
 | 
						|
 | 
						|
    /* This extra retain is for currentMode's copy.
 | 
						|
     * fullscreen and rootless share a retain.
 | 
						|
     */
 | 
						|
    if(pQuartzScreen->currentMode.ref)
 | 
						|
        CFRetain(pQuartzScreen->currentMode.ref);
 | 
						|
    
 | 
						|
    DEBUG_LOG("rootlessMode: %d x %d\n", (int)pQuartzScreen->rootlessMode.width, (int)pQuartzScreen->rootlessMode.height);
 | 
						|
    DEBUG_LOG("fullscreenMode: %d x %d\n", (int)pQuartzScreen->fullscreenMode.width, (int)pQuartzScreen->fullscreenMode.height);
 | 
						|
    DEBUG_LOG("currentMode: %d x %d\n", (int)pQuartzScreen->currentMode.width, (int)pQuartzScreen->currentMode.height);
 | 
						|
    
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool QuartzRandRUpdateFakeModes (BOOL force_update) {
 | 
						|
    ScreenPtr pScreen = screenInfo.screens[0];
 | 
						|
    
 | 
						|
    if(ignore_next_fake_mode_update) {
 | 
						|
        DEBUG_LOG("Ignoring update request caused by RandR resolution change.\n");
 | 
						|
        ignore_next_fake_mode_update = FALSE;
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if(!_QuartzRandRUpdateFakeModes(pScreen))
 | 
						|
        return FALSE;
 | 
						|
    
 | 
						|
    if(force_update)
 | 
						|
        RRGetInfo(pScreen, TRUE);
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Bool QuartzRandRInit (ScreenPtr pScreen) {
 | 
						|
    rrScrPrivPtr    pScrPriv;
 | 
						|
    
 | 
						|
    if (!RRScreenInit (pScreen)) return FALSE;
 | 
						|
    if (!_QuartzRandRUpdateFakeModes (pScreen)) return FALSE;
 | 
						|
 | 
						|
    pScrPriv = rrGetScrPriv(pScreen);
 | 
						|
    pScrPriv->rrGetInfo = QuartzRandRGetInfo;
 | 
						|
    pScrPriv->rrSetConfig = QuartzRandRSetConfig;
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void QuartzRandRSetFakeRootless (void) {
 | 
						|
    int i;
 | 
						|
    
 | 
						|
    DEBUG_LOG("QuartzRandRSetFakeRootless called.\n");
 | 
						|
    
 | 
						|
    for (i=0; i < screenInfo.numScreens; i++) {
 | 
						|
        ScreenPtr pScreen = screenInfo.screens[i];
 | 
						|
        QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
 | 
						|
        QuartzRandRSetMode(pScreen, &pQuartzScreen->rootlessMode, TRUE);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void QuartzRandRSetFakeFullscreen (BOOL state) {
 | 
						|
    int i;
 | 
						|
 | 
						|
    DEBUG_LOG("QuartzRandRSetFakeFullscreen called.\n");
 | 
						|
    
 | 
						|
    for (i=0; i < screenInfo.numScreens; i++) {
 | 
						|
        ScreenPtr pScreen = screenInfo.screens[i];
 | 
						|
        QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
 | 
						|
        QuartzRandRSetMode(pScreen, &pQuartzScreen->fullscreenMode, TRUE);
 | 
						|
    }
 | 
						|
    
 | 
						|
    QuartzShowFullscreen(state);
 | 
						|
}
 | 
						|
 | 
						|
/* Toggle fullscreen mode.  If "fake" fullscreen is the current mode,
 | 
						|
 * this will just show/hide the X11 windows.  If we are in a RandR fullscreen
 | 
						|
 * mode, this will toggles us to the default fake mode and hide windows if
 | 
						|
 * it is fullscreen
 | 
						|
 */
 | 
						|
void QuartzRandRToggleFullscreen (void) {
 | 
						|
    ScreenPtr pScreen = screenInfo.screens[0];
 | 
						|
    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
 | 
						|
 | 
						|
    if (pQuartzScreen->currentMode.ref == NULL) {
 | 
						|
        ErrorF("Ignoring QuartzRandRToggleFullscreen because don't have a current mode set.\n");
 | 
						|
    } else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_ROOTLESS) {
 | 
						|
        ErrorF("Ignoring QuartzRandRToggleFullscreen because we are in rootless mode.\n");
 | 
						|
    } else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_FULLSCREEN) {
 | 
						|
        /* Legacy fullscreen mode.  Hide/Show */
 | 
						|
        QuartzShowFullscreen(!XQuartzFullscreenVisible);
 | 
						|
    } else {
 | 
						|
        /* RandR fullscreen mode.  Return to default mode and hide if it is fullscreen. */
 | 
						|
        if(XQuartzRootlessDefault) {
 | 
						|
            QuartzRandRSetFakeRootless();
 | 
						|
        } else {
 | 
						|
            QuartzRandRSetFakeFullscreen(FALSE);
 | 
						|
        }
 | 
						|
    }    
 | 
						|
}
 |