1706f2543Smrg/*
2706f2543Smrg * Copyright © 2006 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#include "randrstr.h"
24706f2543Smrg#include "protocol-versions.h"
25706f2543Smrg
26706f2543SmrgBool
27706f2543SmrgRRClientKnowsRates (ClientPtr	pClient)
28706f2543Smrg{
29706f2543Smrg    rrClientPriv(pClient);
30706f2543Smrg
31706f2543Smrg    return (pRRClient->major_version > 1 ||
32706f2543Smrg	    (pRRClient->major_version == 1 && pRRClient->minor_version >= 1));
33706f2543Smrg}
34706f2543Smrg
35706f2543Smrgstatic int
36706f2543SmrgProcRRQueryVersion (ClientPtr client)
37706f2543Smrg{
38706f2543Smrg    xRRQueryVersionReply rep = {0};
39706f2543Smrg    register int n;
40706f2543Smrg    REQUEST(xRRQueryVersionReq);
41706f2543Smrg    rrClientPriv(client);
42706f2543Smrg
43706f2543Smrg    REQUEST_SIZE_MATCH(xRRQueryVersionReq);
44706f2543Smrg    pRRClient->major_version = stuff->majorVersion;
45706f2543Smrg    pRRClient->minor_version = stuff->minorVersion;
46706f2543Smrg    rep.type = X_Reply;
47706f2543Smrg    rep.length = 0;
48706f2543Smrg    rep.sequenceNumber = client->sequence;
49706f2543Smrg
50706f2543Smrg    if ((stuff->majorVersion * 1000 + stuff->minorVersion) <
51706f2543Smrg        (SERVER_RANDR_MAJOR_VERSION * 1000 + SERVER_RANDR_MINOR_VERSION))
52706f2543Smrg    {
53706f2543Smrg	rep.majorVersion = stuff->majorVersion;
54706f2543Smrg	rep.minorVersion = stuff->minorVersion;
55706f2543Smrg    } else
56706f2543Smrg    {
57706f2543Smrg        rep.majorVersion = SERVER_RANDR_MAJOR_VERSION;
58706f2543Smrg        rep.minorVersion = SERVER_RANDR_MINOR_VERSION;
59706f2543Smrg    }
60706f2543Smrg
61706f2543Smrg    if (client->swapped) {
62706f2543Smrg    	swaps(&rep.sequenceNumber, n);
63706f2543Smrg    	swapl(&rep.length, n);
64706f2543Smrg	swapl(&rep.majorVersion, n);
65706f2543Smrg	swapl(&rep.minorVersion, n);
66706f2543Smrg    }
67706f2543Smrg    WriteToClient(client, sizeof(xRRQueryVersionReply), (char *)&rep);
68706f2543Smrg    return Success;
69706f2543Smrg}
70706f2543Smrg
71706f2543Smrgstatic int
72706f2543SmrgProcRRSelectInput (ClientPtr client)
73706f2543Smrg{
74706f2543Smrg    REQUEST(xRRSelectInputReq);
75706f2543Smrg    rrClientPriv(client);
76706f2543Smrg    RRTimesPtr	pTimes;
77706f2543Smrg    WindowPtr	pWin;
78706f2543Smrg    RREventPtr	pRREvent, *pHead;
79706f2543Smrg    XID		clientResource;
80706f2543Smrg    int		rc;
81706f2543Smrg
82706f2543Smrg    REQUEST_SIZE_MATCH(xRRSelectInputReq);
83706f2543Smrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess);
84706f2543Smrg    if (rc != Success)
85706f2543Smrg	return rc;
86706f2543Smrg    rc = dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id,
87706f2543Smrg				 RREventType, client, DixWriteAccess);
88706f2543Smrg    if (rc != Success && rc != BadValue)
89706f2543Smrg	return rc;
90706f2543Smrg
91706f2543Smrg    if (stuff->enable & (RRScreenChangeNotifyMask|
92706f2543Smrg			 RRCrtcChangeNotifyMask|
93706f2543Smrg			 RROutputChangeNotifyMask|
94706f2543Smrg			 RROutputPropertyNotifyMask))
95706f2543Smrg    {
96706f2543Smrg	ScreenPtr	pScreen = pWin->drawable.pScreen;
97706f2543Smrg	rrScrPriv	(pScreen);
98706f2543Smrg
99706f2543Smrg	pRREvent = NULL;
100706f2543Smrg	if (pHead)
101706f2543Smrg	{
102706f2543Smrg	    /* check for existing entry. */
103706f2543Smrg	    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
104706f2543Smrg		if (pRREvent->client == client)
105706f2543Smrg		    break;
106706f2543Smrg	}
107706f2543Smrg
108706f2543Smrg	if (!pRREvent)
109706f2543Smrg	{
110706f2543Smrg	    /* build the entry */
111706f2543Smrg	    pRREvent = (RREventPtr) malloc(sizeof (RREventRec));
112706f2543Smrg	    if (!pRREvent)
113706f2543Smrg		return BadAlloc;
114706f2543Smrg	    pRREvent->next = 0;
115706f2543Smrg	    pRREvent->client = client;
116706f2543Smrg	    pRREvent->window = pWin;
117706f2543Smrg	    pRREvent->mask = stuff->enable;
118706f2543Smrg	    /*
119706f2543Smrg	     * add a resource that will be deleted when
120706f2543Smrg	     * the client goes away
121706f2543Smrg	     */
122706f2543Smrg	    clientResource = FakeClientID (client->index);
123706f2543Smrg	    pRREvent->clientResource = clientResource;
124706f2543Smrg	    if (!AddResource (clientResource, RRClientType, (pointer)pRREvent))
125706f2543Smrg		return BadAlloc;
126706f2543Smrg	    /*
127706f2543Smrg	     * create a resource to contain a pointer to the list
128706f2543Smrg	     * of clients selecting input.  This must be indirect as
129706f2543Smrg	     * the list may be arbitrarily rearranged which cannot be
130706f2543Smrg	     * done through the resource database.
131706f2543Smrg	     */
132706f2543Smrg	    if (!pHead)
133706f2543Smrg	    {
134706f2543Smrg		pHead = (RREventPtr *) malloc(sizeof (RREventPtr));
135706f2543Smrg		if (!pHead ||
136706f2543Smrg		    !AddResource (pWin->drawable.id, RREventType, (pointer)pHead))
137706f2543Smrg		{
138706f2543Smrg		    FreeResource (clientResource, RT_NONE);
139706f2543Smrg		    return BadAlloc;
140706f2543Smrg		}
141706f2543Smrg		*pHead = 0;
142706f2543Smrg	    }
143706f2543Smrg	    pRREvent->next = *pHead;
144706f2543Smrg	    *pHead = pRREvent;
145706f2543Smrg	}
146706f2543Smrg	/*
147706f2543Smrg	 * Now see if the client needs an event
148706f2543Smrg	 */
149706f2543Smrg	if (pScrPriv)
150706f2543Smrg	{
151706f2543Smrg	    pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum];
152706f2543Smrg	    if (CompareTimeStamps (pTimes->setTime,
153706f2543Smrg				   pScrPriv->lastSetTime) != 0 ||
154706f2543Smrg		CompareTimeStamps (pTimes->configTime,
155706f2543Smrg				   pScrPriv->lastConfigTime) != 0)
156706f2543Smrg	    {
157706f2543Smrg		if (pRREvent->mask & RRScreenChangeNotifyMask)
158706f2543Smrg		{
159706f2543Smrg		    RRDeliverScreenEvent (client, pWin, pScreen);
160706f2543Smrg		}
161706f2543Smrg
162706f2543Smrg		if (pRREvent->mask & RRCrtcChangeNotifyMask)
163706f2543Smrg		{
164706f2543Smrg		    int i;
165706f2543Smrg
166706f2543Smrg		    for (i = 0; i < pScrPriv->numCrtcs; i++)
167706f2543Smrg		    {
168706f2543Smrg			RRDeliverCrtcEvent (client, pWin, pScrPriv->crtcs[i]);
169706f2543Smrg		    }
170706f2543Smrg		}
171706f2543Smrg
172706f2543Smrg		if (pRREvent->mask & RROutputChangeNotifyMask)
173706f2543Smrg		{
174706f2543Smrg		    int i;
175706f2543Smrg
176706f2543Smrg		    for (i = 0; i < pScrPriv->numOutputs; i++)
177706f2543Smrg		    {
178706f2543Smrg			RRDeliverOutputEvent (client, pWin, pScrPriv->outputs[i]);
179706f2543Smrg		    }
180706f2543Smrg		}
181706f2543Smrg
182706f2543Smrg		/* We don't check for RROutputPropertyNotifyMask, as randrproto.txt doesn't
183706f2543Smrg		 * say if there ought to be notifications of changes to output properties
184706f2543Smrg		 * if those changes occurred before the time RRSelectInput is called.
185706f2543Smrg		 */
186706f2543Smrg	    }
187706f2543Smrg	}
188706f2543Smrg    }
189706f2543Smrg    else if (stuff->enable == 0)
190706f2543Smrg    {
191706f2543Smrg	/* delete the interest */
192706f2543Smrg	if (pHead) {
193706f2543Smrg	    RREventPtr pNewRREvent = 0;
194706f2543Smrg	    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
195706f2543Smrg		if (pRREvent->client == client)
196706f2543Smrg		    break;
197706f2543Smrg		pNewRREvent = pRREvent;
198706f2543Smrg	    }
199706f2543Smrg	    if (pRREvent) {
200706f2543Smrg		FreeResource (pRREvent->clientResource, RRClientType);
201706f2543Smrg		if (pNewRREvent)
202706f2543Smrg		    pNewRREvent->next = pRREvent->next;
203706f2543Smrg		else
204706f2543Smrg		    *pHead = pRREvent->next;
205706f2543Smrg		free(pRREvent);
206706f2543Smrg	    }
207706f2543Smrg	}
208706f2543Smrg    }
209706f2543Smrg    else
210706f2543Smrg    {
211706f2543Smrg	client->errorValue = stuff->enable;
212706f2543Smrg	return BadValue;
213706f2543Smrg    }
214706f2543Smrg    return Success;
215706f2543Smrg}
216706f2543Smrg
217706f2543Smrgint (*ProcRandrVector[RRNumberRequests])(ClientPtr) = {
218706f2543Smrg    ProcRRQueryVersion,	/* 0 */
219706f2543Smrg/* we skip 1 to make old clients fail pretty immediately */
220706f2543Smrg    NULL,			/* 1 ProcRandrOldGetScreenInfo */
221706f2543Smrg/* V1.0 apps share the same set screen config request id */
222706f2543Smrg    ProcRRSetScreenConfig,	/* 2 */
223706f2543Smrg    NULL,			/* 3 ProcRandrOldScreenChangeSelectInput */
224706f2543Smrg/* 3 used to be ScreenChangeSelectInput; deprecated */
225706f2543Smrg    ProcRRSelectInput,		/* 4 */
226706f2543Smrg    ProcRRGetScreenInfo,    	/* 5 */
227706f2543Smrg/* V1.2 additions */
228706f2543Smrg    ProcRRGetScreenSizeRange,	/* 6 */
229706f2543Smrg    ProcRRSetScreenSize,	/* 7 */
230706f2543Smrg    ProcRRGetScreenResources,	/* 8 */
231706f2543Smrg    ProcRRGetOutputInfo,	/* 9 */
232706f2543Smrg    ProcRRListOutputProperties,	/* 10 */
233706f2543Smrg    ProcRRQueryOutputProperty,	/* 11 */
234706f2543Smrg    ProcRRConfigureOutputProperty,  /* 12 */
235706f2543Smrg    ProcRRChangeOutputProperty,	/* 13 */
236706f2543Smrg    ProcRRDeleteOutputProperty,	/* 14 */
237706f2543Smrg    ProcRRGetOutputProperty,	/* 15 */
238706f2543Smrg    ProcRRCreateMode,		/* 16 */
239706f2543Smrg    ProcRRDestroyMode,		/* 17 */
240706f2543Smrg    ProcRRAddOutputMode,	/* 18 */
241706f2543Smrg    ProcRRDeleteOutputMode,	/* 19 */
242706f2543Smrg    ProcRRGetCrtcInfo,		/* 20 */
243706f2543Smrg    ProcRRSetCrtcConfig,	/* 21 */
244706f2543Smrg    ProcRRGetCrtcGammaSize,	/* 22 */
245706f2543Smrg    ProcRRGetCrtcGamma,		/* 23 */
246706f2543Smrg    ProcRRSetCrtcGamma,		/* 24 */
247706f2543Smrg/* V1.3 additions */
248706f2543Smrg    ProcRRGetScreenResourcesCurrent, /* 25 */
249706f2543Smrg    ProcRRSetCrtcTransform,	/* 26 */
250706f2543Smrg    ProcRRGetCrtcTransform,	/* 27 */
251706f2543Smrg    ProcRRGetPanning,		/* 28 */
252706f2543Smrg    ProcRRSetPanning,		/* 29 */
253706f2543Smrg    ProcRRSetOutputPrimary,	/* 30 */
254706f2543Smrg    ProcRRGetOutputPrimary,	/* 31 */
255706f2543Smrg};
256706f2543Smrg
257