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
31 static int
proc_present_query_version(ClientPtr client)32 proc_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
85 static int
proc_present_pixmap(ClientPtr client)86 proc_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), ¬ifies);
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
159 static int
proc_present_notify_msc(ClientPtr client)160 proc_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
190 static int
proc_present_select_input(ClientPtr client)191 proc_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
210 static int
proc_present_query_capabilities(ClientPtr client)211 proc_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
247 static 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
255 int
proc_present_dispatch(ClientPtr client)256 proc_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
264 static int _X_COLD
sproc_present_query_version(ClientPtr client)265 sproc_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
276 static int _X_COLD
sproc_present_pixmap(ClientPtr client)277 sproc_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
296 static int _X_COLD
sproc_present_notify_msc(ClientPtr client)297 sproc_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
310 static int _X_COLD
sproc_present_select_input(ClientPtr client)311 sproc_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
322 static int _X_COLD
sproc_present_query_capabilities(ClientPtr client)323 sproc_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
332 static 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
340 int _X_COLD
sproc_present_dispatch(ClientPtr client)341 sproc_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