present_request.c revision 1b5d61b8
1/*
2 * Copyright © 2013 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#ifdef HAVE_XORG_CONFIG_H
24#include <xorg-config.h>
25#endif
26
27#include "present_priv.h"
28#include "randrstr.h"
29#include <protocol-versions.h>
30
31static int
32proc_present_query_version(ClientPtr client)
33{
34    REQUEST(xPresentQueryVersionReq);
35    xPresentQueryVersionReply rep = {
36        .type = X_Reply,
37        .sequenceNumber = client->sequence,
38        .length = 0,
39        .majorVersion = SERVER_PRESENT_MAJOR_VERSION,
40        .minorVersion = SERVER_PRESENT_MINOR_VERSION
41    };
42
43    REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
44    /* From presentproto:
45     *
46     * The client sends the highest supported version to the server
47     * and the server sends the highest version it supports, but no
48     * higher than the requested version.
49     */
50
51    if (rep.majorVersion > stuff->majorVersion ||
52        rep.minorVersion > stuff->minorVersion) {
53        rep.majorVersion = stuff->majorVersion;
54        rep.minorVersion = stuff->minorVersion;
55    }
56
57    if (client->swapped) {
58        swaps(&rep.sequenceNumber);
59        swapl(&rep.length);
60        swapl(&rep.majorVersion);
61        swapl(&rep.minorVersion);
62    }
63    WriteToClient(client, sizeof(rep), &rep);
64    return Success;
65}
66
67#define VERIFY_FENCE_OR_NONE(fence_ptr, fence_id, client, access) do {  \
68        if ((fence_id) == None)                                         \
69            (fence_ptr) = NULL;                                         \
70        else {                                                          \
71            int __rc__ = SyncVerifyFence(&fence_ptr, fence_id, client, access); \
72            if (__rc__ != Success)                                      \
73                return __rc__;                                          \
74        }                                                               \
75    } while (0)
76
77#define VERIFY_CRTC_OR_NONE(crtc_ptr, crtc_id, client, access) do {     \
78        if ((crtc_id) == None)                                          \
79            (crtc_ptr) = NULL;                                          \
80        else {                                                          \
81            VERIFY_RR_CRTC(crtc_id, crtc_ptr, access);                  \
82        }                                                               \
83    } while (0)
84
85static int
86proc_present_pixmap(ClientPtr client)
87{
88    REQUEST(xPresentPixmapReq);
89    WindowPtr           window;
90    PixmapPtr           pixmap;
91    RegionPtr           valid = NULL;
92    RegionPtr           update = NULL;
93    SyncFence           *wait_fence;
94    SyncFence           *idle_fence;
95    RRCrtcPtr           target_crtc;
96    int                 ret;
97    int                 nnotifies;
98    present_notify_ptr  notifies = NULL;
99
100    REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
101    ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess);
102    if (ret != Success)
103        return ret;
104    ret = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess);
105    if (ret != Success)
106        return ret;
107
108    if (window->drawable.depth != pixmap->drawable.depth)
109        return BadMatch;
110
111    VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess);
112    VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess);
113
114    VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess);
115
116    VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
117    VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
118
119    if (stuff->options & ~(PresentAllOptions)) {
120        client->errorValue = stuff->options;
121        return BadValue;
122    }
123
124    /*
125     * Check to see if remainder is sane
126     */
127    if (stuff->divisor == 0) {
128        if (stuff->remainder != 0) {
129            client->errorValue = (CARD32) stuff->remainder;
130            return BadValue;
131        }
132    } else {
133        if (stuff->remainder >= stuff->divisor) {
134            client->errorValue = (CARD32) stuff->remainder;
135            return BadValue;
136        }
137    }
138
139    nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq);
140    if (nnotifies % sizeof (xPresentNotify))
141        return BadLength;
142
143    nnotifies /= sizeof (xPresentNotify);
144    if (nnotifies) {
145        ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), &notifies);
146        if (ret != Success)
147            return ret;
148    }
149
150    ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
151                         stuff->x_off, stuff->y_off, target_crtc,
152                         wait_fence, idle_fence, stuff->options,
153                         stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
154    if (ret != Success)
155        present_destroy_notifies(notifies, nnotifies);
156    return ret;
157}
158
159static int
160proc_present_notify_msc(ClientPtr client)
161{
162    REQUEST(xPresentNotifyMSCReq);
163    WindowPtr   window;
164    int         rc;
165
166    REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
167    rc = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
168    if (rc != Success)
169        return rc;
170
171    /*
172     * Check to see if remainder is sane
173     */
174    if (stuff->divisor == 0) {
175        if (stuff->remainder != 0) {
176            client->errorValue = (CARD32) stuff->remainder;
177            return BadValue;
178        }
179    } else {
180        if (stuff->remainder >= stuff->divisor) {
181            client->errorValue = (CARD32) stuff->remainder;
182            return BadValue;
183        }
184    }
185
186    return present_notify_msc(window, stuff->serial,
187                              stuff->target_msc, stuff->divisor, stuff->remainder);
188}
189
190static int
191proc_present_select_input (ClientPtr client)
192{
193    REQUEST(xPresentSelectInputReq);
194    WindowPtr window;
195    int rc;
196
197    REQUEST_SIZE_MATCH(xPresentSelectInputReq);
198
199    rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
200    if (rc != Success)
201        return rc;
202
203    if (stuff->eventMask & ~PresentAllEvents) {
204        client->errorValue = stuff->eventMask;
205        return BadValue;
206    }
207    return present_select_input(client, stuff->eid, window, stuff->eventMask);
208}
209
210static int
211proc_present_query_capabilities (ClientPtr client)
212{
213    REQUEST(xPresentQueryCapabilitiesReq);
214    xPresentQueryCapabilitiesReply rep = {
215        .type = X_Reply,
216        .sequenceNumber = client->sequence,
217        .length = 0,
218    };
219    WindowPtr   window;
220    RRCrtcPtr   crtc = NULL;
221    int         r;
222
223    REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
224    r = dixLookupWindow(&window, stuff->target, client, DixGetAttrAccess);
225    switch (r) {
226    case Success:
227        crtc = present_get_crtc(window);
228        break;
229    case BadWindow:
230        VERIFY_RR_CRTC(stuff->target, crtc, DixGetAttrAccess);
231        break;
232    default:
233        return r;
234    }
235
236    rep.capabilities = present_query_capabilities(crtc);
237
238    if (client->swapped) {
239        swaps(&rep.sequenceNumber);
240        swapl(&rep.length);
241        swapl(&rep.capabilities);
242    }
243    WriteToClient(client, sizeof(rep), &rep);
244    return Success;
245}
246
247static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
248    proc_present_query_version,            /* 0 */
249    proc_present_pixmap,                   /* 1 */
250    proc_present_notify_msc,               /* 2 */
251    proc_present_select_input,             /* 3 */
252    proc_present_query_capabilities,       /* 4 */
253};
254
255int
256proc_present_dispatch(ClientPtr client)
257{
258    REQUEST(xReq);
259    if (stuff->data >= PresentNumberRequests || !proc_present_vector[stuff->data])
260        return BadRequest;
261    return (*proc_present_vector[stuff->data]) (client);
262}
263
264static int _X_COLD
265sproc_present_query_version(ClientPtr client)
266{
267    REQUEST(xPresentQueryVersionReq);
268    REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
269
270    swaps(&stuff->length);
271    swapl(&stuff->majorVersion);
272    swapl(&stuff->minorVersion);
273    return (*proc_present_vector[stuff->presentReqType]) (client);
274}
275
276static int _X_COLD
277sproc_present_pixmap(ClientPtr client)
278{
279    REQUEST(xPresentPixmapReq);
280    REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
281
282    swaps(&stuff->length);
283    swapl(&stuff->window);
284    swapl(&stuff->pixmap);
285    swapl(&stuff->valid);
286    swapl(&stuff->update);
287    swaps(&stuff->x_off);
288    swaps(&stuff->y_off);
289    swapll(&stuff->target_msc);
290    swapll(&stuff->divisor);
291    swapll(&stuff->remainder);
292    swapl(&stuff->idle_fence);
293    return (*proc_present_vector[stuff->presentReqType]) (client);
294}
295
296static int _X_COLD
297sproc_present_notify_msc(ClientPtr client)
298{
299    REQUEST(xPresentNotifyMSCReq);
300    REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
301
302    swaps(&stuff->length);
303    swapl(&stuff->window);
304    swapll(&stuff->target_msc);
305    swapll(&stuff->divisor);
306    swapll(&stuff->remainder);
307    return (*proc_present_vector[stuff->presentReqType]) (client);
308}
309
310static int _X_COLD
311sproc_present_select_input (ClientPtr client)
312{
313    REQUEST(xPresentSelectInputReq);
314    REQUEST_SIZE_MATCH(xPresentSelectInputReq);
315
316    swaps(&stuff->length);
317    swapl(&stuff->window);
318    swapl(&stuff->eventMask);
319    return (*proc_present_vector[stuff->presentReqType]) (client);
320}
321
322static int _X_COLD
323sproc_present_query_capabilities (ClientPtr client)
324{
325    REQUEST(xPresentQueryCapabilitiesReq);
326    REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
327    swaps(&stuff->length);
328    swapl(&stuff->target);
329    return (*proc_present_vector[stuff->presentReqType]) (client);
330}
331
332static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
333    sproc_present_query_version,           /* 0 */
334    sproc_present_pixmap,                  /* 1 */
335    sproc_present_notify_msc,              /* 2 */
336    sproc_present_select_input,            /* 3 */
337    sproc_present_query_capabilities,      /* 4 */
338};
339
340int _X_COLD
341sproc_present_dispatch(ClientPtr client)
342{
343    REQUEST(xReq);
344    if (stuff->data >= PresentNumberRequests || !sproc_present_vector[stuff->data])
345        return BadRequest;
346    return (*sproc_present_vector[stuff->data]) (client);
347}
348