425 lines
11 KiB
C
425 lines
11 KiB
C
/* $XdotOrg: xc/programs/Xserver/hw/xfree86/common/xf86RandR.c,v 1.3 2004/07/30 21:53:09 eich Exp $ */
|
|
/*
|
|
* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86RandR.c,v 1.7tsi Exp $
|
|
*
|
|
* 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 "windowstr.h"
|
|
#include "mivalidate.h"
|
|
#include <randrstr.h>
|
|
|
|
#include "i830.h"
|
|
|
|
typedef struct _i830RandRInfo {
|
|
int virtualX;
|
|
int virtualY;
|
|
int mmWidth;
|
|
int mmHeight;
|
|
int maxX;
|
|
int maxY;
|
|
Rotation rotation; /* current mode */
|
|
Rotation supported_rotations; /* driver supported */
|
|
} XF86RandRInfoRec, *XF86RandRInfoPtr;
|
|
|
|
static int i830RandRIndex;
|
|
static int i830RandRGeneration;
|
|
|
|
#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) (p)->devPrivates[i830RandRIndex].ptr)
|
|
|
|
static int
|
|
I830RandRModeRefresh (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
|
|
I830RandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
|
|
{
|
|
RRScreenSizePtr pSize;
|
|
ScrnInfoPtr scrp = XF86SCRNINFO(pScreen);
|
|
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
|
|
DisplayModePtr mode;
|
|
int refresh0 = 60;
|
|
int maxX = 0, maxY = 0;
|
|
|
|
*rotations = randrp->supported_rotations;
|
|
|
|
if (randrp->virtualX == -1 || randrp->virtualY == -1)
|
|
{
|
|
randrp->virtualX = scrp->virtualX;
|
|
randrp->virtualY = scrp->virtualY;
|
|
}
|
|
|
|
for (mode = scrp->modes; ; mode = mode->next)
|
|
{
|
|
int refresh = I830RandRModeRefresh (mode);
|
|
if (randrp->maxX == 0 || randrp->maxY == 0)
|
|
{
|
|
if (maxX < mode->HDisplay)
|
|
maxX = mode->HDisplay;
|
|
if (maxY < mode->VDisplay)
|
|
maxY = mode->VDisplay;
|
|
}
|
|
if (mode == scrp->modes)
|
|
refresh0 = refresh;
|
|
pSize = RRRegisterSize (pScreen,
|
|
mode->HDisplay, mode->VDisplay,
|
|
randrp->mmWidth, randrp->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 (randrp->maxX == 0 || randrp->maxY == 0)
|
|
{
|
|
randrp->maxX = maxX;
|
|
randrp->maxY = maxY;
|
|
}
|
|
|
|
if (scrp->currentMode->HDisplay != randrp->virtualX ||
|
|
scrp->currentMode->VDisplay != randrp->virtualY)
|
|
{
|
|
mode = scrp->modes;
|
|
pSize = RRRegisterSize (pScreen,
|
|
randrp->virtualX, randrp->virtualY,
|
|
randrp->mmWidth,
|
|
randrp->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->RRFunc) {
|
|
xorgRRRotation RRRotation;
|
|
|
|
RRRotation.RRRotations = *rotations;
|
|
if (!(*scrp->RRFunc)(scrp, RR_GET_INFO, &RRRotation))
|
|
return FALSE;
|
|
*rotations = RRRotation.RRRotations;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
I830RandRSetMode (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;
|
|
WindowPtr pRoot = WindowTable[pScreen->myNum];
|
|
DisplayModePtr currentMode = NULL;
|
|
Bool ret = TRUE;
|
|
PixmapPtr pspix = NULL;
|
|
|
|
if (pRoot)
|
|
(*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE);
|
|
if (useVirtual)
|
|
{
|
|
scrp->virtualX = randrp->virtualX;
|
|
scrp->virtualY = randrp->virtualY;
|
|
}
|
|
else
|
|
{
|
|
scrp->virtualX = mode->HDisplay;
|
|
scrp->virtualY = mode->VDisplay;
|
|
}
|
|
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 (scrp->currentMode == mode) {
|
|
/* Save current mode */
|
|
currentMode = scrp->currentMode;
|
|
/* Reset, just so we ensure the drivers SwitchMode is called */
|
|
scrp->currentMode = NULL;
|
|
}
|
|
/*
|
|
* We assume that if the driver failed to SwitchMode to the rotated
|
|
* version, then it should revert back to it's prior mode... Mmm...
|
|
*/
|
|
if (!xf86SwitchMode (pScreen, mode))
|
|
{
|
|
ret = FALSE;
|
|
scrp->virtualX = pScreen->width = oldWidth;
|
|
scrp->virtualY = pScreen->height = oldHeight;
|
|
pScreen->mmWidth = oldmmWidth;
|
|
pScreen->mmHeight = oldmmHeight;
|
|
scrp->currentMode = currentMode;
|
|
}
|
|
/*
|
|
* Get the new Screen pixmap ptr as SwitchMode might have called
|
|
* ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back...
|
|
* Unfortunately.
|
|
*/
|
|
pspix = (*pScreen->GetScreenPixmap) (pScreen);
|
|
if (pspix->devPrivate.ptr)
|
|
scrp->pixmapPrivate = pspix->devPrivate;
|
|
|
|
/*
|
|
* 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->EnableDisableFBAccess) (pScreen->myNum, TRUE);
|
|
return ret;
|
|
}
|
|
|
|
Bool
|
|
I830RandRSetConfig (ScreenPtr pScreen,
|
|
Rotation rotation,
|
|
int rate,
|
|
RRScreenSizePtr pSize)
|
|
{
|
|
ScrnInfoPtr scrp = XF86SCRNINFO(pScreen);
|
|
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
|
|
DisplayModePtr mode;
|
|
int px, py;
|
|
Bool useVirtual = FALSE;
|
|
int maxX = 0, maxY = 0;
|
|
Rotation oldRotation = randrp->rotation;
|
|
|
|
randrp->rotation = rotation;
|
|
|
|
if (randrp->virtualX == -1 || randrp->virtualY == -1)
|
|
{
|
|
randrp->virtualX = scrp->virtualX;
|
|
randrp->virtualY = scrp->virtualY;
|
|
}
|
|
|
|
miPointerPosition (&px, &py);
|
|
for (mode = scrp->modes; ; mode = mode->next)
|
|
{
|
|
if (randrp->maxX == 0 || randrp->maxY == 0)
|
|
{
|
|
if (maxX < mode->HDisplay)
|
|
maxX = mode->HDisplay;
|
|
if (maxY < mode->VDisplay)
|
|
maxY = mode->VDisplay;
|
|
}
|
|
if (mode->HDisplay == pSize->width &&
|
|
mode->VDisplay == pSize->height &&
|
|
(rate == 0 || I830RandRModeRefresh (mode) == rate))
|
|
break;
|
|
if (mode->next == scrp->modes)
|
|
{
|
|
if (pSize->width == randrp->virtualX &&
|
|
pSize->height == randrp->virtualY)
|
|
{
|
|
mode = scrp->modes;
|
|
useVirtual = TRUE;
|
|
break;
|
|
}
|
|
if (randrp->maxX == 0 || randrp->maxY == 0)
|
|
{
|
|
randrp->maxX = maxX;
|
|
randrp->maxY = maxY;
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (randrp->maxX == 0 || randrp->maxY == 0)
|
|
{
|
|
randrp->maxX = maxX;
|
|
randrp->maxY = maxY;
|
|
}
|
|
|
|
/* Have the driver do its thing. */
|
|
if (scrp->RRFunc) {
|
|
xorgRRRotation RRRotation;
|
|
RRRotation.RRConfig.rotation = rotation;
|
|
RRRotation.RRConfig.rate = rate;
|
|
RRRotation.RRConfig.width = pSize->width;
|
|
RRRotation.RRConfig.height = pSize->height;
|
|
|
|
if (!(*scrp->RRFunc)(scrp, RR_SET_CONFIG, &RRRotation))
|
|
return FALSE;
|
|
}
|
|
|
|
if (!I830RandRSetMode (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) {
|
|
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) (pScreen, px, py, FALSE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Rotation
|
|
I830GetRotation(ScreenPtr pScreen)
|
|
{
|
|
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
|
|
|
|
return randrp->rotation;
|
|
}
|
|
|
|
Bool
|
|
I830RandRInit (ScreenPtr pScreen, int rotation)
|
|
{
|
|
rrScrPrivPtr rp;
|
|
XF86RandRInfoPtr randrp;
|
|
ScrnInfoPtr scrp = XF86SCRNINFO(pScreen);
|
|
|
|
#ifdef PANORAMIX
|
|
/* XXX disable RandR when using Xinerama */
|
|
if (!noPanoramiXExtension)
|
|
return TRUE;
|
|
#endif
|
|
if (i830RandRGeneration != serverGeneration)
|
|
{
|
|
i830RandRIndex = AllocateScreenPrivateIndex();
|
|
i830RandRGeneration = serverGeneration;
|
|
}
|
|
|
|
randrp = xalloc (sizeof (XF86RandRInfoRec));
|
|
if (!randrp)
|
|
return FALSE;
|
|
|
|
if (!RRScreenInit(pScreen))
|
|
{
|
|
xfree (randrp);
|
|
return FALSE;
|
|
}
|
|
rp = rrGetScrPriv(pScreen);
|
|
rp->rrGetInfo = I830RandRGetInfo;
|
|
rp->rrSetConfig = I830RandRSetConfig;
|
|
|
|
randrp->virtualX = -1;
|
|
randrp->virtualY = -1;
|
|
randrp->mmWidth = pScreen->mmWidth;
|
|
randrp->mmHeight = pScreen->mmHeight;
|
|
|
|
randrp->rotation = RR_Rotate_0; /* initial rotated mode */
|
|
|
|
randrp->supported_rotations = rotation;
|
|
|
|
randrp->maxX = randrp->maxY = 0;
|
|
|
|
pScreen->devPrivates[i830RandRIndex].ptr = randrp;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef XFree86LOADER
|
|
static MODULESETUPPROTO(intelrandrSetup);
|
|
|
|
static XF86ModuleVersionInfo intelrandrVersRec =
|
|
{
|
|
"intel_randr",
|
|
"Tungsten Graphics, Inc",
|
|
MODINFOSTRING1,
|
|
MODINFOSTRING2,
|
|
XF86_VERSION_CURRENT,
|
|
INTEL_MAJOR_VERSION, INTEL_MINOR_VERSION, INTEL_PATCHLEVEL,
|
|
ABI_CLASS_EXTENSION,
|
|
ABI_EXTENSION_VERSION,
|
|
MOD_CLASS_EXTENSION,
|
|
{0,0,0,0}
|
|
};
|
|
|
|
XF86ModuleData intel_randrModuleData = { &intelrandrVersRec, intelrandrSetup, NULL };
|
|
|
|
ModuleInfoRec INTELRANDR = {
|
|
1,
|
|
"INTELRANDR",
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
static pointer
|
|
intelrandrSetup(pointer Module, pointer Options, int *ErrorMajor, int *ErrorMinor)
|
|
{
|
|
static Bool Initialised = FALSE;
|
|
|
|
if (!Initialised) {
|
|
Initialised = TRUE;
|
|
#ifndef REMOVE_LOADER_CHECK_MODULE_INFO
|
|
if (xf86LoaderCheckSymbol("xf86AddModuleInfo"))
|
|
#endif
|
|
xf86AddModuleInfo(&INTELRANDR, Module);
|
|
}
|
|
|
|
return (pointer)TRUE;
|
|
}
|
|
#endif
|