Basic implementation of XRandR
Hi, the attached patch series contains a basic implementation of XRandR functionality and some related fixes: The first patch removes some dead code I noticed, mainly orphaned forward declarations and unused global variables. The second patch makes Xinerama report the actual screen resolution instead of subtracting the size of the global menu bar. Wine uses Xinerama to determine the current resolution and expects to be able to switch back to that resolution via XRandR. The adjusted resolution is still used by XQuartz internally, and I verified that window placement still works correctly, i.e. it's still impossible to move windows below the menu bar. However, I'm not completely sure my approach here is correct. The third patch contains the routines for enumerating and setting screen modes. By commenting out the definition of "USE_DEPRECATED_API" in quartzRandR.h, you can enable the use of the new CoreGraphics API introduced in MacOS 10.6. I was unsure whether XQuartz is supposed to be compatible with earlier versions of MacOS, so I left both code paths in. The fourth and final patch removes the FAKE_RANDR code to get rid of some preprocessor conditionals. I haven't done any X11 development before, so the patches might not be ready for inclusion yet. Please let me know what needs to be done to make them acceptable. Regards, Jan
From 8e6bf23ec7068524f27f399aa1d9bcc7b5f41abd Mon Sep 17 00:00:00 2001 From: Jan Hauffa <hauffa@in.tum.de> Date: Sun, 13 Jun 2010 18:42:48 +0200 Subject: [PATCH 1/4] XQuartz: Remove some dead code.
Signed-off-by: Jan Hauffa <hauffa@in.tum.de> --- hw/xquartz/quartz.c | 4 ---- hw/xquartz/quartzCocoa.m | 11 ----------- hw/xquartz/quartzCommon.h | 15 --------------- 3 files changed, 0 insertions(+), 30 deletions(-) diff --git a/hw/xquartz/quartz.c b/hw/xquartz/quartz.c index 36d18eb..981a90f 100644 --- a/hw/xquartz/quartz.c +++ b/hw/xquartz/quartz.c @@ -67,12 +67,8 @@ #define FAKE_RANDR 1 // Shared global variables for Quartz modes -int quartzEventWriteFD = -1; int quartzUseSysBeep = 0; -int quartzUseAGL = 1; -int quartzEnableKeyEquivalents = 1; int quartzServerVisible = FALSE; -int quartzServerQuitting = FALSE; static int quartzScreenKeyIndex; DevPrivateKey quartzScreenKey = &quartzScreenKeyIndex; int aquaMenuBarHeight = 0; diff --git a/hw/xquartz/quartzCocoa.m b/hw/xquartz/quartzCocoa.m index 4501472..54c900d 100644 --- a/hw/xquartz/quartzCocoa.m +++ b/hw/xquartz/quartzCocoa.m @@ -44,17 +44,6 @@ #include "darwin.h" /* - * QuartzFSUseQDCursor - * Return whether the screen should use a QuickDraw cursor. - */ -int QuartzFSUseQDCursor( - int depth) // screen depth -{ - return TRUE; -} - - -/* * QuartzBlockHandler * Clean out any autoreleased objects. */ diff --git a/hw/xquartz/quartzCommon.h b/hw/xquartz/quartzCommon.h index 8ab70f2..a80b0b8 100644 --- a/hw/xquartz/quartzCommon.h +++ b/hw/xquartz/quartzCommon.h @@ -51,34 +51,19 @@ typedef struct { #define QUARTZ_PRIV(pScreen) \ ((QuartzScreenPtr)dixLookupPrivate(&pScreen->devPrivates, quartzScreenKey)) -// Data stored at startup for Cocoa front end -extern int quartzEventWriteFD; - // User preferences used by Quartz modes extern int quartzUseSysBeep; -extern int focusOnNewWindow; -extern int quartzUseAGL; -extern int quartzEnableKeyEquivalents; extern int quartzFullscreenDisableHotkeys; extern int quartzOptionSendsAlt; // Other shared data extern int quartzServerVisible; -extern int quartzServerQuitting; extern DevPrivateKey quartzScreenKey; extern int aquaMenuBarHeight; // Name of GLX bundle for native OpenGL extern const char *quartzOpenGLBundle; -void QuartzReadPreferences(void); -void QuartzMessageMainThread(unsigned msg, void *data, unsigned length); -void QuartzMessageServerThread(int type, int argc, ...); -void QuartzSetWindowMenu(int nitems, const char **items, - const char *shortcuts); -void QuartzFSCapture(void); -void QuartzFSRelease(void); -int QuartzFSUseQDCursor(int depth); void QuartzBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadmask); void QuartzWakeupHandler(pointer blockData, int result, pointer pReadmask); -- 1.6.4.4
From 0cc700bd66a81320eb9743fc27d687186435bf75 Mon Sep 17 00:00:00 2001 From: Jan Hauffa <hauffa@in.tum.de> Date: Sun, 13 Jun 2010 18:46:46 +0200 Subject: [PATCH 2/4] XQuartz: Make PseudoramiX report the actual screen resolution.
Before changing the resolution via RandR, Wine queries Xinerama for the current screen size. Without this patch, the size of the top menu bar is subtracted from the reported size, and an attempt to restore the original resolution will fail. This patch makes Xinerama report the actual resolution; the modified size is still used internally. Signed-off-by: Jan Hauffa <hauffa@in.tum.de> --- hw/xquartz/xpr/xprScreen.c | 12 +++++------- 1 files changed, 5 insertions(+), 7 deletions(-) diff --git a/hw/xquartz/xpr/xprScreen.c b/hw/xquartz/xpr/xprScreen.c index d574721..c050969 100644 --- a/hw/xquartz/xpr/xprScreen.c +++ b/hw/xquartz/xpr/xprScreen.c @@ -146,7 +146,7 @@ displayAtIndex(int index) * Return the bounds of a particular display. */ static CGRect -displayScreenBounds(CGDirectDisplayID id) +displayScreenBounds(CGDirectDisplayID id, Bool excludeMenuBar) { CGRect frame; @@ -157,7 +157,7 @@ displayScreenBounds(CGDirectDisplayID id) (int)frame.origin.x, (int)frame.origin.y); /* Remove menubar to help standard X11 window managers. */ - if (quartzEnableRootless && + if (excludeMenuBar && quartzEnableRootless && frame.origin.x == 0 && frame.origin.y == 0) { frame.origin.y += aquaMenuBarHeight; frame.size.height -= aquaMenuBarHeight; @@ -203,7 +203,7 @@ xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height) /* Get the union of all screens */ for (i = 0; i < displayCount; i++) { CGDirectDisplayID dpy = displayList[i]; - frame = displayScreenBounds(dpy); + frame = displayScreenBounds(dpy, TRUE); unionRect = CGRectUnion(unionRect, frame); } @@ -221,9 +221,7 @@ xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height) { CGDirectDisplayID dpy = displayList[i]; - frame = displayScreenBounds(dpy); - frame.origin.x -= unionRect.origin.x; - frame.origin.y -= unionRect.origin.y; + frame = displayScreenBounds(dpy, FALSE); DEBUG_LOG(" placed at X11 coordinate (%d,%d).\n", (int)frame.origin.x, (int)frame.origin.y); @@ -337,7 +335,7 @@ xprAddScreen(int index, ScreenPtr pScreen) dpy = displayAtIndex(index); - frame = displayScreenBounds(dpy); + frame = displayScreenBounds(dpy, TRUE); dfb->x = frame.origin.x; dfb->y = frame.origin.y; -- 1.6.4.4
From 9d48ea7390c42611c9b6c38feaf9e858bc85a9a0 Mon Sep 17 00:00:00 2001 From: Jan Hauffa <hauffa@in.tum.de> Date: Sun, 13 Jun 2010 19:36:57 +0200 Subject: [PATCH 3/4] XQuartz: Implement basic RandR functionality.
Querying and changing of resolution and refresh rate is supported, rotation is not implemented yet. Signed-off-by: Jan Hauffa <hauffa@in.tum.de> --- hw/xquartz/Makefile.am | 2 + hw/xquartz/quartz.c | 104 +++--------- hw/xquartz/quartz.h | 3 +- hw/xquartz/quartzCommon.h | 3 + hw/xquartz/quartzRandR.c | 394 ++++++++++++++++++++++++++++++++++++++++++++ hw/xquartz/quartzRandR.h | 37 ++++ hw/xquartz/xpr/xprScreen.c | 6 +- 7 files changed, 469 insertions(+), 80 deletions(-) create mode 100644 hw/xquartz/quartzRandR.c create mode 100644 hw/xquartz/quartzRandR.h diff --git a/hw/xquartz/Makefile.am b/hw/xquartz/Makefile.am index 96b139f..721d272 100644 --- a/hw/xquartz/Makefile.am +++ b/hw/xquartz/Makefile.am @@ -34,6 +34,7 @@ libXquartz_la_SOURCES = \ quartzCocoa.m \ quartzKeyboard.c \ quartzStartup.c \ + quartzRandR.c \ threadSafety.c EXTRA_DIST = \ @@ -49,6 +50,7 @@ EXTRA_DIST = \ quartzAudio.h \ quartzCommon.h \ quartzKeyboard.h \ + quartzRandR.h \ sanitizedCarbon.h \ sanitizedCocoa.h \ threadSafety.h diff --git a/hw/xquartz/quartz.c b/hw/xquartz/quartz.c index 981a90f..eb9d030 100644 --- a/hw/xquartz/quartz.c +++ b/hw/xquartz/quartz.c @@ -35,6 +35,7 @@ #endif #include "quartzCommon.h" +#include "quartzRandR.h" #include "inputstr.h" #include "quartz.h" #include "darwin.h" @@ -46,7 +47,6 @@ #include "X11Application.h" #include <X11/extensions/applewmconst.h> -#include <X11/extensions/randr.h> // X headers #include "scrnintstr.h" @@ -56,6 +56,8 @@ #include "mi.h" // System headers +#include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -64,8 +66,6 @@ #include <rootlessCommon.h> #include <Xplugin.h> -#define FAKE_RANDR 1 - // Shared global variables for Quartz modes int quartzUseSysBeep = 0; int quartzServerVisible = FALSE; @@ -77,30 +77,6 @@ const char *quartzOpenGLBundle = NULL; int quartzFullscreenDisableHotkeys = TRUE; int quartzOptionSendsAlt = FALSE; -#if defined(RANDR) && !defined(FAKE_RANDR) -Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { - return FALSE; -} - -Bool QuartzRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) { - return FALSE; -} - -Bool QuartzRandRInit (ScreenPtr pScreen) { - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = QuartzRandRGetInfo; - pScrPriv->rrSetConfig = QuartzRandRSetConfig; - return TRUE; -} -#endif - /* =========================================================================== @@ -144,6 +120,13 @@ Bool QuartzSetupScreen( if (! quartzProcs->InitCursor(pScreen)) return FALSE; +#if defined(RANDR) && !defined(FAKE_RANDR) + if(!QuartzRandRInit(pScreen)) { + DEBUG_LOG("Failed to init RandR extension.\n"); + return FALSE; + } +#endif + return TRUE; } @@ -163,11 +146,6 @@ void QuartzInitOutput( FatalError("Could not register block and wakeup handlers."); } -#if defined(RANDR) && !defined(FAKE_RANDR) - if(!QuartzRandRInit(pScreen)) - FatalError("Failed to init RandR extension.\n"); -#endif - // Do display mode specific initialization quartzProcs->DisplayInit(); } @@ -189,50 +167,6 @@ void QuartzInitInput( } -#ifdef FAKE_RANDR - -static const int padlength[4] = {0, 3, 2, 1}; - -static void -RREditConnectionInfo (ScreenPtr pScreen) -{ - xConnSetup *connSetup; - char *vendor; - xPixmapFormat *formats; - xWindowRoot *root; - xDepth *depth; - xVisualType *visual; - int screen = 0; - int d; - - connSetup = (xConnSetup *) ConnectionInfo; - vendor = (char *) connSetup + sizeof (xConnSetup); - formats = (xPixmapFormat *) ((char *) vendor + - connSetup->nbytesVendor + - padlength[connSetup->nbytesVendor & 3]); - root = (xWindowRoot *) ((char *) formats + - sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); - while (screen != pScreen->myNum) - { - depth = (xDepth *) ((char *) root + - sizeof (xWindowRoot)); - for (d = 0; d < root->nDepths; d++) - { - visual = (xVisualType *) ((char *) depth + - sizeof (xDepth)); - depth = (xDepth *) ((char *) visual + - depth->nVisuals * sizeof (xVisualType)); - } - root = (xWindowRoot *) ((char *) depth); - screen++; - } - root->pixWidth = pScreen->width; - root->pixHeight = pScreen->height; - root->mmWidth = pScreen->mmWidth; - root->mmHeight = pScreen->mmHeight; -} -#endif - void QuartzUpdateScreens(void) { ScreenPtr pScreen; WindowPtr pRoot; @@ -253,7 +187,7 @@ void QuartzUpdateScreens(void) { pScreen = screenInfo.screens[0]; PseudoramiXResetScreens(); - quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height); + quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height, pScreen); dixScreenOrigins[pScreen->myNum].x = x; dixScreenOrigins[pScreen->myNum].y = y; @@ -442,3 +376,19 @@ void QuartzSpaceChanged(uint32_t space_id) { /* Do something special here, so we don't depend on quartz-wm for spaces to work... */ DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id); } + +/* + * QuartzCopyDisplayIDs + * Associate an X11 screen with one or more CoreGraphics display IDs by copying + * the list into a private array. Free the previously copied array, if present. + */ +void QuartzCopyDisplayIDs(ScreenPtr pScreen, + int displayCount, CGDirectDisplayID *displayIDs) { + QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); + int size = displayCount * sizeof(CGDirectDisplayID); + + free(pQuartzScreen->displayIDs); + pQuartzScreen->displayIDs = malloc(size); + memcpy(pQuartzScreen->displayIDs, displayIDs, size); + pQuartzScreen->displayCount = displayCount; +} diff --git a/hw/xquartz/quartz.h b/hw/xquartz/quartz.h index b1a3f31..1b924e7 100644 --- a/hw/xquartz/quartz.h +++ b/hw/xquartz/quartz.h @@ -62,7 +62,8 @@ typedef void (*ResumeScreenProc)(ScreenPtr pScreen); /* * Screen state change support */ -typedef void (*AddPseudoramiXScreensProc)(int *x, int *y, int *width, int *height); +typedef void (*AddPseudoramiXScreensProc) + (int *x, int *y, int *width, int *height, ScreenPtr pScreen); typedef void (*UpdateScreenProc)(ScreenPtr pScreen); /* diff --git a/hw/xquartz/quartzCommon.h b/hw/xquartz/quartzCommon.h index a80b0b8..aeccf8b 100644 --- a/hw/xquartz/quartzCommon.h +++ b/hw/xquartz/quartzCommon.h @@ -51,6 +51,9 @@ typedef struct { #define QUARTZ_PRIV(pScreen) \ ((QuartzScreenPtr)dixLookupPrivate(&pScreen->devPrivates, quartzScreenKey)) +void QuartzCopyDisplayIDs(ScreenPtr pScreen, + int displayCount, CGDirectDisplayID *displayIDs); + // User preferences used by Quartz modes extern int quartzUseSysBeep; extern int quartzFullscreenDisableHotkeys; diff --git a/hw/xquartz/quartzRandR.c b/hw/xquartz/quartzRandR.c new file mode 100644 index 0000000..6747752 --- /dev/null +++ b/hw/xquartz/quartzRandR.c @@ -0,0 +1,394 @@ +/* + * + * Quartz-specific support for the XRandR extension + * + * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons, + * 2010 Jan Hauffa. + * 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" + +#if defined(FAKE_RANDR) +#include "scrnintstr.h" +#include "windowstr.h" +#else +#include <X11/extensions/randr.h> +#include <randrstr.h> +#include <IOKit/graphics/IOGraphicsTypes.h> +#endif + + +#if defined(FAKE_RANDR) + +static const int padlength[4] = {0, 3, 2, 1}; + +void +RREditConnectionInfo (ScreenPtr pScreen) +{ + xConnSetup *connSetup; + char *vendor; + xPixmapFormat *formats; + xWindowRoot *root; + xDepth *depth; + xVisualType *visual; + int screen = 0; + int d; + + connSetup = (xConnSetup *) ConnectionInfo; + vendor = (char *) connSetup + sizeof (xConnSetup); + formats = (xPixmapFormat *) ((char *) vendor + + connSetup->nbytesVendor + + padlength[connSetup->nbytesVendor & 3]); + root = (xWindowRoot *) ((char *) formats + + sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); + while (screen != pScreen->myNum) + { + depth = (xDepth *) ((char *) root + + sizeof (xWindowRoot)); + for (d = 0; d < root->nDepths; d++) + { + visual = (xVisualType *) ((char *) depth + + sizeof (xDepth)); + depth = (xDepth *) ((char *) visual + + depth->nVisuals * sizeof (xVisualType)); + } + root = (xWindowRoot *) ((char *) depth); + screen++; + } + root->pixWidth = pScreen->width; + root->pixHeight = pScreen->height; + root->mmWidth = pScreen->mmWidth; + root->mmHeight = pScreen->mmHeight; +} + +#else /* defined(FAKE_RANDR) */ + +#define DEFAULT_REFRESH 60 +#define kDisplayModeUsableFlags (kDisplayModeValidFlag | kDisplayModeSafeFlag) + +typedef struct { + size_t width, height; + int refresh; + const void *ref; +} QuartzModeInfo, *QuartzModeInfoPtr; + +typedef Bool (*QuartzModeCallback) + (ScreenPtr, CGDirectDisplayID, QuartzModeInfoPtr, void *); + + +#if defined(USE_DEPRECATED_CG_API) + +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; +} + +static Bool QuartzRandRGetCurrentModeInfo (CGDirectDisplayID screenId, + QuartzModeInfoPtr pMode) { + CFDictionaryRef curModeRef = CGDisplayCurrentMode(screenId); + if (!curModeRef) + return FALSE; + + QuartzRandRGetModeInfo(curModeRef, pMode); + return TRUE; +} + +static Bool QuartzRandRSetMode (CGDirectDisplayID screenId, + QuartzModeInfoPtr pMode) { + CFDictionaryRef modeRef = (CFDictionaryRef) pMode->ref; + return (CGDisplaySwitchToMode(screenId, modeRef) != kCGErrorSuccess); +} + +static Bool QuartzRandREnumerateModes (ScreenPtr pScreen, + CGDirectDisplayID screenId, + QuartzModeCallback callback, + void *data) { + CFDictionaryRef curModeRef, modeRef; + long curBpp; + CFArrayRef modes; + QuartzModeInfo modeInfo; + int i; + + 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++) { + 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 = modeRef; + if (!callback(pScreen, screenId, &modeInfo, data)) + break; + } + return TRUE; +} + +#else /* defined(USE_DEPRECATED_CG_API) */ + +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; +} + +static Bool QuartzRandRGetCurrentModeInfo (CGDirectDisplayID screenId, + QuartzModeInfoPtr pMode) { + CGDisplayModeRef curModeRef = CGDisplayCopyDisplayMode(screenId); + if (!curModeRef) + return FALSE; + + QuartzRandRGetModeInfo(curModeRef, pMode); + CGDisplayModeRelease(curModeRef); + return TRUE; +} + +static Bool QuartzRandRSetMode (CGDirectDisplayID screenId, + QuartzModeInfoPtr pMode) { + CGDisplayModeRef modeRef = (CGDisplayModeRef) pMode->ref; + if (!modeRef) + return FALSE; + + return (CGDisplaySetDisplayMode(screenId, modeRef, NULL) != + kCGErrorSuccess); +} + +static Bool QuartzRandREnumerateModes (ScreenPtr pScreen, + CGDirectDisplayID screenId, + QuartzModeCallback callback, + void *data) { + CGDisplayModeRef curModeRef, modeRef; + CFStringRef curPixelEnc, pixelEnc; + CFComparisonResult pixelEncEqual; + CFArrayRef modes; + QuartzModeInfo modeInfo; + int i; + + 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++) { + 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; + if (!callback(pScreen, screenId, &modeInfo, data)) + break; + } + CFRelease(modes); + + CFRelease(curPixelEnc); + return TRUE; +} + +#endif /* defined(USE_DEPRECATED_CG_API) */ + + +static Bool QuartzRandRModesEqual (QuartzModeInfoPtr pMode1, + QuartzModeInfoPtr pMode2) { + if (pMode1->width != pMode2->width) + return FALSE; + if (pMode1->height != pMode2->height) + return FALSE; + if (pMode1->refresh != pMode2->refresh) + return FALSE; + return TRUE; +} + +static Bool QuartzRandRGetModeCallback (ScreenPtr pScreen, + CGDirectDisplayID screenId, + QuartzModeInfoPtr pMode, + void *data) { + QuartzModeInfoPtr pCurMode = (QuartzModeInfoPtr) data; + + RRScreenSizePtr pSize = RRRegisterSize(pScreen, + pMode->width, pMode->height, pScreen->mmWidth, pScreen->mmHeight); + if (pSize) { + RRRegisterRate(pScreen, pSize, pMode->refresh); + + if (QuartzRandRModesEqual(pMode, pCurMode)) + RRSetCurrentConfig(pScreen, RR_Rotate_0, pMode->refresh, pSize); + } + return TRUE; +} + +static Bool QuartzRandRSetModeCallback (ScreenPtr pScreen, + CGDirectDisplayID screenId, + QuartzModeInfoPtr pMode, + void *data) { + QuartzModeInfoPtr pReqMode = (QuartzModeInfoPtr) data; + + if (!QuartzRandRModesEqual(pMode, pReqMode)) + return TRUE; /* continue enumeration */ + + return QuartzRandRSetMode(screenId, pMode); +} + +static Bool QuartzRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { + QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); + CGDirectDisplayID screenId; + QuartzModeInfo curMode; + + *rotations = RR_Rotate_0; /* TODO: support rotation */ + + if (pQuartzScreen->displayCount == 0) + return FALSE; + if (pQuartzScreen->displayCount > 1) { + /* RandR operations are not well-defined for an X11 screen spanning + multiple CG displays. Create a single entry for the current virtual + resolution. */ + RRScreenSizePtr pSize = RRRegisterSize(pScreen, pScreen->width, + pScreen->height, pScreen->mmWidth, pScreen->mmHeight); + if (pSize) { + RRRegisterRate(pScreen, pSize, DEFAULT_REFRESH); + RRSetCurrentConfig(pScreen, RR_Rotate_0, DEFAULT_REFRESH, pSize); + } + return TRUE; + } + screenId = pQuartzScreen->displayIDs[0]; + + if (!QuartzRandRGetCurrentModeInfo(screenId, &curMode)) + return FALSE; + return QuartzRandREnumerateModes(pScreen, screenId, + QuartzRandRGetModeCallback, &curMode); +} + +static Bool QuartzRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) { + QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen); + CGDirectDisplayID screenId; + QuartzModeInfo reqMode, curMode; + + if (pQuartzScreen->displayCount == 0) + return FALSE; + if (pQuartzScreen->displayCount > 1) { + /* RandR operations are not well-defined for an X11 screen spanning + multiple CG displays. Do not accept any configuations that differ + from the current configuration. */ + return ((pSize->width == pScreen->width) && + (pSize->height == pScreen->height)); + } + screenId = pQuartzScreen->displayIDs[0]; + + reqMode.width = pSize->width; + reqMode.height = pSize->height; + reqMode.refresh = rate; + + /* Do not switch modes if requested mode is equal to current mode. */ + if (!QuartzRandRGetCurrentModeInfo(screenId, &curMode)) + return FALSE; + if (QuartzRandRModesEqual(&reqMode, &curMode)) + return TRUE; + + return QuartzRandREnumerateModes(pScreen, screenId, + QuartzRandRSetModeCallback, &reqMode); +} + +Bool QuartzRandRInit (ScreenPtr pScreen) { + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = QuartzRandRGetInfo; + pScrPriv->rrSetConfig = QuartzRandRSetConfig; + return TRUE; +} + +#endif /* defined(FAKE_RANDR) */ diff --git a/hw/xquartz/quartzRandR.h b/hw/xquartz/quartzRandR.h new file mode 100644 index 0000000..a190205 --- /dev/null +++ b/hw/xquartz/quartzRandR.h @@ -0,0 +1,37 @@ +/* + * quartzRandR.h + * + * Copyright (c) 2010 Jan Hauffa. + * 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. + */ + +/*define FAKE_RANDR 1*/ +#define USE_DEPRECATED_CG_API 1 + +#if defined(FAKE_RANDR) +void RREditConnectionInfo (ScreenPtr pScreen); +#else +Bool QuartzRandRInit (ScreenPtr pScreen); +#endif diff --git a/hw/xquartz/xpr/xprScreen.c b/hw/xquartz/xpr/xprScreen.c index c050969..f5a4c7a 100644 --- a/hw/xquartz/xpr/xprScreen.c +++ b/hw/xquartz/xpr/xprScreen.c @@ -176,7 +176,7 @@ displayScreenBounds(CGDirectDisplayID id, Bool excludeMenuBar) * with PseudoramiX. */ static void -xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height) +xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height, ScreenPtr pScreen) { CGDisplayCount i, displayCount; CGDirectDisplayID *displayList = NULL; @@ -199,6 +199,7 @@ xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height) if(!displayList) FatalError("Unable to allocate memory for list of displays.\n"); CGGetActiveDisplayList(displayCount, displayList, &displayCount); + QuartzCopyDisplayIDs(pScreen, displayCount, displayList); /* Get the union of all screens */ for (i = 0; i < displayCount; i++) { @@ -334,6 +335,7 @@ xprAddScreen(int index, ScreenPtr pScreen) ErrorF("Warning: noPseudoramiXExtension!\n"); dpy = displayAtIndex(index); + QuartzCopyDisplayIDs(pScreen, 1, &dpy); frame = displayScreenBounds(dpy, TRUE); @@ -344,7 +346,7 @@ xprAddScreen(int index, ScreenPtr pScreen) } else { - xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height); + xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height, pScreen); } /* Passing zero width (pitch) makes miCreateScreenResources set the -- 1.6.4.4
From e48172f4101a911b3cbb141aaf5d0f1c30928ffb Mon Sep 17 00:00:00 2001 From: Jan Hauffa <hauffa@in.tum.de> Date: Sun, 13 Jun 2010 19:44:30 +0200 Subject: [PATCH 4/4] XQuartz: Remove FAKE_RANDR code.
Signed-off-by: Jan Hauffa <hauffa@in.tum.de> --- hw/xquartz/quartz.c | 6 +---- hw/xquartz/quartzRandR.c | 52 ---------------------------------------------- hw/xquartz/quartzRandR.h | 5 ---- 3 files changed, 1 insertions(+), 62 deletions(-) diff --git a/hw/xquartz/quartz.c b/hw/xquartz/quartz.c index eb9d030..749a98b 100644 --- a/hw/xquartz/quartz.c +++ b/hw/xquartz/quartz.c @@ -120,7 +120,7 @@ Bool QuartzSetupScreen( if (! quartzProcs->InitCursor(pScreen)) return FALSE; -#if defined(RANDR) && !defined(FAKE_RANDR) +#if defined(RANDR) if(!QuartzRandRInit(pScreen)) { DEBUG_LOG("Failed to init RandR extension.\n"); return FALSE; @@ -235,10 +235,6 @@ void QuartzUpdateScreens(void) { e.u.configureNotify.borderWidth = wBorderWidth(pRoot); e.u.configureNotify.override = pRoot->overrideRedirect; DeliverEvents(pRoot, &e, 1, NullWindow); - -#ifdef FAKE_RANDR - RREditConnectionInfo(pScreen); -#endif } void QuartzSetFullscreen(Bool state) { diff --git a/hw/xquartz/quartzRandR.c b/hw/xquartz/quartzRandR.c index 6747752..e75bea5 100644 --- a/hw/xquartz/quartzRandR.c +++ b/hw/xquartz/quartzRandR.c @@ -38,60 +38,10 @@ #include "quartzCommon.h" #include "quartzRandR.h" -#if defined(FAKE_RANDR) -#include "scrnintstr.h" -#include "windowstr.h" -#else #include <X11/extensions/randr.h> #include <randrstr.h> #include <IOKit/graphics/IOGraphicsTypes.h> -#endif - - -#if defined(FAKE_RANDR) - -static const int padlength[4] = {0, 3, 2, 1}; - -void -RREditConnectionInfo (ScreenPtr pScreen) -{ - xConnSetup *connSetup; - char *vendor; - xPixmapFormat *formats; - xWindowRoot *root; - xDepth *depth; - xVisualType *visual; - int screen = 0; - int d; - - connSetup = (xConnSetup *) ConnectionInfo; - vendor = (char *) connSetup + sizeof (xConnSetup); - formats = (xPixmapFormat *) ((char *) vendor + - connSetup->nbytesVendor + - padlength[connSetup->nbytesVendor & 3]); - root = (xWindowRoot *) ((char *) formats + - sizeof (xPixmapFormat) * screenInfo.numPixmapFormats); - while (screen != pScreen->myNum) - { - depth = (xDepth *) ((char *) root + - sizeof (xWindowRoot)); - for (d = 0; d < root->nDepths; d++) - { - visual = (xVisualType *) ((char *) depth + - sizeof (xDepth)); - depth = (xDepth *) ((char *) visual + - depth->nVisuals * sizeof (xVisualType)); - } - root = (xWindowRoot *) ((char *) depth); - screen++; - } - root->pixWidth = pScreen->width; - root->pixHeight = pScreen->height; - root->mmWidth = pScreen->mmWidth; - root->mmHeight = pScreen->mmHeight; -} -#else /* defined(FAKE_RANDR) */ #define DEFAULT_REFRESH 60 #define kDisplayModeUsableFlags (kDisplayModeValidFlag | kDisplayModeSafeFlag) @@ -390,5 +340,3 @@ Bool QuartzRandRInit (ScreenPtr pScreen) { pScrPriv->rrSetConfig = QuartzRandRSetConfig; return TRUE; } - -#endif /* defined(FAKE_RANDR) */ diff --git a/hw/xquartz/quartzRandR.h b/hw/xquartz/quartzRandR.h index a190205..711c3f3 100644 --- a/hw/xquartz/quartzRandR.h +++ b/hw/xquartz/quartzRandR.h @@ -27,11 +27,6 @@ * use or other dealings in this Software without prior written authorization. */ -/*define FAKE_RANDR 1*/ #define USE_DEPRECATED_CG_API 1 -#if defined(FAKE_RANDR) -void RREditConnectionInfo (ScreenPtr pScreen); -#else Bool QuartzRandRInit (ScreenPtr pScreen); -#endif -- 1.6.4.4
On Jun 13, 2010, at 2:13 PM, Jan Hauffa wrote:
the attached patch series contains a basic implementation of XRandR functionality and some related fixes: [ ... ]
Hi Jan, Wow, that's great! I'm sure Jeremy (or someone else in the project) will dive on this pretty quickly given that this particular feature has going begging for resources for some time now, and it's really gratifying to see someone other than Apple step forward in trying to make this happen; it rather validates the work we've done to keep Xquartz alive and active as an OSS project! :) Thanks, - Jordan
Yes, Jan. A big thanks. I've started looking through the patch set and I have a few questions. I wanted to give it a test run first (which hopefully I'll be able to do tomorrow), but here's what I've been thinking... The main issue is with the second patch... you have indicated reservations as well, and I think we will need to investigate this further. The X11 screen and root windows do not actually include the menu bar unless we are in fullscreen, so I'm concerned that the second patch may cause problems since we'll not be reporting the correct resolution of the X11 screen. Was the problem that the menu bar was incorrectly being subtracted when it was already not included? I'm concerned about how the resolution changes will affect desktop icon layout. A common use case would be a game switching to a lower resolution and we want to make sure that the user's desktop icons don't get rearranged on them when they return. Codeweavers got around this by always switching to fullscreen mode when xrandr changed to a non-default resolution. Perhaps we can do something "interesting" to tackle both of these issues. We can include the resolution with the menu bar subtracted in the list of resolutions. If XRandR chooses any resolution except that one, we can switch to quartz fullscreen mode (not the X11 cmd-alt-a fullscreen) in expectation of a game taking over like Codeweavers does. Switching back to the normal resolution would then result in returning to normal mode. Thoughts? On Jun 13, 2010, at 16:44, Jordan K. Hubbard wrote:
On Jun 13, 2010, at 2:13 PM, Jan Hauffa wrote:
the attached patch series contains a basic implementation of XRandR functionality and some related fixes: [ ... ]
Hi Jan,
Wow, that's great! I'm sure Jeremy (or someone else in the project) will dive on this pretty quickly given that this particular feature has going begging for resources for some time now, and it's really gratifying to see someone other than Apple step forward in trying to make this happen; it rather validates the work we've done to keep Xquartz alive and active as an OSS project! :)
Thanks,
- Jordan
_______________________________________________ Xquartz-dev mailing list Xquartz-dev@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/xquartz-dev
14 jun 2010 kl. 07.26 skrev Jeremy Huddleston:
Yes, Jan. A big thanks. I've started looking through the patch set and I have a few questions. I wanted to give it a test run first (which hopefully I'll be able to do tomorrow), but here's what I've been thinking...
The main issue is with the second patch... you have indicated reservations as well, and I think we will need to investigate this further. The X11 screen and root windows do not actually include the menu bar unless we are in fullscreen, so I'm concerned that the second patch may cause problems since we'll not be reporting the correct resolution of the X11 screen. Was the problem that the menu bar was incorrectly being subtracted when it was already not included?
I think you have to hide the menu bar. In most cases, the app that uses XRandR will open a window of the same resolution it switched to. Switching to fullscreen is probably the best solution.
Perhaps we can do something "interesting" to tackle both of these issues. We can include the resolution with the menu bar subtracted in the list of resolutions. If XRandR chooses any resolution except that one, we can switch to quartz fullscreen mode (not the X11 cmd-alt-a fullscreen) in expectation of a game taking over like Codeweavers does. Switching back to the normal resolution would then result in returning to normal mode.
That's exactly what I did in my incomplete version. Make sure to make the desktop resolution the first one listed, as that will be the default one switch to. You probably have to make sure that cmd-option-a will always take you out off fullscreen as well. Otherwise a crashing game might end you up with a black screen and no options except cmd-option-escape to get out, which will force quit X11 (and I think a lot of people do not know about that combination). In the best case some information about this would be displayed on the root window as well, though that'd be up to quartz-wm I guess. Both OS X and Windows handles this differently. In them, if the application that switches resolution exits, it is automatically switched back to the default one. Perhaps something to suggest to the other X11 developers? -- Pelle Johansson
On Jun 14, 2010, at 00:44, Per Johansson wrote:
That's exactly what I did in my incomplete version. Make sure to make the desktop resolution the first one listed, as that will be the default one switch to.
You probably have to make sure that cmd-option-a will always take you out off fullscreen as well. Otherwise a crashing game might end you up with a black screen and no options except cmd-option-escape to get out, which will force quit X11 (and I think a lot of people do not know about that combination). In the best case some information about this would be displayed on the root window as well, though that'd be up to quartz-wm I guess.
Yeah. Another option I thought of would be to allow a defaults option to toggle between "game mode" and "desktop mode" for RandR. Some people might want to use xrandr and utilities to actually
Both OS X and Windows handles this differently. In them, if the application that switches resolution exits, it is automatically switched back to the default one. Perhaps something to suggest to the other X11 developers?
Unfortunately, the "application" in this case would be the XQuartz.app server, not the X11 client that crashes. As for X11 "at large", that approach is not very feasible. In fact, think about the 'xrandr' command line utility. It can be used to change the desktop resolution, then immediately exists.
participants (4)
-
Jan Hauffa
-
Jeremy Huddleston
-
Jordan K. Hubbard
-
Per Johansson