/* * * 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. */ #ifdef HAVE_XORG_CONFIG_H #include <xorg-config.h> #endif #include <X11/X.h> #include "os.h" #include "globals.h" #include "xf86.h" #include "xf86str.h" #include "xf86Priv.h" #include "xf86DDC.h" #include "mipointer.h" #include <randrstr.h> #include "inputstr.h" typedef struct _xf86RandRInfo { CreateScreenResourcesProcPtr CreateScreenResources; CloseScreenProcPtr CloseScreen; int virtualX; int virtualY; int mmWidth; int mmHeight; Rotation rotation; } XF86RandRInfoRec, *XF86RandRInfoPtr; static DevPrivateKeyRec xf86RandRKeyRec; static DevPrivateKey xf86RandRKey; #define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey)) static int xf86RandRModeRefresh (DisplayModePtr mode) { if (mode->VRefresh) return (int) (mode->VRefresh + 0.5); else if (mode->Clock == 0) return 0; 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; xorgRRModeMM RRModeMM; *rotations = RR_Rotate_0; for (mode = scrp->modes; mode != NULL ; mode = mode->next) { int refresh = xf86RandRModeRefresh (mode); if (mode == scrp->modes) refresh0 = refresh; RRModeMM.mode = mode; RRModeMM.virtX = randrp->virtualX; RRModeMM.virtY = randrp->virtualY; RRModeMM.mmWidth = randrp->mmWidth; RRModeMM.mmHeight = randrp->mmHeight; if(scrp->DriverFunc) { (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); } pSize = RRRegisterSize (pScreen, mode->HDisplay, mode->VDisplay, RRModeMM.mmWidth, RRModeMM.mmHeight); if (!pSize) return FALSE; RRRegisterRate (pScreen, pSize, refresh); if (mode == scrp->currentMode && mode->HDisplay == scrp->virtualX && mode->VDisplay == scrp->virtualY) RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); if (mode->next == scrp->modes) break; } if (scrp->currentMode->HDisplay != randrp->virtualX || scrp->currentMode->VDisplay != randrp->virtualY) { mode = scrp->modes; RRModeMM.mode = NULL; RRModeMM.virtX = randrp->virtualX; RRModeMM.virtY = randrp->virtualY; RRModeMM.mmWidth = randrp->mmWidth; RRModeMM.mmHeight = randrp->mmHeight; if(scrp->DriverFunc) { (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); } pSize = RRRegisterSize (pScreen, randrp->virtualX, randrp->virtualY, RRModeMM.mmWidth, RRModeMM.mmHeight); if (!pSize) return FALSE; RRRegisterRate (pScreen, pSize, refresh0); if (scrp->virtualX == randrp->virtualX && scrp->virtualY == randrp->virtualY) { RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); } } /* If there is driver support for randr, let it set our supported rotations */ if(scrp->DriverFunc) { xorgRRRotation RRRotation; RRRotation.RRRotations = *rotations; if (!(*scrp->DriverFunc)(scrp, RR_GET_INFO, &RRRotation)) return TRUE; *rotations = RRRotation.RRRotations; } return TRUE; } static Bool xf86RandRSetMode (ScreenPtr pScreen, DisplayModePtr mode, Bool useVirtual, int mmWidth, int mmHeight) { ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); int oldWidth = pScreen->width; int oldHeight = pScreen->height; int oldmmWidth = pScreen->mmWidth; int oldmmHeight = pScreen->mmHeight; int oldVirtualX = scrp->virtualX; int oldVirtualY = scrp->virtualY; WindowPtr pRoot = pScreen->root; Bool ret = TRUE; if (pRoot && scrp->vtSema) (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); if (useVirtual) { scrp->virtualX = randrp->virtualX; scrp->virtualY = randrp->virtualY; } else { scrp->virtualX = mode->HDisplay; scrp->virtualY = mode->VDisplay; } /* * The DIX forgets the physical dimensions we passed into RRRegisterSize, so * reconstruct them if possible. */ if(scrp->DriverFunc) { xorgRRModeMM RRModeMM; RRModeMM.mode = mode; RRModeMM.virtX = scrp->virtualX; RRModeMM.virtY = scrp->virtualY; RRModeMM.mmWidth = mmWidth; RRModeMM.mmHeight = mmHeight; (*scrp->DriverFunc)(scrp, RR_GET_MODE_MM, &RRModeMM); mmWidth = RRModeMM.mmWidth; mmHeight = RRModeMM.mmHeight; } if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) { /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ pScreen->width = scrp->virtualY; pScreen->height = scrp->virtualX; pScreen->mmWidth = mmHeight; pScreen->mmHeight = mmWidth; } else { pScreen->width = scrp->virtualX; pScreen->height = scrp->virtualY; pScreen->mmWidth = mmWidth; pScreen->mmHeight = mmHeight; } if (!xf86SwitchMode (pScreen, mode)) { pScreen->width = oldWidth; pScreen->height = oldHeight; pScreen->mmWidth = oldmmWidth; pScreen->mmHeight = oldmmHeight; scrp->virtualX = oldVirtualX; scrp->virtualY = oldVirtualY; ret = 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 && scrp->vtSema) (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); return ret; } 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; Rotation oldRotation = randrp->rotation; miPointerGetPosition(inputInfo.pointer, &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 (randrp->rotation != rotation) { /* Have the driver do its thing. */ if (scrp->DriverFunc) { xorgRRRotation RRRotation; RRRotation.RRConfig.rotation = rotation; RRRotation.RRConfig.rate = rate; RRRotation.RRConfig.width = pSize->width; RRRotation.RRConfig.height = pSize->height; /* * Currently we need to rely on HW support for rotation. */ if (!(*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation)) return FALSE; } else return FALSE; randrp->rotation = rotation; } if (!xf86RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) { if(randrp->rotation != oldRotation) { /* Have the driver undo its thing. */ if (scrp->DriverFunc) { xorgRRRotation RRRotation; RRRotation.RRConfig.rotation = oldRotation; RRRotation.RRConfig.rate = xf86RandRModeRefresh (scrp->currentMode); RRRotation.RRConfig.width = scrp->virtualX; RRRotation.RRConfig.height = scrp->virtualY; (*scrp->DriverFunc)(scrp, RR_SET_CONFIG, &RRRotation); } randrp->rotation = oldRotation; } return FALSE; } /* * Move the cursor back where it belongs; SwitchMode repositions it */ if (pScreen == miPointerCurrentScreen ()) { px = (px >= pScreen->width ? (pScreen->width - 1) : px); py = (py >= pScreen->height ? (pScreen->height - 1) : py); xf86SetViewport(pScreen, px, py); (*pScreen->SetCursorPosition) (inputInfo.pointer, 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; free(randrp); dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL); return (*pScreen->CloseScreen) (index, pScreen); } Rotation xf86GetRotation(ScreenPtr pScreen) { if (xf86RandRKey == NULL) return RR_Rotate_0; return XF86RANDRINFO(pScreen)->rotation; } /* Function to change RandR's idea of the virtual screen size */ Bool xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen, int newvirtX, int newvirtY, int newmmWidth, int newmmHeight, Bool resetMode) { XF86RandRInfoPtr randrp; if (xf86RandRKey == NULL) return FALSE; randrp = XF86RANDRINFO(pScreen); if (randrp == NULL) return FALSE; if (newvirtX > 0) randrp->virtualX = newvirtX; if (newvirtY > 0) randrp->virtualY = newvirtY; if (newmmWidth > 0) randrp->mmWidth = newmmWidth; if (newmmHeight > 0) randrp->mmHeight = newmmHeight; /* This is only for during server start */ if (resetMode) { return (xf86RandRSetMode(pScreen, XF86SCRNINFO(pScreen)->currentMode, TRUE, pScreen->mmWidth, pScreen->mmHeight)); } return TRUE; } 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 xf86RandRKey = &xf86RandRKeyRec; if (!dixRegisterPrivateKey(&xf86RandRKeyRec, PRIVATE_SCREEN, 0)) return FALSE; randrp = malloc(sizeof (XF86RandRInfoRec)); if (!randrp) return FALSE; if (!RRScreenInit (pScreen)) { free(randrp); return FALSE; } rp = rrGetScrPriv(pScreen); rp->rrGetInfo = xf86RandRGetInfo; rp->rrSetConfig = xf86RandRSetConfig; randrp->virtualX = scrp->virtualX; randrp->virtualY = scrp->virtualY; randrp->mmWidth = pScreen->mmWidth; randrp->mmHeight = pScreen->mmHeight; randrp->CreateScreenResources = pScreen->CreateScreenResources; pScreen->CreateScreenResources = xf86RandRCreateScreenResources; randrp->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = xf86RandRCloseScreen; randrp->rotation = RR_Rotate_0; dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp); return TRUE; }