xserver/randr/rrdispatch.c

279 lines
11 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 <dix-config.h>
#include "dix/dix_priv.h"
#include "randr/randrstr_priv.h"
#include "os/fmt.h"
#include "protocol-versions.h"
Bool
RRClientKnowsRates(ClientPtr pClient)
{
rrClientPriv(pClient);
return version_compare(pRRClient->major_version, pRRClient->minor_version,
1, 1) >= 0;
}
int
ProcRRQueryVersion(ClientPtr client)
{
xRRQueryVersionReply rep = {
.type = X_Reply,
.sequenceNumber = client->sequence,
};
REQUEST(xRRQueryVersionReq);
rrClientPriv(client);
REQUEST_SIZE_MATCH(xRRQueryVersionReq);
pRRClient->major_version = stuff->majorVersion;
pRRClient->minor_version = stuff->minorVersion;
if (version_compare(stuff->majorVersion, stuff->minorVersion,
SERVER_RANDR_MAJOR_VERSION,
SERVER_RANDR_MINOR_VERSION) < 0) {
rep.majorVersion = stuff->majorVersion;
rep.minorVersion = stuff->minorVersion;
}
else {
rep.majorVersion = SERVER_RANDR_MAJOR_VERSION;
rep.minorVersion = SERVER_RANDR_MINOR_VERSION;
}
if (client->swapped) {
swaps(&rep.sequenceNumber);
swapl(&rep.length);
swapl(&rep.majorVersion);
swapl(&rep.minorVersion);
}
WriteToClient(client, sizeof(xRRQueryVersionReply), &rep);
return Success;
}
int
ProcRRSelectInput(ClientPtr client)
{
REQUEST(xRRSelectInputReq);
rrClientPriv(client);
RRTimesPtr pTimes;
WindowPtr pWin;
RREventPtr pRREvent, *pHead;
XID clientResource;
int rc;
REQUEST_SIZE_MATCH(xRRSelectInputReq);
rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess);
if (rc != Success)
return rc;
rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
RREventType, client, DixWriteAccess);
if (rc != Success && rc != BadValue)
return rc;
if (stuff->enable & (RRScreenChangeNotifyMask |
RRCrtcChangeNotifyMask |
RROutputChangeNotifyMask |
RROutputPropertyNotifyMask |
RRProviderChangeNotifyMask |
RRProviderPropertyNotifyMask |
RRResourceChangeNotifyMask)) {
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) 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, (void *) 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 *) malloc(sizeof(RREventPtr));
if (!pHead ||
!AddResource(pWin->drawable.id, RREventType,
(void *) pHead)) {
FreeResource(clientResource, X11_RESTYPE_NONE);
return BadAlloc;
}
*pHead = 0;
}
pRREvent->next = *pHead;
*pHead = pRREvent;
}
/*
* Now see if the client needs an event
*/
if (pScrPriv) {
pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum];
if (CompareTimeStamps(pTimes->setTime,
pScrPriv->lastSetTime) != 0 ||
CompareTimeStamps(pTimes->configTime,
pScrPriv->lastConfigTime) != 0) {
if (pRREvent->mask & RRScreenChangeNotifyMask) {
RRDeliverScreenEvent(client, pWin, pScreen);
}
if (pRREvent->mask & RRCrtcChangeNotifyMask) {
int i;
for (i = 0; i < pScrPriv->numCrtcs; i++) {
RRDeliverCrtcEvent(client, pWin, pScrPriv->crtcs[i]);
}
}
if (pRREvent->mask & RROutputChangeNotifyMask) {
int i;
for (i = 0; i < pScrPriv->numOutputs; i++) {
RRDeliverOutputEvent(client, pWin,
pScrPriv->outputs[i]);
}
}
/* We don't check for RROutputPropertyNotifyMask, as randrproto.txt doesn't
* say if there ought to be notifications of changes to output properties
* if those changes occurred before the time RRSelectInput is called.
*/
}
}
}
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
ProcRRDispatch(ClientPtr client)
{
REQUEST(xReq);
UpdateCurrentTimeIf();
switch (stuff->data) {
case X_RRQueryVersion: return ProcRRQueryVersion(client);
case X_RRSetScreenConfig: return ProcRRSetScreenConfig(client);
case X_RRSelectInput: return ProcRRSelectInput(client);
case X_RRGetScreenInfo: return ProcRRGetScreenInfo(client);
/* V1.2 additions */
case X_RRGetScreenSizeRange: return ProcRRGetScreenSizeRange(client);
case X_RRSetScreenSize: return ProcRRSetScreenSize(client);
case X_RRGetScreenResources: return ProcRRGetScreenResources(client);
case X_RRGetOutputInfo: return ProcRRGetOutputInfo(client);
case X_RRListOutputProperties: return ProcRRListOutputProperties(client);
case X_RRQueryOutputProperty: return ProcRRQueryOutputProperty(client);
case X_RRConfigureOutputProperty: return ProcRRConfigureOutputProperty(client);
case X_RRChangeOutputProperty: return ProcRRChangeOutputProperty(client);
case X_RRDeleteOutputProperty: return ProcRRDeleteOutputProperty(client);
case X_RRGetOutputProperty: return ProcRRGetOutputProperty(client);
case X_RRCreateMode: return ProcRRCreateMode(client);
case X_RRDestroyMode: return ProcRRDestroyMode(client);
case X_RRAddOutputMode: return ProcRRAddOutputMode(client);
case X_RRDeleteOutputMode: return ProcRRDeleteOutputMode(client);
case X_RRGetCrtcInfo: return ProcRRGetCrtcInfo(client);
case X_RRSetCrtcConfig: return ProcRRSetCrtcConfig(client);
case X_RRGetCrtcGammaSize: return ProcRRGetCrtcGammaSize(client);
case X_RRGetCrtcGamma: return ProcRRGetCrtcGamma(client);
case X_RRSetCrtcGamma: return ProcRRSetCrtcGamma(client);
/* V1.3 additions */
case X_RRGetScreenResourcesCurrent: return ProcRRGetScreenResourcesCurrent(client);
case X_RRSetCrtcTransform: return ProcRRSetCrtcTransform(client);
case X_RRGetCrtcTransform: return ProcRRGetCrtcTransform(client);
case X_RRGetPanning: return ProcRRGetPanning(client);
case X_RRSetPanning: return ProcRRSetPanning(client);
case X_RRSetOutputPrimary: return ProcRRSetOutputPrimary(client);
case X_RRGetOutputPrimary: return ProcRRGetOutputPrimary(client);
/* V1.4 additions */
case X_RRGetProviders: return ProcRRGetProviders(client);
case X_RRGetProviderInfo: return ProcRRGetProviderInfo(client);
case X_RRSetProviderOffloadSink: return ProcRRSetProviderOffloadSink(client);
case X_RRSetProviderOutputSource: return ProcRRSetProviderOutputSource(client);
case X_RRListProviderProperties: return ProcRRListProviderProperties(client);
case X_RRQueryProviderProperty: return ProcRRQueryProviderProperty(client);
case X_RRConfigureProviderProperty: return ProcRRConfigureProviderProperty(client);
case X_RRChangeProviderProperty: return ProcRRChangeProviderProperty(client);
case X_RRDeleteProviderProperty: return ProcRRDeleteProviderProperty(client);
case X_RRGetProviderProperty: return ProcRRGetProviderProperty(client);
/* V1.5 additions */
case X_RRGetMonitors: return ProcRRGetMonitors(client);
case X_RRSetMonitor: return ProcRRSetMonitor(client);
case X_RRDeleteMonitor: return ProcRRDeleteMonitor(client);
/* V1.6 additions */
case X_RRCreateLease: return ProcRRCreateLease(client);
case X_RRFreeLease: return ProcRRFreeLease(client);
}
return BadRequest;
}