xenocara/xserver/hw/xfree86/common/xf86RandR.c
2011-11-05 13:32:40 +00:00

486 lines
13 KiB
C

/*
*
* 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 pos[MAXDEVICES][2];
Bool useVirtual = FALSE;
Rotation oldRotation = randrp->rotation;
DeviceIntPtr dev;
Bool view_adjusted = FALSE;
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (!IsMaster(dev) && !IsFloating(dev))
continue;
miPointerGetPosition(dev, &pos[dev->id][0], &pos[dev->id][1]);
}
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
* FIXME: duplicated code, see modes/xf86RandR12.c
*/
for (dev = inputInfo.devices; dev; dev = dev->next)
{
if (!IsMaster(dev) && !IsFloating(dev))
continue;
if (pScreen == miPointerGetScreen(dev)) {
int px = pos[dev->id][0];
int py = pos[dev->id][1];
px = (px >= pScreen->width ? (pScreen->width - 1) : px);
py = (py >= pScreen->height ? (pScreen->height - 1) : py);
/* Setting the viewpoint makes only sense on one device */
if (!view_adjusted && IsMaster(dev)) {
xf86SetViewport(pScreen, px, py);
view_adjusted = TRUE;
}
(*pScreen->SetCursorPosition) (dev, 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;
}