475 lines
14 KiB
C
475 lines
14 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 = xf86ScreenToScrn(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 = xf86ScreenToScrn(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) (scrp, 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) (scrp, TRUE);
|
|
return ret;
|
|
}
|
|
|
|
static Bool
|
|
xf86RandRSetConfig(ScreenPtr pScreen,
|
|
Rotation rotation, int rate, RRScreenSizePtr pSize)
|
|
{
|
|
ScrnInfoPtr scrp = xf86ScreenToScrn(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;
|
|
}
|
|
|
|
update_desktop_dimensions();
|
|
|
|
/*
|
|
* 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 = xf86ScreenToScrn(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(ScreenPtr pScreen)
|
|
{
|
|
ScrnInfoPtr scrp = xf86ScreenToScrn(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) (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) {
|
|
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
|
|
return (xf86RandRSetMode(pScreen,
|
|
pScrn->currentMode,
|
|
TRUE, pScreen->mmWidth, pScreen->mmHeight));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
xf86RandRInit(ScreenPtr pScreen)
|
|
{
|
|
rrScrPrivPtr rp;
|
|
XF86RandRInfoPtr randrp;
|
|
ScrnInfoPtr scrp = xf86ScreenToScrn(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;
|
|
}
|