/* * $XFree86$ * * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "X.h" #include "os.h" #include "mibank.h" #include "globals.h" #include "xf86.h" #include "xf86Priv.h" #include "xf86DDC.h" #include "mipointer.h" #include typedef struct _xf86RandRInfo { CreateScreenResourcesProcPtr CreateScreenResources; CloseScreenProcPtr CloseScreen; int virtualX; int virtualY; } XF86RandRInfoRec, *XF86RandRInfoPtr; static int xf86RandRIndex; static int xf86RandRGeneration; #define XF86RANDRINFO(p) ((XF86RandRInfoPtr) (p)->devPrivates[xf86RandRIndex].ptr) static int xf86RandRModeRefresh (DisplayModePtr mode) { if (mode->VRefresh) return (int) (mode->VRefresh + 0.5); else return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); } static Bool xf86RandRGetInfo (ScreenPtr pScreen, Rotation *rotations) { RRScreenSizePtr pSize; ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); DisplayModePtr mode; int refresh0 = 60; *rotations = RR_Rotate_0; for (mode = scrp->modes; ; mode = mode->next) { int refresh = xf86RandRModeRefresh (mode); if (mode == scrp->modes) refresh0 = refresh; pSize = RRRegisterSize (pScreen, mode->HDisplay, mode->VDisplay, pScreen->mmWidth, pScreen->mmHeight); if (!pSize) return FALSE; RRRegisterRate (pScreen, pSize, refresh); if (mode == scrp->currentMode && mode->HDisplay == pScreen->width && mode->VDisplay == pScreen->height) RRSetCurrentConfig (pScreen, RR_Rotate_0, refresh, pSize); if (mode->next == scrp->modes) break; } if (scrp->currentMode->HDisplay != randrp->virtualX || scrp->currentMode->VDisplay != randrp->virtualY) { mode = scrp->modes; pSize = RRRegisterSize (pScreen, randrp->virtualX, randrp->virtualY, pScreen->mmWidth * randrp->virtualX / scrp->currentMode->HDisplay, pScreen->mmHeight * randrp->virtualY / scrp->currentMode->VDisplay); if (!pSize) return FALSE; RRRegisterRate (pScreen, pSize, refresh0); if (pScreen->width == randrp->virtualX && pScreen->height == randrp->virtualY) { RRSetCurrentConfig (pScreen, RR_Rotate_0, refresh0, pSize); } } return TRUE; } static Bool xf86RandRSetMode (ScreenPtr pScreen, DisplayModePtr mode, Bool useVirtual) { ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); int oldWidth = pScreen->width; int oldHeight = pScreen->height; WindowPtr pRoot = WindowTable[pScreen->myNum]; if (pRoot) xf86EnableDisableFBAccess (pScreen->myNum, FALSE); if (useVirtual) { scrp->virtualX = randrp->virtualX; scrp->virtualY = randrp->virtualY; } else { scrp->virtualX = mode->HDisplay; scrp->virtualY = mode->VDisplay; } pScreen->width = scrp->virtualX; pScreen->height = scrp->virtualY; if (!xf86SwitchMode (pScreen, mode)) { scrp->virtualX = pScreen->width = oldWidth; scrp->virtualY = pScreen->height = oldHeight; return FALSE; } /* * Make sure the layout is correct */ xf86ReconfigureLayout(); /* * Make sure the whole screen is visible */ xf86SetViewport (pScreen, pScreen->width, pScreen->height); xf86SetViewport (pScreen, 0, 0); if (pRoot) xf86EnableDisableFBAccess (pScreen->myNum, TRUE); return TRUE; } static Bool xf86RandRSetConfig (ScreenPtr pScreen, Rotation rotation, int rate, RRScreenSizePtr pSize) { ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); DisplayModePtr mode; int px, py; Bool useVirtual = FALSE; miPointerPosition (&px, &py); for (mode = scrp->modes; ; mode = mode->next) { if (mode->HDisplay == pSize->width && mode->VDisplay == pSize->height && (rate == 0 || xf86RandRModeRefresh (mode) == rate)) break; if (mode->next == scrp->modes) { if (pSize->width == randrp->virtualX && pSize->height == randrp->virtualY) { mode = scrp->modes; useVirtual = TRUE; break; } return FALSE; } } if (!xf86RandRSetMode (pScreen, mode, useVirtual)) return FALSE; /* * Move the cursor back where it belongs; SwitchMode repositions it */ if (pScreen == miPointerCurrentScreen ()) { if (px < pSize->width && py < pSize->height) (*pScreen->SetCursorPosition) (pScreen, px, py, FALSE); } return TRUE; } /* * Wait until the screen is initialized before whacking the * sizes around; otherwise the screen pixmap will be allocated * at the current mode size rather than the maximum size */ static Bool xf86RandRCreateScreenResources (ScreenPtr pScreen) { XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); #if 0 ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); DisplayModePtr mode; #endif pScreen->CreateScreenResources = randrp->CreateScreenResources; if (!(*pScreen->CreateScreenResources) (pScreen)) return FALSE; #if 0 mode = scrp->currentMode; if (mode) xf86RandRSetMode (pScreen, mode, TRUE); #endif return TRUE; } /* * Reset size back to original */ static Bool xf86RandRCloseScreen (int index, ScreenPtr pScreen) { ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); scrp->virtualX = pScreen->width = randrp->virtualX; scrp->virtualY = pScreen->height = randrp->virtualY; scrp->currentMode = scrp->modes; pScreen->CloseScreen = randrp->CloseScreen; xfree (randrp); pScreen->devPrivates[xf86RandRIndex].ptr = 0; return (*pScreen->CloseScreen) (index, pScreen); } Bool xf86RandRInit (ScreenPtr pScreen) { rrScrPrivPtr rp; XF86RandRInfoPtr randrp; ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); #ifdef PANORAMIX /* XXX disable RandR when using Xinerama */ if (!noPanoramiXExtension) return TRUE; #endif if (xf86RandRGeneration != serverGeneration) { xf86RandRIndex = AllocateScreenPrivateIndex(); xf86RandRGeneration = serverGeneration; } randrp = xalloc (sizeof (XF86RandRInfoRec)); if (!randrp) return FALSE; if (!RRScreenInit (pScreen)) { xfree (randrp); return FALSE; } rp = rrGetScrPriv(pScreen); rp->rrGetInfo = xf86RandRGetInfo; rp->rrSetConfig = xf86RandRSetConfig; randrp->virtualX = scrp->virtualX; randrp->virtualY = scrp->virtualY; randrp->CreateScreenResources = pScreen->CreateScreenResources; pScreen->CreateScreenResources = xf86RandRCreateScreenResources; randrp->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = xf86RandRCloseScreen; pScreen->devPrivates[xf86RandRIndex].ptr = randrp; return TRUE; }