/* * 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)); } static int ProcRRQueryVersion(ClientPtr client) { xRRQueryVersionReply rep; 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 = 1; rep.minorVersion = 1; if (client->swapped) { swaps(&rep.sequenceNumber); swapl(&rep.length); swapl(&rep.majorVersion); swapl(&rep.minorVersion); } WriteToClient(client, sizeof(xRRQueryVersionReply), (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 = malloc(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 = malloc(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; free(pRREvent); } } } else { client->errorValue = stuff->enable; return BadValue; } return Success; } 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 */ ProcRRQueryOutputProperty, /* 11 */ ProcRRConfigureOutputProperty, /* 12 */ ProcRRChangeOutputProperty, /* 13 */ ProcRRDeleteOutputProperty, /* 14 */ ProcRRGetOutputProperty, /* 15 */ ProcRRCreateMode, /* 16 */ ProcRRDestroyMode, /* 17 */ ProcRRAddOutputMode, /* 18 */ ProcRRDeleteOutputMode, /* 19 */ ProcRRGetCrtcInfo, /* 20 */ ProcRRSetCrtcConfig, /* 21 */ ProcRRGetCrtcGammaSize, /* 22 */ ProcRRGetCrtcGamma, /* 23 */ ProcRRSetCrtcGamma, /* 24 */ };