aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xfree86/common/xf86RandR.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xfree86/common/xf86RandR.c')
-rw-r--r--xorg-server/hw/xfree86/common/xf86RandR.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/xorg-server/hw/xfree86/common/xf86RandR.c b/xorg-server/hw/xfree86/common/xf86RandR.c
new file mode 100644
index 000000000..a55b93d4c
--- /dev/null
+++ b/xorg-server/hw/xfree86/common/xf86RandR.c
@@ -0,0 +1,457 @@
+/*
+ *
+ * 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 "mibank.h"
+#include "globals.h"
+#include "xf86.h"
+#include "xf86Priv.h"
+#include "xf86DDC.h"
+#include "mipointer.h"
+#include <randrstr.h>
+
+typedef struct _xf86RandRInfo {
+ CreateScreenResourcesProcPtr CreateScreenResources;
+ CloseScreenProcPtr CloseScreen;
+ int virtualX;
+ int virtualY;
+ int mmWidth;
+ int mmHeight;
+ Rotation rotation;
+} XF86RandRInfoRec, *XF86RandRInfoPtr;
+
+static DevPrivateKey xf86RandRKey = NULL;
+
+#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 = 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 = WindowTable[pScreen->myNum];
+ Bool ret = TRUE;
+
+ 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;
+ }
+
+ /*
+ * 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->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;
+
+ 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 (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) (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);
+ dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL);
+ return (*pScreen->CloseScreen) (index, pScreen);
+}
+
+_X_EXPORT 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 */
+_X_EXPORT 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 = &xf86RandRKey;
+
+ 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->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;
+}
+
+