xserver-multidpi/hw/xfree86/modes/xf86RandR12.c
Keith Packard bcf17df69a Disable CRTC when SetSingleMode has no matching mode. Update RandR as well.
xf86SetSingleMode tries to resize all crtcs to match the selected mode. When
a CRTC has no matching mode, it now disables the CRTC (instead of crashing).

Also, poke the RandR extension when xf86SetSingleMode is done so that
appropriate events can be delivered, and so that future RandR queries return
correct information.
(cherry picked from commit dc6c4f6989)
2007-04-10 12:36:45 -07:00

1111 lines
28 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 the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS 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>
#else
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#endif
#include "xf86.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 <randrstr.h>
#include <X11/extensions/render.h>
#include "xf86Crtc.h"
#include "xf86RandR12.h"
typedef struct _xf86RandR12Info {
int virtualX;
int virtualY;
int mmWidth;
int mmHeight;
int maxX;
int maxY;
Rotation rotation; /* current mode */
Rotation supported_rotations; /* driver supported */
} XF86RandRInfoRec, *XF86RandRInfoPtr;
#ifdef RANDR_12_INTERFACE
static Bool xf86RandR12Init12 (ScreenPtr pScreen);
static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen);
#endif
static int xf86RandR12Index;
static int xf86RandR12Generation;
#define XF86RANDRINFO(p) \
((XF86RandRInfoPtr)(p)->devPrivates[xf86RandR12Index].ptr)
static int
xf86RandR12ModeRefresh (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
xf86RandR12GetInfo (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;
}
/* Re-probe the outputs for new monitors or modes */
xf86ProbeOutputModes (scrp, 0, 0);
xf86SetScrnInfoModes (scrp);
xf86DiDGAReInit (pScreen);
for (mode = scrp->modes; ; mode = mode->next)
{
int refresh = xf86RandR12ModeRefresh (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 (xf86ModesEqual(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)
{
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);
}
}
return TRUE;
}
static Bool
xf86RandR12SetMode (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 know that if the driver failed to SwitchMode to the rotated
* version, then it should revert back to it's prior mode.
*/
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
xf86RandR12SetConfig (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 || xf86RandR12ModeRefresh (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;
}
if (!xf86RandR12SetMode (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;
}
static Bool
xf86RandR12ScreenSetSize (ScreenPtr pScreen,
CARD16 width,
CARD16 height,
CARD32 mmWidth,
CARD32 mmHeight)
{
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
ScrnInfoPtr pScrn = XF86SCRNINFO(pScreen);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
WindowPtr pRoot = WindowTable[pScreen->myNum];
Bool ret = FALSE;
if (randrp->virtualX == -1 || randrp->virtualY == -1)
{
randrp->virtualX = pScrn->virtualX;
randrp->virtualY = pScrn->virtualY;
}
if (pRoot)
(*pScrn->EnableDisableFBAccess) (pScreen->myNum, FALSE);
/* Let the driver update virtualX and virtualY */
if (!(*config->funcs->resize)(pScrn, width, height))
goto finish;
ret = TRUE;
pScreen->width = width;
pScreen->height = height;
pScreen->mmWidth = mmWidth;
pScreen->mmHeight = mmHeight;
xf86SetViewport (pScreen, pScreen->width-1, pScreen->height-1);
xf86SetViewport (pScreen, 0, 0);
finish:
if (pRoot)
(*pScrn->EnableDisableFBAccess) (pScreen->myNum, TRUE);
#if RANDR_12_INTERFACE
if (WindowTable[pScreen->myNum] && ret)
RRScreenSizeNotify (pScreen);
#endif
return ret;
}
Rotation
xf86RandR12GetRotation(ScreenPtr pScreen)
{
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
return randrp->rotation;
}
Bool
xf86RandR12CreateScreenResources (ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
int c;
int width, height;
int mmWidth, mmHeight;
#ifdef PANORAMIX
/* XXX disable RandR when using Xinerama */
if (!noPanoramiXExtension)
return TRUE;
#endif
/*
* Compute size of screen
*/
width = 0; height = 0;
for (c = 0; c < config->num_crtc; c++)
{
xf86CrtcPtr crtc = config->crtc[c];
int crtc_width = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
int crtc_height = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
if (crtc->enabled && crtc_width > width)
width = crtc_width;
if (crtc->enabled && crtc_height > height)
height = crtc_height;
}
if (width && height)
{
/*
* Compute physical size of screen
*/
if (monitorResolution)
{
mmWidth = width * 25.4 / monitorResolution;
mmHeight = height * 25.4 / monitorResolution;
}
else
{
xf86OutputPtr output = config->output[config->compat_output];
xf86CrtcPtr crtc = output->crtc;
if (crtc && crtc->mode.HDisplay &&
output->mm_width && output->mm_height)
{
/*
* If the output has a mode and a declared size, use that
* to scale the screen size
*/
DisplayModePtr mode = &crtc->mode;
mmWidth = output->mm_width * width / mode->HDisplay;
mmHeight = output->mm_height * height / mode->VDisplay;
}
else
{
/*
* Otherwise, just set the screen to 96dpi
*/
mmWidth = width * 25.4 / 96;
mmHeight = height * 25.4 / 96;
}
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Setting screen physical size to %d x %d\n",
mmWidth, mmHeight);
xf86RandR12ScreenSetSize (pScreen,
width,
height,
mmWidth,
mmHeight);
}
if (randrp->virtualX == -1 || randrp->virtualY == -1)
{
randrp->virtualX = pScrn->virtualX;
randrp->virtualY = pScrn->virtualY;
}
xf86CrtcSetScreenSubpixelOrder (pScreen);
#if RANDR_12_INTERFACE
if (xf86RandR12CreateScreenResources12 (pScreen))
return TRUE;
#endif
return TRUE;
}
Bool
xf86RandR12Init (ScreenPtr pScreen)
{
rrScrPrivPtr rp;
XF86RandRInfoPtr randrp;
#ifdef PANORAMIX
/* XXX disable RandR when using Xinerama */
if (!noPanoramiXExtension)
return TRUE;
#endif
if (xf86RandR12Generation != serverGeneration)
{
xf86RandR12Index = AllocateScreenPrivateIndex();
xf86RandR12Generation = serverGeneration;
}
randrp = xalloc (sizeof (XF86RandRInfoRec));
if (!randrp)
return FALSE;
if (!RRScreenInit(pScreen))
{
xfree (randrp);
return FALSE;
}
rp = rrGetScrPriv(pScreen);
rp->rrGetInfo = xf86RandR12GetInfo;
rp->rrSetConfig = xf86RandR12SetConfig;
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 = RR_Rotate_0;
randrp->maxX = randrp->maxY = 0;
pScreen->devPrivates[xf86RandR12Index].ptr = randrp;
#if RANDR_12_INTERFACE
if (!xf86RandR12Init12 (pScreen))
return FALSE;
#endif
return TRUE;
}
void
xf86RandR12SetRotations (ScreenPtr pScreen, Rotation rotations)
{
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
#if RANDR_12_INTERFACE
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
int c;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
for (c = 0; c < config->num_crtc; c++) {
xf86CrtcPtr crtc = config->crtc[c];
RRCrtcSetRotations (crtc->randr_crtc, rotations);
}
#endif
randrp->supported_rotations = rotations;
}
void
xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y)
{
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
if (xf86RandR12Generation != serverGeneration ||
XF86RANDRINFO(pScreen)->virtualX == -1)
{
*x = pScrn->virtualX;
*y = pScrn->virtualY;
} else {
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
*x = randrp->virtualX;
*y = randrp->virtualY;
}
}
#if RANDR_12_INTERFACE
#define FLAG_BITS (RR_HSyncPositive | \
RR_HSyncNegative | \
RR_VSyncPositive | \
RR_VSyncNegative | \
RR_Interlace | \
RR_DoubleScan | \
RR_CSync | \
RR_CSyncPositive | \
RR_CSyncNegative | \
RR_HSkewPresent | \
RR_BCast | \
RR_PixelMultiplex | \
RR_DoubleClock | \
RR_ClockDivideBy2)
static Bool
xf86RandRModeMatches (RRModePtr randr_mode,
DisplayModePtr mode)
{
#if 0
if (match_name)
{
/* check for same name */
int len = strlen (mode->name);
if (randr_mode->mode.nameLength != len) return FALSE;
if (memcmp (randr_mode->name, mode->name, len) != 0) return FALSE;
}
#endif
/* check for same timings */
if (randr_mode->mode.dotClock / 1000 != mode->Clock) return FALSE;
if (randr_mode->mode.width != mode->HDisplay) return FALSE;
if (randr_mode->mode.hSyncStart != mode->HSyncStart) return FALSE;
if (randr_mode->mode.hSyncEnd != mode->HSyncEnd) return FALSE;
if (randr_mode->mode.hTotal != mode->HTotal) return FALSE;
if (randr_mode->mode.hSkew != mode->HSkew) return FALSE;
if (randr_mode->mode.height != mode->VDisplay) return FALSE;
if (randr_mode->mode.vSyncStart != mode->VSyncStart) return FALSE;
if (randr_mode->mode.vSyncEnd != mode->VSyncEnd) return FALSE;
if (randr_mode->mode.vTotal != mode->VTotal) return FALSE;
/* check for same flags (using only the XF86 valid flag bits) */
if ((randr_mode->mode.modeFlags & FLAG_BITS) != (mode->Flags & FLAG_BITS))
return FALSE;
/* everything matches */
return TRUE;
}
static Bool
xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc)
{
ScreenPtr pScreen = randr_crtc->pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
RRModePtr randr_mode = NULL;
int x;
int y;
Rotation rotation;
int numOutputs;
RROutputPtr *randr_outputs;
RROutputPtr randr_output;
xf86CrtcPtr crtc = randr_crtc->devPrivate;
xf86OutputPtr output;
int i, j;
DisplayModePtr mode = &crtc->mode;
Bool ret;
randr_outputs = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr));
if (!randr_outputs)
return FALSE;
x = crtc->x;
y = crtc->y;
rotation = crtc->rotation;
numOutputs = 0;
randr_mode = NULL;
for (i = 0; i < config->num_output; i++)
{
output = config->output[i];
if (output->crtc == crtc)
{
randr_output = output->randr_output;
randr_outputs[numOutputs++] = randr_output;
/*
* We make copies of modes, so pointer equality
* isn't sufficient
*/
for (j = 0; j < randr_output->numModes + randr_output->numUserModes; j++)
{
RRModePtr m = (j < randr_output->numModes ?
randr_output->modes[j] :
randr_output->userModes[j-randr_output->numModes]);
if (xf86RandRModeMatches (m, mode))
{
randr_mode = m;
break;
}
}
}
}
ret = RRCrtcNotify (randr_crtc, randr_mode, x, y,
rotation, numOutputs, randr_outputs);
DEALLOCATE_LOCAL(randr_outputs);
return ret;
}
/*
* Convert a RandR mode to a DisplayMode
*/
static void
xf86RandRModeConvert (ScrnInfoPtr scrn,
RRModePtr randr_mode,
DisplayModePtr mode)
{
mode->prev = NULL;
mode->next = NULL;
mode->name = NULL;
mode->status = MODE_OK;
mode->type = 0;
mode->Clock = randr_mode->mode.dotClock / 1000;
mode->HDisplay = randr_mode->mode.width;
mode->HSyncStart = randr_mode->mode.hSyncStart;
mode->HSyncEnd = randr_mode->mode.hSyncEnd;
mode->HTotal = randr_mode->mode.hTotal;
mode->HSkew = randr_mode->mode.hSkew;
mode->VDisplay = randr_mode->mode.height;
mode->VSyncStart = randr_mode->mode.vSyncStart;
mode->VSyncEnd = randr_mode->mode.vSyncEnd;
mode->VTotal = randr_mode->mode.vTotal;
mode->VScan = 0;
mode->Flags = randr_mode->mode.modeFlags & FLAG_BITS;
xf86SetModeCrtc (mode, scrn->adjustFlags);
}
static Bool
xf86RandR12CrtcSet (ScreenPtr pScreen,
RRCrtcPtr randr_crtc,
RRModePtr randr_mode,
int x,
int y,
Rotation rotation,
int num_randr_outputs,
RROutputPtr *randr_outputs)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
xf86CrtcPtr crtc = randr_crtc->devPrivate;
Bool changed = FALSE;
int o, ro;
xf86CrtcPtr *save_crtcs;
Bool save_enabled = crtc->enabled;
save_crtcs = ALLOCATE_LOCAL(config->num_crtc * sizeof (xf86CrtcPtr));
if ((randr_mode != NULL) != crtc->enabled)
changed = TRUE;
else if (randr_mode && !xf86RandRModeMatches (randr_mode, &crtc->mode))
changed = TRUE;
if (rotation != crtc->rotation)
changed = TRUE;
if (x != crtc->x || y != crtc->y)
changed = TRUE;
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
xf86CrtcPtr new_crtc;
save_crtcs[o] = output->crtc;
if (output->crtc == crtc)
new_crtc = NULL;
else
new_crtc = output->crtc;
for (ro = 0; ro < num_randr_outputs; ro++)
if (output->randr_output == randr_outputs[ro])
{
new_crtc = crtc;
break;
}
if (new_crtc != output->crtc)
{
changed = TRUE;
output->crtc = new_crtc;
}
}
/* XXX need device-independent mode setting code through an API */
if (changed)
{
crtc->enabled = randr_mode != NULL;
if (randr_mode)
{
DisplayModeRec mode;
xf86RandRModeConvert (pScrn, randr_mode, &mode);
if (!xf86CrtcSetMode (crtc, &mode, rotation, x, y))
{
crtc->enabled = save_enabled;
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
output->crtc = save_crtcs[o];
}
DEALLOCATE_LOCAL(save_crtcs);
return FALSE;
}
/*
* Save the last successful setting for EnterVT
*/
crtc->desiredMode = mode;
crtc->desiredRotation = rotation;
crtc->desiredX = x;
crtc->desiredY = y;
}
xf86DisableUnusedFunctions (pScrn);
}
DEALLOCATE_LOCAL(save_crtcs);
return xf86RandR12CrtcNotify (randr_crtc);
}
static Bool
xf86RandR12CrtcSetGamma (ScreenPtr pScreen,
RRCrtcPtr randr_crtc)
{
xf86CrtcPtr crtc = randr_crtc->devPrivate;
if (crtc->funcs->gamma_set == NULL)
return FALSE;
crtc->funcs->gamma_set(crtc, randr_crtc->gammaRed, randr_crtc->gammaGreen,
randr_crtc->gammaBlue, randr_crtc->gammaSize);
return TRUE;
}
static Bool
xf86RandR12OutputSetProperty (ScreenPtr pScreen,
RROutputPtr randr_output,
Atom property,
RRPropertyValuePtr value)
{
xf86OutputPtr output = randr_output->devPrivate;
/* If we don't have any property handler, then we don't care what the
* user is setting properties to.
*/
if (output->funcs->set_property == NULL)
return TRUE;
return output->funcs->set_property(output, property, value);
}
static Bool
xf86RandR12OutputValidateMode (ScreenPtr pScreen,
RROutputPtr randr_output,
RRModePtr randr_mode)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86OutputPtr output = randr_output->devPrivate;
DisplayModeRec mode;
xf86RandRModeConvert (pScrn, randr_mode, &mode);
if (output->funcs->mode_valid (output, &mode) != MODE_OK)
return FALSE;
return TRUE;
}
static void
xf86RandR12ModeDestroy (ScreenPtr pScreen, RRModePtr randr_mode)
{
}
/**
* Given a list of xf86 modes and a RandR Output object, construct
* RandR modes and assign them to the output
*/
static Bool
xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes)
{
DisplayModePtr mode;
RRModePtr *rrmodes = NULL;
int nmode = 0;
int npreferred = 0;
Bool ret = TRUE;
int pref;
for (mode = modes; mode; mode = mode->next)
nmode++;
if (nmode) {
rrmodes = xalloc (nmode * sizeof (RRModePtr));
if (!rrmodes)
return FALSE;
nmode = 0;
for (pref = 1; pref >= 0; pref--) {
for (mode = modes; mode; mode = mode->next) {
if ((pref != 0) == ((mode->type & M_T_PREFERRED) != 0)) {
xRRModeInfo modeInfo;
RRModePtr rrmode;
modeInfo.nameLength = strlen (mode->name);
modeInfo.width = mode->HDisplay;
modeInfo.dotClock = mode->Clock * 1000;
modeInfo.hSyncStart = mode->HSyncStart;
modeInfo.hSyncEnd = mode->HSyncEnd;
modeInfo.hTotal = mode->HTotal;
modeInfo.hSkew = mode->HSkew;
modeInfo.height = mode->VDisplay;
modeInfo.vSyncStart = mode->VSyncStart;
modeInfo.vSyncEnd = mode->VSyncEnd;
modeInfo.vTotal = mode->VTotal;
modeInfo.modeFlags = mode->Flags;
rrmode = RRModeGet (&modeInfo, mode->name);
if (rrmode) {
rrmodes[nmode++] = rrmode;
npreferred += pref;
}
}
}
}
}
ret = RROutputSetModes (randr_output, rrmodes, nmode, npreferred);
xfree (rrmodes);
return ret;
}
/*
* Mirror the current mode configuration to RandR
*/
static Bool
xf86RandR12SetInfo12 (ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
RROutputPtr *clones;
RRCrtcPtr *crtcs;
int ncrtc;
int o, c, l;
RRCrtcPtr randr_crtc;
int nclone;
clones = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr));
crtcs = ALLOCATE_LOCAL (config->num_crtc * sizeof (RRCrtcPtr));
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
ncrtc = 0;
for (c = 0; c < config->num_crtc; c++)
if (output->possible_crtcs & (1 << c))
crtcs[ncrtc++] = config->crtc[c]->randr_crtc;
if (output->crtc)
randr_crtc = output->crtc->randr_crtc;
else
randr_crtc = NULL;
if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc))
{
DEALLOCATE_LOCAL (crtcs);
DEALLOCATE_LOCAL (clones);
return FALSE;
}
RROutputSetCrtc (output->randr_output, randr_crtc);
RROutputSetPhysicalSize(output->randr_output,
output->mm_width,
output->mm_height);
xf86RROutputSetModes (output->randr_output, output->probed_modes);
switch (output->status) {
case XF86OutputStatusConnected:
RROutputSetConnection (output->randr_output, RR_Connected);
break;
case XF86OutputStatusDisconnected:
RROutputSetConnection (output->randr_output, RR_Disconnected);
break;
case XF86OutputStatusUnknown:
RROutputSetConnection (output->randr_output, RR_UnknownConnection);
break;
}
RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order);
/*
* Valid clones
*/
nclone = 0;
for (l = 0; l < config->num_output; l++)
{
xf86OutputPtr clone = config->output[l];
if (l != o && (output->possible_clones & (1 << l)))
clones[nclone++] = clone->randr_output;
}
if (!RROutputSetClones (output->randr_output, clones, nclone))
{
DEALLOCATE_LOCAL (crtcs);
DEALLOCATE_LOCAL (clones);
return FALSE;
}
}
DEALLOCATE_LOCAL (crtcs);
DEALLOCATE_LOCAL (clones);
return TRUE;
}
/*
* Query the hardware for the current state, then mirror
* that to RandR
*/
static Bool
xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86ProbeOutputModes (pScrn, 0, 0);
xf86SetScrnInfoModes (pScrn);
xf86DiDGAReInit (pScreen);
return xf86RandR12SetInfo12 (pScreen);
}
static Bool
xf86RandR12CreateObjects12 (ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
int c;
int o;
if (!RRInit ())
return FALSE;
/*
* Configure crtcs
*/
for (c = 0; c < config->num_crtc; c++)
{
xf86CrtcPtr crtc = config->crtc[c];
crtc->randr_crtc = RRCrtcCreate (pScreen, crtc);
RRCrtcGammaSetSize (crtc->randr_crtc, 256);
}
/*
* Configure outputs
*/
for (o = 0; o < config->num_output; o++)
{
xf86OutputPtr output = config->output[o];
output->randr_output = RROutputCreate (pScreen, output->name,
strlen (output->name),
output);
if (output->funcs->create_resources != NULL)
output->funcs->create_resources(output);
RRPostPendingProperties (output->randr_output);
}
return TRUE;
}
static Bool
xf86RandR12CreateScreenResources12 (ScreenPtr pScreen)
{
int c;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
for (c = 0; c < config->num_crtc; c++)
xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
RRScreenSetSizeRange (pScreen, config->minWidth, config->minHeight,
config->maxWidth, config->maxHeight);
return TRUE;
}
/*
* Something happened within the screen configuration due
* to DGA, VidMode or hot key. Tell RandR
*/
void
xf86RandR12TellChanged (ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
int c;
if (!randrp)
return;
xf86RandR12SetInfo12 (pScreen);
for (c = 0; c < config->num_crtc; c++)
xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc);
RRTellChanged (pScreen);
}
static void
xf86RandR12PointerMoved (int scrnIndex, int x, int y)
{
}
static Bool
xf86RandR12Init12 (ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
rrScrPrivPtr rp = rrGetScrPriv(pScreen);
rp->rrGetInfo = xf86RandR12GetInfo12;
rp->rrScreenSetSize = xf86RandR12ScreenSetSize;
rp->rrCrtcSet = xf86RandR12CrtcSet;
rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma;
rp->rrOutputSetProperty = xf86RandR12OutputSetProperty;
rp->rrOutputValidateMode = xf86RandR12OutputValidateMode;
rp->rrModeDestroy = xf86RandR12ModeDestroy;
rp->rrSetConfig = NULL;
pScrn->PointerMoved = xf86RandR12PointerMoved;
if (!xf86RandR12CreateObjects12 (pScreen))
return FALSE;
/*
* Configure output modes
*/
if (!xf86RandR12SetInfo12 (pScreen))
return FALSE;
return TRUE;
}
#endif
Bool
xf86RandR12PreInit (ScrnInfoPtr pScrn)
{
return TRUE;
}