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