xserver-multidpi/randr/rrdispatch.c
2006-09-18 12:18:22 -07:00

1035 lines
25 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"
Bool
RRClientKnowsRates (ClientPtr pClient)
{
rrClientPriv(pClient);
return (pRRClient->major_version > 1 ||
(pRRClient->major_version == 1 && pRRClient->minor_version >= 1));
}
typedef struct _RR10Data {
RRScreenSizePtr sizes;
int nsize;
int nrefresh;
int size;
CARD16 refresh;
} RR10DataRec, *RR10DataPtr;
/*
* Convert 1.2 monitor data into 1.0 screen data
*/
static RR10DataPtr
RR10GetData (ScreenPtr pScreen, RROutputPtr output)
{
RR10DataPtr data;
RRScreenSizePtr size;
int nmode = output->numModes;
int i, j, k;
RRScreenRatePtr refresh;
CARD16 vRefresh;
RRModePtr mode;
/* Make sure there is plenty of space for any combination */
data = malloc (sizeof (RR10DataRec) +
sizeof (RRScreenSize) * nmode +
sizeof (RRScreenRate) * nmode);
if (!data)
return NULL;
size = (RRScreenSizePtr) (data + 1);
refresh = (RRScreenRatePtr) (size + nmode);
data->sizes = size;
data->nsize = 0;
data->nrefresh = 0;
data->size = 0;
data->refresh = 0;
for (i = 0; i < output->numModes; i++)
{
mode = output->modes[i];
for (j = 0; j < data->nsize; j++)
if (mode->mode.width == size[j].width &&
mode->mode.height == size[j].height)
break;
if (j == data->nsize)
{
size[j].id = j;
size[j].width = mode->mode.width;
size[j].height = mode->mode.height;
size[j].mmWidth = mode->mode.mmWidth;
size[j].mmHeight = mode->mode.mmHeight;
size[j].nRates = 0;
size[j].pRates = &refresh[data->nrefresh];
data->nsize++;
}
vRefresh = RRVerticalRefresh (&mode->mode);
for (k = 0; k < size[j].nRates; k++)
if (vRefresh == size[j].pRates[k].rate)
break;
if (k == size[j].nRates)
{
size[j].pRates[k].rate = vRefresh;
size[j].pRates[k].mode = mode;
size[j].nRates++;
data->nrefresh++;
}
if (mode == output->crtc->mode)
{
data->size = j;
data->refresh = vRefresh;
}
}
return data;
}
static int
ProcRRQueryVersion (ClientPtr client)
{
xRRQueryVersionReply rep;
register int n;
REQUEST(xRRQueryVersionReq);
rrClientPriv(client);
REQUEST_SIZE_MATCH(xRRQueryVersionReq);
pRRClient->major_version = stuff->majorVersion;
pRRClient->minor_version = stuff->minorVersion;
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
/*
* Report the current version; the current
* spec says they're all compatible after 1.0
*/
rep.majorVersion = RANDR_MAJOR;
rep.minorVersion = RANDR_MINOR;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.majorVersion, n);
swapl(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xRRQueryVersionReply), (char *)&rep);
return (client->noClientException);
}
static int
ProcRRGetScreenInfo (ClientPtr client)
{
REQUEST(xRRGetScreenInfoReq);
xRRGetScreenInfoReply rep;
WindowPtr pWin;
int n;
ScreenPtr pScreen;
rrScrPrivPtr pScrPriv;
CARD8 *extra;
unsigned long extraLen;
RROutputPtr output;
REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client,
SecurityReadAccess);
if (!pWin)
return BadWindow;
pScreen = pWin->drawable.pScreen;
pScrPriv = rrGetScrPriv(pScreen);
rep.pad = 0;
if (pScrPriv)
RRGetInfo (pScreen);
output = RRFirstOutput (pScreen);
if (!pScrPriv || !output)
{
rep.type = X_Reply;
rep.setOfRotations = RR_Rotate_0;;
rep.sequenceNumber = client->sequence;
rep.length = 0;
rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id;
rep.timestamp = currentTime.milliseconds;
rep.configTimestamp = currentTime.milliseconds;
rep.nSizes = 0;
rep.sizeID = 0;
rep.rotation = RR_Rotate_0;
rep.rate = 0;
rep.nrateEnts = 0;
extra = 0;
extraLen = 0;
}
else
{
int i, j;
xScreenSizes *size;
CARD16 *rates;
CARD8 *data8;
Bool has_rate = RRClientKnowsRates (client);
RR10DataPtr pData;
RRScreenSizePtr pSize;
pData = RR10GetData (pScreen, output);
if (!pData)
return BadAlloc;
rep.type = X_Reply;
rep.setOfRotations = output->crtc->rotations;
rep.sequenceNumber = client->sequence;
rep.length = 0;
rep.root = WindowTable[pWin->drawable.pScreen->myNum]->drawable.id;
rep.timestamp = pScrPriv->lastSetTime.milliseconds;
rep.configTimestamp = pScrPriv->lastConfigTime.milliseconds;
rep.rotation = output->crtc->rotation;
rep.nSizes = pData->nsize;
rep.nrateEnts = pData->nrefresh + pData->nsize;
rep.sizeID = pData->size;
rep.rate = pData->refresh;
extraLen = (rep.nSizes * sizeof (xScreenSizes) +
rep.nrateEnts * sizeof (CARD16));
extra = (CARD8 *) xalloc (extraLen);
if (!extra)
{
xfree (pData);
return BadAlloc;
}
/*
* First comes the size information
*/
size = (xScreenSizes *) extra;
rates = (CARD16 *) (size + rep.nSizes);
for (i = 0; i < pData->nsize; i++)
{
pSize = &pData->sizes[i];
size->widthInPixels = pSize->width;
size->heightInPixels = pSize->height;
size->widthInMillimeters = pSize->mmWidth;
size->heightInMillimeters = pSize->mmHeight;
if (client->swapped)
{
swaps (&size->widthInPixels, n);
swaps (&size->heightInPixels, n);
swaps (&size->widthInMillimeters, n);
swaps (&size->heightInMillimeters, n);
}
size++;
if (has_rate)
{
*rates = pSize->nRates;
if (client->swapped)
{
swaps (rates, n);
}
rates++;
for (j = 0; j < pSize->nRates; j++)
{
*rates = pSize->pRates[j].rate;
if (client->swapped)
{
swaps (rates, n);
}
rates++;
}
}
}
xfree (pData);
data8 = (CARD8 *) rates;
if (data8 - (CARD8 *) extra != extraLen)
FatalError ("RRGetScreenInfo bad extra len %ld != %ld\n",
(unsigned long)(data8 - (CARD8 *) extra), extraLen);
rep.length = (extraLen + 3) >> 2;
}
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.timestamp, n);
swaps(&rep.rotation, n);
swaps(&rep.nSizes, n);
swaps(&rep.sizeID, n);
swaps(&rep.rate, n);
swaps(&rep.nrateEnts, n);
}
WriteToClient(client, sizeof(xRRGetScreenInfoReply), (char *)&rep);
if (extraLen)
{
WriteToClient (client, extraLen, (char *) extra);
xfree (extra);
}
return (client->noClientException);
}
static int
ProcRRSetScreenConfig (ClientPtr client)
{
REQUEST(xRRSetScreenConfigReq);
xRRSetScreenConfigReply rep;
DrawablePtr pDraw;
int n;
ScreenPtr pScreen;
rrScrPrivPtr pScrPriv;
TimeStamp configTime;
TimeStamp time;
int i;
Rotation rotation;
int rate;
Bool has_rate;
RROutputPtr output;
RRModePtr mode;
RR10DataPtr pData = NULL;
RRScreenSizePtr pSize;
UpdateCurrentTime ();
if (RRClientKnowsRates (client))
{
REQUEST_SIZE_MATCH (xRRSetScreenConfigReq);
has_rate = TRUE;
}
else
{
REQUEST_SIZE_MATCH (xRR1_0SetScreenConfigReq);
has_rate = FALSE;
}
SECURITY_VERIFY_DRAWABLE(pDraw, stuff->drawable, client,
SecurityWriteAccess);
pScreen = pDraw->pScreen;
pScrPriv = rrGetScrPriv(pScreen);
time = ClientTimeToServerTime(stuff->timestamp);
configTime = ClientTimeToServerTime(stuff->configTimestamp);
if (!pScrPriv)
{
time = currentTime;
rep.status = RRSetConfigFailed;
goto sendReply;
}
if (!RRGetInfo (pScreen))
return BadAlloc;
output = RRFirstOutput (pScreen);
if (!output)
{
time = currentTime;
rep.status = RRSetConfigFailed;
goto sendReply;
}
/*
* 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;
}
pData = RR10GetData (pScreen, output);
if (!pData)
return BadAlloc;
if (stuff->sizeID >= pData->nsize)
{
/*
* Invalid size ID
*/
client->errorValue = stuff->sizeID;
xfree (pData);
return BadValue;
}
pSize = &pData->sizes[stuff->sizeID];
/*
* 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;
xfree (pData);
return BadValue;
}
if ((~output->crtc->rotations) & rotation)
{
/*
* requested rotation or reflection not supported by screen
*/
client->errorValue = stuff->rotation;
xfree (pData);
return BadMatch;
}
/*
* Validate requested refresh
*/
if (has_rate)
rate = (int) stuff->rate;
else
rate = 0;
if (rate)
{
for (i = 0; i < pSize->nRates; i++)
{
if (pSize->pRates[i].rate == rate)
break;
}
if (i == pSize->nRates)
{
/*
* Invalid rate
*/
client->errorValue = rate;
xfree (pData);
return BadValue;
}
mode = pSize->pRates[i].mode;
}
else
mode = pSize->pRates[0].mode;
/*
* 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;
}
rep.status = RRCrtcSet (output->crtc, mode, 0, 0, stuff->rotation,
1, &output);
sendReply:
if (pData)
xfree (pData);
rep.type = X_Reply;
/* rep.status has already been filled in */
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.newTimestamp = pScrPriv->lastSetTime.milliseconds;
rep.newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds;
rep.root = WindowTable[pDraw->pScreen->myNum]->drawable.id;
if (client->swapped)
{
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.newTimestamp, n);
swapl(&rep.newConfigTimestamp, n);
swapl(&rep.root, n);
}
WriteToClient(client, sizeof(xRRSetScreenConfigReply), (char *)&rep);
return (client->noClientException);
}
static int
ProcRRSelectInput (ClientPtr client)
{
REQUEST(xRRSelectInputReq);
rrClientPriv(client);
RRTimesPtr pTimes;
WindowPtr pWin;
RREventPtr pRREvent, *pHead;
XID clientResource;
REQUEST_SIZE_MATCH(xRRSelectInputReq);
pWin = SecurityLookupWindow (stuff->window, client, SecurityWriteAccess);
if (!pWin)
return BadWindow;
pHead = (RREventPtr *)SecurityLookupIDByType(client,
pWin->drawable.id, RREventType,
SecurityWriteAccess);
if (stuff->enable & (RRScreenChangeNotifyMask|
RRCrtcChangeNotifyMask|
RROutputChangeNotifyMask))
{
ScreenPtr pScreen = pWin->drawable.pScreen;
rrScrPriv (pScreen);
pRREvent = NULL;
if (pHead)
{
/* check for existing entry. */
for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
if (pRREvent->client == client)
break;
}
if (!pRREvent)
{
/* build the entry */
pRREvent = (RREventPtr) xalloc (sizeof (RREventRec));
if (!pRREvent)
return BadAlloc;
pRREvent->next = 0;
pRREvent->client = client;
pRREvent->window = pWin;
pRREvent->mask = stuff->enable;
/*
* add a resource that will be deleted when
* the client goes away
*/
clientResource = FakeClientID (client->index);
pRREvent->clientResource = clientResource;
if (!AddResource (clientResource, RRClientType, (pointer)pRREvent))
return BadAlloc;
/*
* create a resource to contain a pointer to the list
* of clients selecting input. This must be indirect as
* the list may be arbitrarily rearranged which cannot be
* done through the resource database.
*/
if (!pHead)
{
pHead = (RREventPtr *) xalloc (sizeof (RREventPtr));
if (!pHead ||
!AddResource (pWin->drawable.id, RREventType, (pointer)pHead))
{
FreeResource (clientResource, RT_NONE);
return BadAlloc;
}
*pHead = 0;
}
pRREvent->next = *pHead;
*pHead = pRREvent;
}
/*
* Now see if the client needs an event
*/
if (pScrPriv && (pRREvent->mask & RRScreenChangeNotifyMask))
{
pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum];
if (CompareTimeStamps (pTimes->setTime,
pScrPriv->lastSetTime) != 0 ||
CompareTimeStamps (pTimes->configTime,
pScrPriv->lastConfigTime) != 0)
{
RRDeliverScreenEvent (client, pWin, pScreen);
}
}
}
else if (stuff->enable == 0)
{
/* delete the interest */
if (pHead) {
RREventPtr pNewRREvent = 0;
for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
if (pRREvent->client == client)
break;
pNewRREvent = pRREvent;
}
if (pRREvent) {
FreeResource (pRREvent->clientResource, RRClientType);
if (pNewRREvent)
pNewRREvent->next = pRREvent->next;
else
*pHead = pRREvent->next;
xfree (pRREvent);
}
}
}
else
{
client->errorValue = stuff->enable;
return BadValue;
}
return Success;
}
/*
* Retrieve valid screen size range
*/
static int
ProcRRGetScreenSizeRange (ClientPtr client)
{
REQUEST(xRRGetScreenSizeRangeReq);
xRRGetScreenSizeRangeReply rep;
WindowPtr pWin;
ScreenPtr pScreen;
rrScrPrivPtr pScrPriv;
REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client,
SecurityReadAccess);
if (!pWin)
return BadWindow;
pScreen = pWin->drawable.pScreen;
pScrPriv = rrGetScrPriv(pScreen);
rep.type = X_Reply;
rep.pad = 0;
rep.sequenceNumber = client->sequence;
rep.length = 0;
if (pScrPriv)
{
RRGetInfo (pScreen);
rep.minWidth = pScrPriv->minWidth;
rep.minHeight = pScrPriv->minHeight;
rep.maxWidth = pScrPriv->maxWidth;
rep.maxHeight = pScrPriv->maxHeight;
}
else
{
rep.maxWidth = rep.minWidth = pScreen->width;
rep.maxHeight = rep.minHeight = pScreen->height;
}
if (client->swapped)
{
int n;
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.minWidth, n);
swaps(&rep.minHeight, n);
swaps(&rep.maxWidth, n);
swaps(&rep.maxHeight, n);
}
WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), (char *)&rep);
return (client->noClientException);
}
static int ProcRRSetScreenSize (ClientPtr client)
{
REQUEST(xRRSetScreenSizeReq);
WindowPtr pWin;
ScreenPtr pScreen;
rrScrPrivPtr pScrPriv;
RRCrtcPtr crtc;
int i;
REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client,
SecurityReadAccess);
if (!pWin)
return BadWindow;
pScreen = pWin->drawable.pScreen;
pScrPriv = rrGetScrPriv(pScreen);
if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width)
{
client->errorValue = stuff->width;
return BadValue;
}
if (stuff->height < pScrPriv->minHeight ||
pScrPriv->maxHeight < stuff->height)
{
client->errorValue = stuff->height;
return BadValue;
}
for (i = 0; i < pScrPriv->numCrtcs; i++) {
crtc = pScrPriv->crtcs[i];
if (crtc->mode &&
(crtc->x + crtc->mode->mode.width > stuff->width ||
crtc->y + crtc->mode->mode.height > stuff->height))
return BadMatch;
}
if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0)
{
client->errorValue = 0;
return BadValue;
}
if (!RRScreenSizeSet (pScreen,
stuff->width, stuff->height,
stuff->widthInMillimeters,
stuff->heightInMillimeters))
{
return BadMatch;
}
return Success;
}
static int
ProcRRGetScreenResources (ClientPtr client)
{
REQUEST(xRRGetScreenResourcesReq);
REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRGetOutputInfo (ClientPtr client)
{
REQUEST(xRRGetOutputInfoReq);;
REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRListOutputProperties (ClientPtr client)
{
REQUEST(xRRListOutputPropertiesReq);
REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRChangeOutputProperty (ClientPtr client)
{
REQUEST(xRRChangeOutputPropertyReq);
REQUEST_SIZE_MATCH(xRRChangeOutputPropertyReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRDeleteOutputProperty (ClientPtr client)
{
REQUEST(xRRDeleteOutputPropertyReq);
REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRGetOutputProperty (ClientPtr client)
{
REQUEST(xRRGetOutputPropertyReq);
REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRCreateMode (ClientPtr client)
{
REQUEST(xRRCreateModeReq);
REQUEST_SIZE_MATCH(xRRCreateModeReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRDestroyMode (ClientPtr client)
{
REQUEST(xRRDestroyModeReq);
REQUEST_SIZE_MATCH(xRRDestroyModeReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRAddOutputMode (ClientPtr client)
{
REQUEST(xRRAddOutputModeReq);
REQUEST_SIZE_MATCH(xRRAddOutputModeReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRDeleteOutputMode (ClientPtr client)
{
REQUEST(xRRDeleteOutputModeReq);
REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRGetCrtcInfo (ClientPtr client)
{
REQUEST(xRRGetCrtcInfoReq);
REQUEST_SIZE_MATCH(xRRGetCrtcInfoReq);
(void) stuff;
return BadImplementation;
}
static 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;
}
outputs = xalloc (numOutputs * sizeof (RROutputPtr));
if (!outputs)
return BadAlloc;
outputIds = (RROutput *) (stuff + 1);
for (i = 0; i < numOutputs; i++)
{
outputs[i] = LookupIDByType (outputIds[i], RROutputType);
if (!outputs[i])
{
client->errorValue = outputIds[i];
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[j]->numCrtcs)
return BadMatch;
/* validate mode for this output */
for (j = 0; j < outputs[i]->numModes; j++)
if (outputs[i]->modes[j] == mode)
break;
if (j == outputs[j]->numModes)
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 (!RRGetInfo (pScreen))
return BadAlloc;
/*
* 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;
}
/*
* 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;
return BadValue;
}
if ((~crtc->rotations) & rotation)
{
/*
* requested rotation or reflection not supported by screen
*/
client->errorValue = stuff->rotation;
return BadMatch;
}
if (stuff->x + mode->mode.width > pScreen->width)
{
client->errorValue = stuff->x;
return BadValue;
}
if (stuff->y + mode->mode.height > pScreen->height)
{
client->errorValue = stuff->y;
return BadValue;
}
/*
* 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;
}
rep.status = RRCrtcSet (crtc, mode, stuff->x, stuff->y,
rotation, numOutputs, outputs);
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;
}
static int
ProcRRGetCrtcGammaSize (ClientPtr client)
{
REQUEST(xRRGetCrtcGammaSizeReq);
REQUEST_SIZE_MATCH(xRRGetCrtcGammaSizeReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRGetCrtcGamma (ClientPtr client)
{
REQUEST(xRRGetCrtcGammaReq);
REQUEST_SIZE_MATCH(xRRGetCrtcGammaReq);
(void) stuff;
return BadImplementation;
}
static int
ProcRRSetCrtcGamma (ClientPtr client)
{
REQUEST(xRRSetCrtcGammaReq);
REQUEST_SIZE_MATCH(xRRSetCrtcGammaReq);
(void) stuff;
return BadImplementation;
}
int (*ProcRandrVector[RRNumberRequests])(ClientPtr) = {
ProcRRQueryVersion, /* 0 */
/* we skip 1 to make old clients fail pretty immediately */
NULL, /* 1 ProcRandrOldGetScreenInfo */
/* V1.0 apps share the same set screen config request id */
ProcRRSetScreenConfig, /* 2 */
NULL, /* 3 ProcRandrOldScreenChangeSelectInput */
/* 3 used to be ScreenChangeSelectInput; deprecated */
ProcRRSelectInput, /* 4 */
ProcRRGetScreenInfo, /* 5 */
/* V1.2 additions */
ProcRRGetScreenSizeRange, /* 6 */
ProcRRSetScreenSize, /* 7 */
ProcRRGetScreenResources, /* 8 */
ProcRRGetOutputInfo, /* 9 */
ProcRRListOutputProperties, /* 10 */
ProcRRChangeOutputProperty, /* 11 */
ProcRRDeleteOutputProperty, /* 12 */
ProcRRGetOutputProperty, /* 13 */
ProcRRCreateMode, /* 14 */
ProcRRDestroyMode, /* 15 */
ProcRRAddOutputMode, /* 16 */
ProcRRDeleteOutputMode, /* 17 */
ProcRRGetCrtcInfo, /* 18 */
ProcRRSetCrtcConfig, /* 19 */
ProcRRGetCrtcGammaSize, /* 20 */
ProcRRGetCrtcGamma, /* 21 */
ProcRRSetCrtcGamma, /* 22 */
};