/* * 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 + BadCrtc; } 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 + BadMode; } 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 + BadOutput; } /* 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 */ };