961 lines
21 KiB
C
961 lines
21 KiB
C
/*
|
|
* Copyright © 2006 Keith Packard
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "randrstr.h"
|
|
#include "swaprep.h"
|
|
#include "registry.h"
|
|
|
|
RESTYPE RRCrtcType;
|
|
|
|
/*
|
|
* Notify the CRTC of some change
|
|
*/
|
|
void
|
|
RRCrtcChanged (RRCrtcPtr crtc, Bool layoutChanged)
|
|
{
|
|
ScreenPtr pScreen = crtc->pScreen;
|
|
|
|
crtc->changed = TRUE;
|
|
if (pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
|
|
pScrPriv->changed = TRUE;
|
|
/*
|
|
* Send ConfigureNotify on any layout change
|
|
*/
|
|
if (layoutChanged)
|
|
pScrPriv->layoutChanged = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Create a CRTC
|
|
*/
|
|
RRCrtcPtr
|
|
RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
|
|
{
|
|
RRCrtcPtr crtc;
|
|
RRCrtcPtr *crtcs;
|
|
rrScrPrivPtr pScrPriv;
|
|
|
|
if (!RRInit())
|
|
return NULL;
|
|
|
|
pScrPriv = rrGetScrPriv(pScreen);
|
|
|
|
/* make space for the crtc pointer */
|
|
if (pScrPriv->numCrtcs)
|
|
crtcs = xrealloc (pScrPriv->crtcs,
|
|
(pScrPriv->numCrtcs + 1) * sizeof (RRCrtcPtr));
|
|
else
|
|
crtcs = xalloc (sizeof (RRCrtcPtr));
|
|
if (!crtcs)
|
|
return FALSE;
|
|
pScrPriv->crtcs = crtcs;
|
|
|
|
crtc = xcalloc (1, sizeof (RRCrtcRec));
|
|
if (!crtc)
|
|
return NULL;
|
|
crtc->id = FakeClientID (0);
|
|
crtc->pScreen = pScreen;
|
|
crtc->mode = NULL;
|
|
crtc->x = 0;
|
|
crtc->y = 0;
|
|
crtc->rotation = RR_Rotate_0;
|
|
crtc->rotations = RR_Rotate_0;
|
|
crtc->outputs = NULL;
|
|
crtc->numOutputs = 0;
|
|
crtc->gammaSize = 0;
|
|
crtc->gammaRed = crtc->gammaBlue = crtc->gammaGreen = NULL;
|
|
crtc->changed = FALSE;
|
|
crtc->devPrivate = devPrivate;
|
|
|
|
if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
|
|
return NULL;
|
|
|
|
/* attach the screen and crtc together */
|
|
crtc->pScreen = pScreen;
|
|
pScrPriv->crtcs[pScrPriv->numCrtcs++] = crtc;
|
|
|
|
return crtc;
|
|
}
|
|
|
|
/*
|
|
* Set the allowed rotations on a CRTC
|
|
*/
|
|
void
|
|
RRCrtcSetRotations (RRCrtcPtr crtc, Rotation rotations)
|
|
{
|
|
crtc->rotations = rotations;
|
|
}
|
|
|
|
/*
|
|
* Notify the extension that the Crtc has been reconfigured,
|
|
* the driver calls this whenever it has updated the mode
|
|
*/
|
|
Bool
|
|
RRCrtcNotify (RRCrtcPtr crtc,
|
|
RRModePtr mode,
|
|
int x,
|
|
int y,
|
|
Rotation rotation,
|
|
int numOutputs,
|
|
RROutputPtr *outputs)
|
|
{
|
|
int i, j;
|
|
|
|
/*
|
|
* Check to see if any of the new outputs were
|
|
* not in the old list and mark them as changed
|
|
*/
|
|
for (i = 0; i < numOutputs; i++)
|
|
{
|
|
for (j = 0; j < crtc->numOutputs; j++)
|
|
if (outputs[i] == crtc->outputs[j])
|
|
break;
|
|
if (j == crtc->numOutputs)
|
|
{
|
|
outputs[i]->crtc = crtc;
|
|
RROutputChanged (outputs[i], FALSE);
|
|
RRCrtcChanged (crtc, FALSE);
|
|
}
|
|
}
|
|
/*
|
|
* Check to see if any of the old outputs are
|
|
* not in the new list and mark them as changed
|
|
*/
|
|
for (j = 0; j < crtc->numOutputs; j++)
|
|
{
|
|
for (i = 0; i < numOutputs; i++)
|
|
if (outputs[i] == crtc->outputs[j])
|
|
break;
|
|
if (i == numOutputs)
|
|
{
|
|
if (crtc->outputs[j]->crtc == crtc)
|
|
crtc->outputs[j]->crtc = NULL;
|
|
RROutputChanged (crtc->outputs[j], FALSE);
|
|
RRCrtcChanged (crtc, FALSE);
|
|
}
|
|
}
|
|
/*
|
|
* Reallocate the crtc output array if necessary
|
|
*/
|
|
if (numOutputs != crtc->numOutputs)
|
|
{
|
|
RROutputPtr *newoutputs;
|
|
|
|
if (numOutputs)
|
|
{
|
|
if (crtc->numOutputs)
|
|
newoutputs = xrealloc (crtc->outputs,
|
|
numOutputs * sizeof (RROutputPtr));
|
|
else
|
|
newoutputs = xalloc (numOutputs * sizeof (RROutputPtr));
|
|
if (!newoutputs)
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (crtc->outputs)
|
|
xfree (crtc->outputs);
|
|
newoutputs = NULL;
|
|
}
|
|
crtc->outputs = newoutputs;
|
|
crtc->numOutputs = numOutputs;
|
|
}
|
|
/*
|
|
* Copy the new list of outputs into the crtc
|
|
*/
|
|
memcpy (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr));
|
|
/*
|
|
* Update remaining crtc fields
|
|
*/
|
|
if (mode != crtc->mode)
|
|
{
|
|
if (crtc->mode)
|
|
RRModeDestroy (crtc->mode);
|
|
crtc->mode = mode;
|
|
if (mode != NULL)
|
|
mode->refcnt++;
|
|
RRCrtcChanged (crtc, TRUE);
|
|
}
|
|
if (x != crtc->x)
|
|
{
|
|
crtc->x = x;
|
|
RRCrtcChanged (crtc, TRUE);
|
|
}
|
|
if (y != crtc->y)
|
|
{
|
|
crtc->y = y;
|
|
RRCrtcChanged (crtc, TRUE);
|
|
}
|
|
if (rotation != crtc->rotation)
|
|
{
|
|
crtc->rotation = rotation;
|
|
RRCrtcChanged (crtc, TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
RRDeliverCrtcEvent (ClientPtr client, WindowPtr pWin, RRCrtcPtr crtc)
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
rrScrPriv (pScreen);
|
|
xRRCrtcChangeNotifyEvent ce;
|
|
RRModePtr mode = crtc->mode;
|
|
|
|
ce.type = RRNotify + RREventBase;
|
|
ce.subCode = RRNotify_CrtcChange;
|
|
ce.sequenceNumber = client->sequence;
|
|
ce.timestamp = pScrPriv->lastSetTime.milliseconds;
|
|
ce.window = pWin->drawable.id;
|
|
ce.crtc = crtc->id;
|
|
ce.rotation = crtc->rotation;
|
|
if (mode)
|
|
{
|
|
ce.mode = mode->mode.id;
|
|
ce.x = crtc->x;
|
|
ce.y = crtc->y;
|
|
ce.width = mode->mode.width;
|
|
ce.height = mode->mode.height;
|
|
}
|
|
else
|
|
{
|
|
ce.mode = None;
|
|
ce.x = 0;
|
|
ce.y = 0;
|
|
ce.width = 0;
|
|
ce.height = 0;
|
|
}
|
|
WriteEventsToClient (client, 1, (xEvent *) &ce);
|
|
}
|
|
|
|
static Bool
|
|
RRCrtcPendingProperties (RRCrtcPtr crtc)
|
|
{
|
|
ScreenPtr pScreen = crtc->pScreen;
|
|
rrScrPriv(pScreen);
|
|
int o;
|
|
|
|
for (o = 0; o < pScrPriv->numOutputs; o++)
|
|
{
|
|
RROutputPtr output = pScrPriv->outputs[o];
|
|
if (output->crtc == crtc && output->pendingProperties)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Request that the Crtc be reconfigured
|
|
*/
|
|
Bool
|
|
RRCrtcSet (RRCrtcPtr crtc,
|
|
RRModePtr mode,
|
|
int x,
|
|
int y,
|
|
Rotation rotation,
|
|
int numOutputs,
|
|
RROutputPtr *outputs)
|
|
{
|
|
ScreenPtr pScreen = crtc->pScreen;
|
|
Bool ret = FALSE;
|
|
rrScrPriv(pScreen);
|
|
|
|
/* See if nothing changed */
|
|
if (crtc->mode == mode &&
|
|
crtc->x == x &&
|
|
crtc->y == y &&
|
|
crtc->rotation == rotation &&
|
|
crtc->numOutputs == numOutputs &&
|
|
!memcmp (crtc->outputs, outputs, numOutputs * sizeof (RROutputPtr)) &&
|
|
!RRCrtcPendingProperties (crtc))
|
|
{
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#if RANDR_12_INTERFACE
|
|
if (pScrPriv->rrCrtcSet)
|
|
{
|
|
ret = (*pScrPriv->rrCrtcSet) (pScreen, crtc, mode, x, y,
|
|
rotation, numOutputs, outputs);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#if RANDR_10_INTERFACE
|
|
if (pScrPriv->rrSetConfig)
|
|
{
|
|
RRScreenSize size;
|
|
RRScreenRate rate;
|
|
|
|
if (!mode)
|
|
{
|
|
RRCrtcNotify (crtc, NULL, x, y, rotation, 0, NULL);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
size.width = mode->mode.width;
|
|
size.height = mode->mode.height;
|
|
if (outputs[0]->mmWidth && outputs[0]->mmHeight)
|
|
{
|
|
size.mmWidth = outputs[0]->mmWidth;
|
|
size.mmHeight = outputs[0]->mmHeight;
|
|
}
|
|
else
|
|
{
|
|
size.mmWidth = pScreen->mmWidth;
|
|
size.mmHeight = pScreen->mmHeight;
|
|
}
|
|
size.nRates = 1;
|
|
rate.rate = RRVerticalRefresh (&mode->mode);
|
|
size.pRates = &rate;
|
|
ret = (*pScrPriv->rrSetConfig) (pScreen, rotation, rate.rate, &size);
|
|
/*
|
|
* Old 1.0 interface tied screen size to mode size
|
|
*/
|
|
if (ret)
|
|
{
|
|
RRCrtcNotify (crtc, mode, x, y, rotation, 1, outputs);
|
|
RRScreenSizeNotify (pScreen);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (ret)
|
|
{
|
|
int o;
|
|
RRTellChanged (pScreen);
|
|
|
|
for (o = 0; o < numOutputs; o++)
|
|
RRPostPendingProperties (outputs[o]);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Destroy a Crtc at shutdown
|
|
*/
|
|
void
|
|
RRCrtcDestroy (RRCrtcPtr crtc)
|
|
{
|
|
FreeResource (crtc->id, 0);
|
|
}
|
|
|
|
static int
|
|
RRCrtcDestroyResource (pointer value, XID pid)
|
|
{
|
|
RRCrtcPtr crtc = (RRCrtcPtr) value;
|
|
ScreenPtr pScreen = crtc->pScreen;
|
|
|
|
if (pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
int i;
|
|
|
|
for (i = 0; i < pScrPriv->numCrtcs; i++)
|
|
{
|
|
if (pScrPriv->crtcs[i] == crtc)
|
|
{
|
|
memmove (pScrPriv->crtcs + i, pScrPriv->crtcs + i + 1,
|
|
(pScrPriv->numCrtcs - (i + 1)) * sizeof (RRCrtcPtr));
|
|
--pScrPriv->numCrtcs;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (crtc->gammaRed)
|
|
xfree (crtc->gammaRed);
|
|
if (crtc->mode)
|
|
RRModeDestroy (crtc->mode);
|
|
xfree (crtc);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Request that the Crtc gamma be changed
|
|
*/
|
|
|
|
Bool
|
|
RRCrtcGammaSet (RRCrtcPtr crtc,
|
|
CARD16 *red,
|
|
CARD16 *green,
|
|
CARD16 *blue)
|
|
{
|
|
Bool ret = TRUE;
|
|
#if RANDR_12_INTERFACE
|
|
ScreenPtr pScreen = crtc->pScreen;
|
|
#endif
|
|
|
|
memcpy (crtc->gammaRed, red, crtc->gammaSize * sizeof (CARD16));
|
|
memcpy (crtc->gammaGreen, green, crtc->gammaSize * sizeof (CARD16));
|
|
memcpy (crtc->gammaBlue, blue, crtc->gammaSize * sizeof (CARD16));
|
|
#if RANDR_12_INTERFACE
|
|
if (pScreen)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
if (pScrPriv->rrCrtcSetGamma)
|
|
ret = (*pScrPriv->rrCrtcSetGamma) (pScreen, crtc);
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Notify the extension that the Crtc gamma has been changed
|
|
* The driver calls this whenever it has changed the gamma values
|
|
* in the RRCrtcRec
|
|
*/
|
|
|
|
Bool
|
|
RRCrtcGammaNotify (RRCrtcPtr crtc)
|
|
{
|
|
return TRUE; /* not much going on here */
|
|
}
|
|
|
|
/**
|
|
* Returns the width/height that the crtc scans out from the framebuffer
|
|
*/
|
|
void
|
|
RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height)
|
|
{
|
|
if (crtc->mode == NULL) {
|
|
*width = 0;
|
|
*height = 0;
|
|
return;
|
|
}
|
|
|
|
switch (crtc->rotation & 0xf) {
|
|
case RR_Rotate_0:
|
|
case RR_Rotate_180:
|
|
*width = crtc->mode->mode.width;
|
|
*height = crtc->mode->mode.height;
|
|
break;
|
|
case RR_Rotate_90:
|
|
case RR_Rotate_270:
|
|
*width = crtc->mode->mode.height;
|
|
*height = crtc->mode->mode.width;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the size of the gamma table at server startup time
|
|
*/
|
|
|
|
Bool
|
|
RRCrtcGammaSetSize (RRCrtcPtr crtc,
|
|
int size)
|
|
{
|
|
CARD16 *gamma;
|
|
|
|
if (size == crtc->gammaSize)
|
|
return TRUE;
|
|
if (size)
|
|
{
|
|
gamma = xalloc (size * 3 * sizeof (CARD16));
|
|
if (!gamma)
|
|
return FALSE;
|
|
}
|
|
else
|
|
gamma = NULL;
|
|
if (crtc->gammaRed)
|
|
xfree (crtc->gammaRed);
|
|
crtc->gammaRed = gamma;
|
|
crtc->gammaGreen = gamma + size;
|
|
crtc->gammaBlue = gamma + size*2;
|
|
crtc->gammaSize = size;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Initialize crtc type
|
|
*/
|
|
Bool
|
|
RRCrtcInit (void)
|
|
{
|
|
RRCrtcType = CreateNewResourceType (RRCrtcDestroyResource);
|
|
if (!RRCrtcType)
|
|
return FALSE;
|
|
RegisterResourceName (RRCrtcType, "CRTC");
|
|
return TRUE;
|
|
}
|
|
|
|
int
|
|
ProcRRGetCrtcInfo (ClientPtr client)
|
|
{
|
|
REQUEST(xRRGetCrtcInfoReq);
|
|
xRRGetCrtcInfoReply rep;
|
|
RRCrtcPtr crtc;
|
|
CARD8 *extra;
|
|
unsigned long extraLen;
|
|
ScreenPtr pScreen;
|
|
rrScrPrivPtr pScrPriv;
|
|
RRModePtr mode;
|
|
RROutput *outputs;
|
|
RROutput *possible;
|
|
int i, j, k, n;
|
|
int width, height;
|
|
|
|
REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
|
|
crtc = LookupCrtc(client, stuff->crtc, DixReadAccess);
|
|
|
|
if (!crtc)
|
|
return RRErrorBase + BadRRCrtc;
|
|
|
|
/* All crtcs must be associated with screens before client
|
|
* requests are processed
|
|
*/
|
|
pScreen = crtc->pScreen;
|
|
pScrPriv = rrGetScrPriv(pScreen);
|
|
|
|
mode = crtc->mode;
|
|
|
|
rep.type = X_Reply;
|
|
rep.status = RRSetConfigSuccess;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.length = 0;
|
|
rep.timestamp = pScrPriv->lastSetTime.milliseconds;
|
|
rep.x = crtc->x;
|
|
rep.y = crtc->y;
|
|
RRCrtcGetScanoutSize (crtc, &width, &height);
|
|
rep.width = width;
|
|
rep.height = height;
|
|
rep.mode = mode ? mode->mode.id : 0;
|
|
rep.rotation = crtc->rotation;
|
|
rep.rotations = crtc->rotations;
|
|
rep.nOutput = crtc->numOutputs;
|
|
k = 0;
|
|
for (i = 0; i < pScrPriv->numOutputs; i++)
|
|
for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
|
|
if (pScrPriv->outputs[i]->crtcs[j] == crtc)
|
|
k++;
|
|
rep.nPossibleOutput = k;
|
|
|
|
rep.length = rep.nOutput + rep.nPossibleOutput;
|
|
|
|
extraLen = rep.length << 2;
|
|
if (extraLen)
|
|
{
|
|
extra = xalloc (extraLen);
|
|
if (!extra)
|
|
return BadAlloc;
|
|
}
|
|
else
|
|
extra = NULL;
|
|
|
|
outputs = (RROutput *) extra;
|
|
possible = (RROutput *) (outputs + rep.nOutput);
|
|
|
|
for (i = 0; i < crtc->numOutputs; i++)
|
|
{
|
|
outputs[i] = crtc->outputs[i]->id;
|
|
if (client->swapped)
|
|
swapl (&outputs[i], n);
|
|
}
|
|
k = 0;
|
|
for (i = 0; i < pScrPriv->numOutputs; i++)
|
|
for (j = 0; j < pScrPriv->outputs[i]->numCrtcs; j++)
|
|
if (pScrPriv->outputs[i]->crtcs[j] == crtc)
|
|
{
|
|
possible[k] = pScrPriv->outputs[i]->id;
|
|
if (client->swapped)
|
|
swapl (&possible[k], n);
|
|
k++;
|
|
}
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.length, n);
|
|
swapl(&rep.timestamp, n);
|
|
swaps(&rep.x, n);
|
|
swaps(&rep.y, n);
|
|
swaps(&rep.width, n);
|
|
swaps(&rep.height, n);
|
|
swapl(&rep.mode, n);
|
|
swaps(&rep.rotation, n);
|
|
swaps(&rep.rotations, n);
|
|
swaps(&rep.nOutput, n);
|
|
swaps(&rep.nPossibleOutput, n);
|
|
}
|
|
WriteToClient(client, sizeof(xRRGetCrtcInfoReply), (char *)&rep);
|
|
if (extraLen)
|
|
{
|
|
WriteToClient (client, extraLen, (char *) extra);
|
|
xfree (extra);
|
|
}
|
|
|
|
return client->noClientException;
|
|
}
|
|
|
|
int
|
|
ProcRRSetCrtcConfig (ClientPtr client)
|
|
{
|
|
REQUEST(xRRSetCrtcConfigReq);
|
|
xRRSetCrtcConfigReply rep;
|
|
ScreenPtr pScreen;
|
|
rrScrPrivPtr pScrPriv;
|
|
RRCrtcPtr crtc;
|
|
RRModePtr mode;
|
|
int numOutputs;
|
|
RROutputPtr *outputs = NULL;
|
|
RROutput *outputIds;
|
|
TimeStamp configTime;
|
|
TimeStamp time;
|
|
Rotation rotation;
|
|
int i, j;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xRRSetCrtcConfigReq);
|
|
numOutputs = (stuff->length - (SIZEOF (xRRSetCrtcConfigReq) >> 2));
|
|
|
|
crtc = LookupIDByType (stuff->crtc, RRCrtcType);
|
|
if (!crtc)
|
|
{
|
|
client->errorValue = stuff->crtc;
|
|
return RRErrorBase + BadRRCrtc;
|
|
}
|
|
if (stuff->mode == None)
|
|
{
|
|
mode = NULL;
|
|
if (numOutputs > 0)
|
|
return BadMatch;
|
|
}
|
|
else
|
|
{
|
|
mode = LookupIDByType (stuff->mode, RRModeType);
|
|
if (!mode)
|
|
{
|
|
client->errorValue = stuff->mode;
|
|
return RRErrorBase + BadRRMode;
|
|
}
|
|
if (numOutputs == 0)
|
|
return BadMatch;
|
|
}
|
|
if (numOutputs)
|
|
{
|
|
outputs = xalloc (numOutputs * sizeof (RROutputPtr));
|
|
if (!outputs)
|
|
return BadAlloc;
|
|
}
|
|
else
|
|
outputs = NULL;
|
|
|
|
outputIds = (RROutput *) (stuff + 1);
|
|
for (i = 0; i < numOutputs; i++)
|
|
{
|
|
outputs[i] = (RROutputPtr) LookupIDByType (outputIds[i], RROutputType);
|
|
if (!outputs[i])
|
|
{
|
|
client->errorValue = outputIds[i];
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return RRErrorBase + BadRROutput;
|
|
}
|
|
/* validate crtc for this output */
|
|
for (j = 0; j < outputs[i]->numCrtcs; j++)
|
|
if (outputs[i]->crtcs[j] == crtc)
|
|
break;
|
|
if (j == outputs[i]->numCrtcs)
|
|
{
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadMatch;
|
|
}
|
|
/* validate mode for this output */
|
|
for (j = 0; j < outputs[i]->numModes + outputs[i]->numUserModes; j++)
|
|
{
|
|
RRModePtr m = (j < outputs[i]->numModes ?
|
|
outputs[i]->modes[j] :
|
|
outputs[i]->userModes[j - outputs[i]->numModes]);
|
|
if (m == mode)
|
|
break;
|
|
}
|
|
if (j == outputs[i]->numModes + outputs[i]->numUserModes)
|
|
{
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadMatch;
|
|
}
|
|
}
|
|
/* validate clones */
|
|
for (i = 0; i < numOutputs; i++)
|
|
{
|
|
for (j = 0; j < numOutputs; j++)
|
|
{
|
|
int k;
|
|
if (i == j)
|
|
continue;
|
|
for (k = 0; k < outputs[i]->numClones; k++)
|
|
{
|
|
if (outputs[i]->clones[k] == outputs[j])
|
|
break;
|
|
}
|
|
if (k == outputs[i]->numClones)
|
|
{
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadMatch;
|
|
}
|
|
}
|
|
}
|
|
|
|
pScreen = crtc->pScreen;
|
|
pScrPriv = rrGetScrPriv(pScreen);
|
|
|
|
time = ClientTimeToServerTime(stuff->timestamp);
|
|
configTime = ClientTimeToServerTime(stuff->configTimestamp);
|
|
|
|
if (!pScrPriv)
|
|
{
|
|
time = currentTime;
|
|
rep.status = RRSetConfigFailed;
|
|
goto sendReply;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* if the client's config timestamp is not the same as the last config
|
|
* timestamp, then the config information isn't up-to-date and
|
|
* can't even be validated
|
|
*/
|
|
if (CompareTimeStamps (configTime, pScrPriv->lastConfigTime) != 0)
|
|
{
|
|
rep.status = RRSetConfigInvalidConfigTime;
|
|
goto sendReply;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Validate requested rotation
|
|
*/
|
|
rotation = (Rotation) stuff->rotation;
|
|
|
|
/* test the rotation bits only! */
|
|
switch (rotation & 0xf) {
|
|
case RR_Rotate_0:
|
|
case RR_Rotate_90:
|
|
case RR_Rotate_180:
|
|
case RR_Rotate_270:
|
|
break;
|
|
default:
|
|
/*
|
|
* Invalid rotation
|
|
*/
|
|
client->errorValue = stuff->rotation;
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadValue;
|
|
}
|
|
|
|
if (mode)
|
|
{
|
|
if ((~crtc->rotations) & rotation)
|
|
{
|
|
/*
|
|
* requested rotation or reflection not supported by screen
|
|
*/
|
|
client->errorValue = stuff->rotation;
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadMatch;
|
|
}
|
|
|
|
#ifdef RANDR_12_INTERFACE
|
|
/*
|
|
* Check screen size bounds if the DDX provides a 1.2 interface
|
|
* for setting screen size. Else, assume the CrtcSet sets
|
|
* the size along with the mode
|
|
*/
|
|
if (pScrPriv->rrScreenSetSize)
|
|
{
|
|
int source_width = mode->mode.width;
|
|
int source_height = mode->mode.height;
|
|
|
|
if ((rotation & 0xf) == RR_Rotate_90 || (rotation & 0xf) == RR_Rotate_270)
|
|
{
|
|
source_width = mode->mode.height;
|
|
source_height = mode->mode.width;
|
|
}
|
|
if (stuff->x + source_width > pScreen->width)
|
|
{
|
|
client->errorValue = stuff->x;
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadValue;
|
|
}
|
|
|
|
if (stuff->y + source_height > pScreen->height)
|
|
{
|
|
client->errorValue = stuff->y;
|
|
if (outputs)
|
|
xfree (outputs);
|
|
return BadValue;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Make sure the requested set-time is not older than
|
|
* the last set-time
|
|
*/
|
|
if (CompareTimeStamps (time, pScrPriv->lastSetTime) < 0)
|
|
{
|
|
rep.status = RRSetConfigInvalidTime;
|
|
goto sendReply;
|
|
}
|
|
|
|
if (!RRCrtcSet (crtc, mode, stuff->x, stuff->y,
|
|
rotation, numOutputs, outputs))
|
|
{
|
|
rep.status = RRSetConfigFailed;
|
|
goto sendReply;
|
|
}
|
|
rep.status = RRSetConfigSuccess;
|
|
|
|
sendReply:
|
|
if (outputs)
|
|
xfree (outputs);
|
|
|
|
rep.type = X_Reply;
|
|
/* rep.status has already been filled in */
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.newTimestamp = pScrPriv->lastConfigTime.milliseconds;
|
|
|
|
if (client->swapped)
|
|
{
|
|
int n;
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.length, n);
|
|
swapl(&rep.newTimestamp, n);
|
|
}
|
|
WriteToClient(client, sizeof(xRRSetCrtcConfigReply), (char *)&rep);
|
|
|
|
return client->noClientException;
|
|
}
|
|
|
|
int
|
|
ProcRRGetCrtcGammaSize (ClientPtr client)
|
|
{
|
|
REQUEST(xRRGetCrtcGammaSizeReq);
|
|
xRRGetCrtcGammaSizeReply reply;
|
|
RRCrtcPtr crtc;
|
|
int n;
|
|
|
|
REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
|
|
crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
|
|
if (!crtc)
|
|
return RRErrorBase + BadRRCrtc;
|
|
|
|
reply.type = X_Reply;
|
|
reply.sequenceNumber = client->sequence;
|
|
reply.length = 0;
|
|
reply.size = crtc->gammaSize;
|
|
if (client->swapped) {
|
|
swaps (&reply.sequenceNumber, n);
|
|
swapl (&reply.length, n);
|
|
swaps (&reply.size, n);
|
|
}
|
|
WriteToClient (client, sizeof (xRRGetCrtcGammaSizeReply), (char *) &reply);
|
|
return client->noClientException;
|
|
}
|
|
|
|
int
|
|
ProcRRGetCrtcGamma (ClientPtr client)
|
|
{
|
|
REQUEST(xRRGetCrtcGammaReq);
|
|
xRRGetCrtcGammaReply reply;
|
|
RRCrtcPtr crtc;
|
|
int n;
|
|
unsigned long len;
|
|
char *extra;
|
|
|
|
REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
|
|
crtc = LookupCrtc (client, stuff->crtc, DixReadAccess);
|
|
if (!crtc)
|
|
return RRErrorBase + BadRRCrtc;
|
|
|
|
len = crtc->gammaSize * 3 * 2;
|
|
|
|
if (crtc->gammaSize) {
|
|
extra = xalloc(len);
|
|
if (!extra)
|
|
return BadAlloc;
|
|
}
|
|
|
|
reply.type = X_Reply;
|
|
reply.sequenceNumber = client->sequence;
|
|
reply.length = (len + 3) >> 2;
|
|
reply.size = crtc->gammaSize;
|
|
if (client->swapped) {
|
|
swaps (&reply.sequenceNumber, n);
|
|
swapl (&reply.length, n);
|
|
swaps (&reply.size, n);
|
|
}
|
|
WriteToClient (client, sizeof (xRRGetCrtcGammaReply), (char *) &reply);
|
|
if (crtc->gammaSize)
|
|
{
|
|
memcpy(extra, crtc->gammaRed, len);
|
|
client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write;
|
|
WriteSwappedDataToClient (client, len, extra);
|
|
xfree(extra);
|
|
}
|
|
return client->noClientException;
|
|
}
|
|
|
|
int
|
|
ProcRRSetCrtcGamma (ClientPtr client)
|
|
{
|
|
REQUEST(xRRSetCrtcGammaReq);
|
|
RRCrtcPtr crtc;
|
|
unsigned long len;
|
|
CARD16 *red, *green, *blue;
|
|
|
|
REQUEST_AT_LEAST_SIZE(xRRSetCrtcGammaReq);
|
|
crtc = LookupCrtc (client, stuff->crtc, DixWriteAccess);
|
|
if (!crtc)
|
|
return RRErrorBase + BadRRCrtc;
|
|
|
|
len = client->req_len - (sizeof (xRRSetCrtcGammaReq) >> 2);
|
|
if (len < (stuff->size * 3 + 1) >> 1)
|
|
return BadLength;
|
|
|
|
if (stuff->size != crtc->gammaSize)
|
|
return BadMatch;
|
|
|
|
red = (CARD16 *) (stuff + 1);
|
|
green = red + crtc->gammaSize;
|
|
blue = green + crtc->gammaSize;
|
|
|
|
RRCrtcGammaSet (crtc, red, green, blue);
|
|
|
|
return Success;
|
|
}
|
|
|