1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2013 Keith Packard
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, distribute, and sell this software and its
5*4882a593Smuzhiyun * documentation for any purpose is hereby granted without fee, provided that
6*4882a593Smuzhiyun * the above copyright notice appear in all copies and that both that copyright
7*4882a593Smuzhiyun * notice and this permission notice appear in supporting documentation, and
8*4882a593Smuzhiyun * that the name of the copyright holders not be used in advertising or
9*4882a593Smuzhiyun * publicity pertaining to distribution of the software without specific,
10*4882a593Smuzhiyun * written prior permission. The copyright holders make no representations
11*4882a593Smuzhiyun * about the suitability of this software for any purpose. It is provided "as
12*4882a593Smuzhiyun * is" without express or implied warranty.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15*4882a593Smuzhiyun * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16*4882a593Smuzhiyun * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18*4882a593Smuzhiyun * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19*4882a593Smuzhiyun * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20*4882a593Smuzhiyun * OF THIS SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #ifdef HAVE_XORG_CONFIG_H
24*4882a593Smuzhiyun #include <xorg-config.h>
25*4882a593Smuzhiyun #endif
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "present_priv.h"
28*4882a593Smuzhiyun #include "randrstr.h"
29*4882a593Smuzhiyun #include <protocol-versions.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun static int
proc_present_query_version(ClientPtr client)32*4882a593Smuzhiyun proc_present_query_version(ClientPtr client)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun REQUEST(xPresentQueryVersionReq);
35*4882a593Smuzhiyun xPresentQueryVersionReply rep = {
36*4882a593Smuzhiyun .type = X_Reply,
37*4882a593Smuzhiyun .sequenceNumber = client->sequence,
38*4882a593Smuzhiyun .length = 0,
39*4882a593Smuzhiyun .majorVersion = SERVER_PRESENT_MAJOR_VERSION,
40*4882a593Smuzhiyun .minorVersion = SERVER_PRESENT_MINOR_VERSION
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
44*4882a593Smuzhiyun /* From presentproto:
45*4882a593Smuzhiyun *
46*4882a593Smuzhiyun * The client sends the highest supported version to the server
47*4882a593Smuzhiyun * and the server sends the highest version it supports, but no
48*4882a593Smuzhiyun * higher than the requested version.
49*4882a593Smuzhiyun */
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (rep.majorVersion > stuff->majorVersion ||
52*4882a593Smuzhiyun rep.minorVersion > stuff->minorVersion) {
53*4882a593Smuzhiyun rep.majorVersion = stuff->majorVersion;
54*4882a593Smuzhiyun rep.minorVersion = stuff->minorVersion;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun if (client->swapped) {
58*4882a593Smuzhiyun swaps(&rep.sequenceNumber);
59*4882a593Smuzhiyun swapl(&rep.length);
60*4882a593Smuzhiyun swapl(&rep.majorVersion);
61*4882a593Smuzhiyun swapl(&rep.minorVersion);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun WriteToClient(client, sizeof(rep), &rep);
64*4882a593Smuzhiyun return Success;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun #define VERIFY_FENCE_OR_NONE(fence_ptr, fence_id, client, access) do { \
68*4882a593Smuzhiyun if ((fence_id) == None) \
69*4882a593Smuzhiyun (fence_ptr) = NULL; \
70*4882a593Smuzhiyun else { \
71*4882a593Smuzhiyun int __rc__ = SyncVerifyFence(&fence_ptr, fence_id, client, access); \
72*4882a593Smuzhiyun if (__rc__ != Success) \
73*4882a593Smuzhiyun return __rc__; \
74*4882a593Smuzhiyun } \
75*4882a593Smuzhiyun } while (0)
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define VERIFY_CRTC_OR_NONE(crtc_ptr, crtc_id, client, access) do { \
78*4882a593Smuzhiyun if ((crtc_id) == None) \
79*4882a593Smuzhiyun (crtc_ptr) = NULL; \
80*4882a593Smuzhiyun else { \
81*4882a593Smuzhiyun VERIFY_RR_CRTC(crtc_id, crtc_ptr, access); \
82*4882a593Smuzhiyun } \
83*4882a593Smuzhiyun } while (0)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static int
proc_present_pixmap(ClientPtr client)86*4882a593Smuzhiyun proc_present_pixmap(ClientPtr client)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun REQUEST(xPresentPixmapReq);
89*4882a593Smuzhiyun WindowPtr window;
90*4882a593Smuzhiyun PixmapPtr pixmap;
91*4882a593Smuzhiyun RegionPtr valid = NULL;
92*4882a593Smuzhiyun RegionPtr update = NULL;
93*4882a593Smuzhiyun SyncFence *wait_fence;
94*4882a593Smuzhiyun SyncFence *idle_fence;
95*4882a593Smuzhiyun RRCrtcPtr target_crtc;
96*4882a593Smuzhiyun int ret;
97*4882a593Smuzhiyun int nnotifies;
98*4882a593Smuzhiyun present_notify_ptr notifies = NULL;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
101*4882a593Smuzhiyun ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess);
102*4882a593Smuzhiyun if (ret != Success)
103*4882a593Smuzhiyun return ret;
104*4882a593Smuzhiyun ret = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess);
105*4882a593Smuzhiyun if (ret != Success)
106*4882a593Smuzhiyun return ret;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (window->drawable.depth != pixmap->drawable.depth)
109*4882a593Smuzhiyun return BadMatch;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess);
112*4882a593Smuzhiyun VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
117*4882a593Smuzhiyun VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (stuff->options & ~(PresentAllOptions)) {
120*4882a593Smuzhiyun client->errorValue = stuff->options;
121*4882a593Smuzhiyun return BadValue;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun * Check to see if remainder is sane
126*4882a593Smuzhiyun */
127*4882a593Smuzhiyun if (stuff->divisor == 0) {
128*4882a593Smuzhiyun if (stuff->remainder != 0) {
129*4882a593Smuzhiyun client->errorValue = (CARD32) stuff->remainder;
130*4882a593Smuzhiyun return BadValue;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun } else {
133*4882a593Smuzhiyun if (stuff->remainder >= stuff->divisor) {
134*4882a593Smuzhiyun client->errorValue = (CARD32) stuff->remainder;
135*4882a593Smuzhiyun return BadValue;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq);
140*4882a593Smuzhiyun if (nnotifies % sizeof (xPresentNotify))
141*4882a593Smuzhiyun return BadLength;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun nnotifies /= sizeof (xPresentNotify);
144*4882a593Smuzhiyun if (nnotifies) {
145*4882a593Smuzhiyun ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), ¬ifies);
146*4882a593Smuzhiyun if (ret != Success)
147*4882a593Smuzhiyun return ret;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
151*4882a593Smuzhiyun stuff->x_off, stuff->y_off, target_crtc,
152*4882a593Smuzhiyun wait_fence, idle_fence, stuff->options,
153*4882a593Smuzhiyun stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
154*4882a593Smuzhiyun if (ret != Success)
155*4882a593Smuzhiyun present_destroy_notifies(notifies, nnotifies);
156*4882a593Smuzhiyun return ret;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun static int
proc_present_notify_msc(ClientPtr client)160*4882a593Smuzhiyun proc_present_notify_msc(ClientPtr client)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun REQUEST(xPresentNotifyMSCReq);
163*4882a593Smuzhiyun WindowPtr window;
164*4882a593Smuzhiyun int rc;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
167*4882a593Smuzhiyun rc = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
168*4882a593Smuzhiyun if (rc != Success)
169*4882a593Smuzhiyun return rc;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * Check to see if remainder is sane
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun if (stuff->divisor == 0) {
175*4882a593Smuzhiyun if (stuff->remainder != 0) {
176*4882a593Smuzhiyun client->errorValue = (CARD32) stuff->remainder;
177*4882a593Smuzhiyun return BadValue;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun } else {
180*4882a593Smuzhiyun if (stuff->remainder >= stuff->divisor) {
181*4882a593Smuzhiyun client->errorValue = (CARD32) stuff->remainder;
182*4882a593Smuzhiyun return BadValue;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return present_notify_msc(window, stuff->serial,
187*4882a593Smuzhiyun stuff->target_msc, stuff->divisor, stuff->remainder);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun static int
proc_present_select_input(ClientPtr client)191*4882a593Smuzhiyun proc_present_select_input (ClientPtr client)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun REQUEST(xPresentSelectInputReq);
194*4882a593Smuzhiyun WindowPtr window;
195*4882a593Smuzhiyun int rc;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentSelectInputReq);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
200*4882a593Smuzhiyun if (rc != Success)
201*4882a593Smuzhiyun return rc;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (stuff->eventMask & ~PresentAllEvents) {
204*4882a593Smuzhiyun client->errorValue = stuff->eventMask;
205*4882a593Smuzhiyun return BadValue;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun return present_select_input(client, stuff->eid, window, stuff->eventMask);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun static int
proc_present_query_capabilities(ClientPtr client)211*4882a593Smuzhiyun proc_present_query_capabilities (ClientPtr client)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun REQUEST(xPresentQueryCapabilitiesReq);
214*4882a593Smuzhiyun xPresentQueryCapabilitiesReply rep = {
215*4882a593Smuzhiyun .type = X_Reply,
216*4882a593Smuzhiyun .sequenceNumber = client->sequence,
217*4882a593Smuzhiyun .length = 0,
218*4882a593Smuzhiyun };
219*4882a593Smuzhiyun WindowPtr window;
220*4882a593Smuzhiyun RRCrtcPtr crtc = NULL;
221*4882a593Smuzhiyun int r;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
224*4882a593Smuzhiyun r = dixLookupWindow(&window, stuff->target, client, DixGetAttrAccess);
225*4882a593Smuzhiyun switch (r) {
226*4882a593Smuzhiyun case Success:
227*4882a593Smuzhiyun crtc = present_get_crtc(window);
228*4882a593Smuzhiyun break;
229*4882a593Smuzhiyun case BadWindow:
230*4882a593Smuzhiyun VERIFY_RR_CRTC(stuff->target, crtc, DixGetAttrAccess);
231*4882a593Smuzhiyun break;
232*4882a593Smuzhiyun default:
233*4882a593Smuzhiyun return r;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun rep.capabilities = present_query_capabilities(crtc);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (client->swapped) {
239*4882a593Smuzhiyun swaps(&rep.sequenceNumber);
240*4882a593Smuzhiyun swapl(&rep.length);
241*4882a593Smuzhiyun swapl(&rep.capabilities);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun WriteToClient(client, sizeof(rep), &rep);
244*4882a593Smuzhiyun return Success;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
248*4882a593Smuzhiyun proc_present_query_version, /* 0 */
249*4882a593Smuzhiyun proc_present_pixmap, /* 1 */
250*4882a593Smuzhiyun proc_present_notify_msc, /* 2 */
251*4882a593Smuzhiyun proc_present_select_input, /* 3 */
252*4882a593Smuzhiyun proc_present_query_capabilities, /* 4 */
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun int
proc_present_dispatch(ClientPtr client)256*4882a593Smuzhiyun proc_present_dispatch(ClientPtr client)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun REQUEST(xReq);
259*4882a593Smuzhiyun if (stuff->data >= PresentNumberRequests || !proc_present_vector[stuff->data])
260*4882a593Smuzhiyun return BadRequest;
261*4882a593Smuzhiyun return (*proc_present_vector[stuff->data]) (client);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun static int _X_COLD
sproc_present_query_version(ClientPtr client)265*4882a593Smuzhiyun sproc_present_query_version(ClientPtr client)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun REQUEST(xPresentQueryVersionReq);
268*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun swaps(&stuff->length);
271*4882a593Smuzhiyun swapl(&stuff->majorVersion);
272*4882a593Smuzhiyun swapl(&stuff->minorVersion);
273*4882a593Smuzhiyun return (*proc_present_vector[stuff->presentReqType]) (client);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun static int _X_COLD
sproc_present_pixmap(ClientPtr client)277*4882a593Smuzhiyun sproc_present_pixmap(ClientPtr client)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun REQUEST(xPresentPixmapReq);
280*4882a593Smuzhiyun REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun swaps(&stuff->length);
283*4882a593Smuzhiyun swapl(&stuff->window);
284*4882a593Smuzhiyun swapl(&stuff->pixmap);
285*4882a593Smuzhiyun swapl(&stuff->valid);
286*4882a593Smuzhiyun swapl(&stuff->update);
287*4882a593Smuzhiyun swaps(&stuff->x_off);
288*4882a593Smuzhiyun swaps(&stuff->y_off);
289*4882a593Smuzhiyun swapll(&stuff->target_msc);
290*4882a593Smuzhiyun swapll(&stuff->divisor);
291*4882a593Smuzhiyun swapll(&stuff->remainder);
292*4882a593Smuzhiyun swapl(&stuff->idle_fence);
293*4882a593Smuzhiyun return (*proc_present_vector[stuff->presentReqType]) (client);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun static int _X_COLD
sproc_present_notify_msc(ClientPtr client)297*4882a593Smuzhiyun sproc_present_notify_msc(ClientPtr client)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun REQUEST(xPresentNotifyMSCReq);
300*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun swaps(&stuff->length);
303*4882a593Smuzhiyun swapl(&stuff->window);
304*4882a593Smuzhiyun swapll(&stuff->target_msc);
305*4882a593Smuzhiyun swapll(&stuff->divisor);
306*4882a593Smuzhiyun swapll(&stuff->remainder);
307*4882a593Smuzhiyun return (*proc_present_vector[stuff->presentReqType]) (client);
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun static int _X_COLD
sproc_present_select_input(ClientPtr client)311*4882a593Smuzhiyun sproc_present_select_input (ClientPtr client)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun REQUEST(xPresentSelectInputReq);
314*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentSelectInputReq);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun swaps(&stuff->length);
317*4882a593Smuzhiyun swapl(&stuff->window);
318*4882a593Smuzhiyun swapl(&stuff->eventMask);
319*4882a593Smuzhiyun return (*proc_present_vector[stuff->presentReqType]) (client);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun static int _X_COLD
sproc_present_query_capabilities(ClientPtr client)323*4882a593Smuzhiyun sproc_present_query_capabilities (ClientPtr client)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun REQUEST(xPresentQueryCapabilitiesReq);
326*4882a593Smuzhiyun REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
327*4882a593Smuzhiyun swaps(&stuff->length);
328*4882a593Smuzhiyun swapl(&stuff->target);
329*4882a593Smuzhiyun return (*proc_present_vector[stuff->presentReqType]) (client);
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
333*4882a593Smuzhiyun sproc_present_query_version, /* 0 */
334*4882a593Smuzhiyun sproc_present_pixmap, /* 1 */
335*4882a593Smuzhiyun sproc_present_notify_msc, /* 2 */
336*4882a593Smuzhiyun sproc_present_select_input, /* 3 */
337*4882a593Smuzhiyun sproc_present_query_capabilities, /* 4 */
338*4882a593Smuzhiyun };
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun int _X_COLD
sproc_present_dispatch(ClientPtr client)341*4882a593Smuzhiyun sproc_present_dispatch(ClientPtr client)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun REQUEST(xReq);
344*4882a593Smuzhiyun if (stuff->data >= PresentNumberRequests || !sproc_present_vector[stuff->data])
345*4882a593Smuzhiyun return BadRequest;
346*4882a593Smuzhiyun return (*sproc_present_vector[stuff->data]) (client);
347*4882a593Smuzhiyun }
348