1/*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "protocol-versions.h"
25
26Bool
27RRClientKnowsRates(ClientPtr pClient)
28{
29    rrClientPriv(pClient);
30
31    return version_compare(pRRClient->major_version, pRRClient->minor_version,
32                           1, 1) >= 0;
33}
34
35static int
36ProcRRQueryVersion(ClientPtr client)
37{
38    xRRQueryVersionReply rep = {
39        .type = X_Reply,
40        .sequenceNumber = client->sequence,
41        .length = 0
42    };
43    REQUEST(xRRQueryVersionReq);
44    rrClientPriv(client);
45
46    REQUEST_SIZE_MATCH(xRRQueryVersionReq);
47    pRRClient->major_version = stuff->majorVersion;
48    pRRClient->minor_version = stuff->minorVersion;
49
50    if (version_compare(stuff->majorVersion, stuff->minorVersion,
51                        SERVER_RANDR_MAJOR_VERSION,
52                        SERVER_RANDR_MINOR_VERSION) < 0) {
53        rep.majorVersion = stuff->majorVersion;
54        rep.minorVersion = stuff->minorVersion;
55    }
56    else {
57        rep.majorVersion = SERVER_RANDR_MAJOR_VERSION;
58        rep.minorVersion = SERVER_RANDR_MINOR_VERSION;
59    }
60
61    if (client->swapped) {
62        swaps(&rep.sequenceNumber);
63        swapl(&rep.length);
64        swapl(&rep.majorVersion);
65        swapl(&rep.minorVersion);
66    }
67    WriteToClient(client, sizeof(xRRQueryVersionReply), &rep);
68    return Success;
69}
70
71static int
72ProcRRSelectInput(ClientPtr client)
73{
74    REQUEST(xRRSelectInputReq);
75    rrClientPriv(client);
76    RRTimesPtr pTimes;
77    WindowPtr pWin;
78    RREventPtr pRREvent, *pHead;
79    XID clientResource;
80    int rc;
81
82    REQUEST_SIZE_MATCH(xRRSelectInputReq);
83    rc = dixLookupWindow(&pWin, stuff->window, client, DixReceiveAccess);
84    if (rc != Success)
85        return rc;
86    rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id,
87                                 RREventType, client, DixWriteAccess);
88    if (rc != Success && rc != BadValue)
89        return rc;
90
91    if (stuff->enable & (RRScreenChangeNotifyMask |
92                         RRCrtcChangeNotifyMask |
93                         RROutputChangeNotifyMask |
94                         RROutputPropertyNotifyMask |
95                         RRProviderChangeNotifyMask |
96                         RRProviderPropertyNotifyMask |
97                         RRResourceChangeNotifyMask)) {
98        ScreenPtr pScreen = pWin->drawable.pScreen;
99
100        rrScrPriv(pScreen);
101
102        pRREvent = NULL;
103        if (pHead) {
104            /* check for existing entry. */
105            for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
106                if (pRREvent->client == client)
107                    break;
108        }
109
110        if (!pRREvent) {
111            /* build the entry */
112            pRREvent = (RREventPtr) malloc(sizeof(RREventRec));
113            if (!pRREvent)
114                return BadAlloc;
115            pRREvent->next = 0;
116            pRREvent->client = client;
117            pRREvent->window = pWin;
118            pRREvent->mask = stuff->enable;
119            /*
120             * add a resource that will be deleted when
121             * the client goes away
122             */
123            clientResource = FakeClientID(client->index);
124            pRREvent->clientResource = clientResource;
125            if (!AddResource(clientResource, RRClientType, (void *) pRREvent))
126                return BadAlloc;
127            /*
128             * create a resource to contain a pointer to the list
129             * of clients selecting input.  This must be indirect as
130             * the list may be arbitrarily rearranged which cannot be
131             * done through the resource database.
132             */
133            if (!pHead) {
134                pHead = (RREventPtr *) malloc(sizeof(RREventPtr));
135                if (!pHead ||
136                    !AddResource(pWin->drawable.id, RREventType,
137                                 (void *) pHead)) {
138                    FreeResource(clientResource, RT_NONE);
139                    return BadAlloc;
140                }
141                *pHead = 0;
142            }
143            pRREvent->next = *pHead;
144            *pHead = pRREvent;
145        }
146        /*
147         * Now see if the client needs an event
148         */
149        if (pScrPriv) {
150            pTimes = &((RRTimesPtr) (pRRClient + 1))[pScreen->myNum];
151            if (CompareTimeStamps(pTimes->setTime,
152                                  pScrPriv->lastSetTime) != 0 ||
153                CompareTimeStamps(pTimes->configTime,
154                                  pScrPriv->lastConfigTime) != 0) {
155                if (pRREvent->mask & RRScreenChangeNotifyMask) {
156                    RRDeliverScreenEvent(client, pWin, pScreen);
157                }
158
159                if (pRREvent->mask & RRCrtcChangeNotifyMask) {
160                    int i;
161
162                    for (i = 0; i < pScrPriv->numCrtcs; i++) {
163                        RRDeliverCrtcEvent(client, pWin, pScrPriv->crtcs[i]);
164                    }
165                }
166
167                if (pRREvent->mask & RROutputChangeNotifyMask) {
168                    int i;
169
170                    for (i = 0; i < pScrPriv->numOutputs; i++) {
171                        RRDeliverOutputEvent(client, pWin,
172                                             pScrPriv->outputs[i]);
173                    }
174                }
175
176                /* We don't check for RROutputPropertyNotifyMask, as randrproto.txt doesn't
177                 * say if there ought to be notifications of changes to output properties
178                 * if those changes occurred before the time RRSelectInput is called.
179                 */
180            }
181        }
182    }
183    else if (stuff->enable == 0) {
184        /* delete the interest */
185        if (pHead) {
186            RREventPtr pNewRREvent = 0;
187
188            for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) {
189                if (pRREvent->client == client)
190                    break;
191                pNewRREvent = pRREvent;
192            }
193            if (pRREvent) {
194                FreeResource(pRREvent->clientResource, RRClientType);
195                if (pNewRREvent)
196                    pNewRREvent->next = pRREvent->next;
197                else
198                    *pHead = pRREvent->next;
199                free(pRREvent);
200            }
201        }
202    }
203    else {
204        client->errorValue = stuff->enable;
205        return BadValue;
206    }
207    return Success;
208}
209
210int (*ProcRandrVector[RRNumberRequests]) (ClientPtr) = {
211    ProcRRQueryVersion,         /* 0 */
212/* we skip 1 to make old clients fail pretty immediately */
213        NULL,                   /* 1 ProcRandrOldGetScreenInfo */
214/* V1.0 apps share the same set screen config request id */
215        ProcRRSetScreenConfig,  /* 2 */
216        NULL,                   /* 3 ProcRandrOldScreenChangeSelectInput */
217/* 3 used to be ScreenChangeSelectInput; deprecated */
218        ProcRRSelectInput,      /* 4 */
219        ProcRRGetScreenInfo,    /* 5 */
220/* V1.2 additions */
221        ProcRRGetScreenSizeRange,       /* 6 */
222        ProcRRSetScreenSize,    /* 7 */
223        ProcRRGetScreenResources,       /* 8 */
224        ProcRRGetOutputInfo,    /* 9 */
225        ProcRRListOutputProperties,     /* 10 */
226        ProcRRQueryOutputProperty,      /* 11 */
227        ProcRRConfigureOutputProperty,  /* 12 */
228        ProcRRChangeOutputProperty,     /* 13 */
229        ProcRRDeleteOutputProperty,     /* 14 */
230        ProcRRGetOutputProperty,        /* 15 */
231        ProcRRCreateMode,       /* 16 */
232        ProcRRDestroyMode,      /* 17 */
233        ProcRRAddOutputMode,    /* 18 */
234        ProcRRDeleteOutputMode, /* 19 */
235        ProcRRGetCrtcInfo,      /* 20 */
236        ProcRRSetCrtcConfig,    /* 21 */
237        ProcRRGetCrtcGammaSize, /* 22 */
238        ProcRRGetCrtcGamma,     /* 23 */
239        ProcRRSetCrtcGamma,     /* 24 */
240/* V1.3 additions */
241        ProcRRGetScreenResourcesCurrent,        /* 25 */
242        ProcRRSetCrtcTransform, /* 26 */
243        ProcRRGetCrtcTransform, /* 27 */
244        ProcRRGetPanning,       /* 28 */
245        ProcRRSetPanning,       /* 29 */
246        ProcRRSetOutputPrimary, /* 30 */
247        ProcRRGetOutputPrimary, /* 31 */
248/* V1.4 additions */
249        ProcRRGetProviders,     /* 32 */
250        ProcRRGetProviderInfo,  /* 33 */
251        ProcRRSetProviderOffloadSink, /* 34 */
252        ProcRRSetProviderOutputSource, /* 35 */
253        ProcRRListProviderProperties,    /* 36 */
254        ProcRRQueryProviderProperty,     /* 37 */
255        ProcRRConfigureProviderProperty, /* 38 */
256        ProcRRChangeProviderProperty, /* 39 */
257        ProcRRDeleteProviderProperty, /* 40 */
258        ProcRRGetProviderProperty,    /* 41 */
259/* V1.5 additions */
260        ProcRRGetMonitors,            /* 42 */
261        ProcRRSetMonitor,             /* 43 */
262        ProcRRDeleteMonitor,          /* 44 */
263/* V1.6 additions */
264        ProcRRCreateLease,            /* 45 */
265        ProcRRFreeLease,              /* 46 */
266};
267