1 /*
2 * Copyright © 2009 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Author: Peter Hutterer
24 */
25
26 /***********************************************************************
27 *
28 * Request to grab or ungrab input device.
29 *
30 */
31
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
35
36 #include "inputstr.h" /* DeviceIntPtr */
37 #include "windowstr.h" /* window structure */
38 #include <X11/extensions/XI2.h>
39 #include <X11/extensions/XI2proto.h>
40 #include "swaprep.h"
41
42 #include "exglobals.h" /* BadDevice */
43 #include "exevents.h"
44 #include "xipassivegrab.h"
45 #include "dixgrabs.h"
46 #include "misc.h"
47 #include "inpututils.h"
48
49 int _X_COLD
SProcXIPassiveGrabDevice(ClientPtr client)50 SProcXIPassiveGrabDevice(ClientPtr client)
51 {
52 int i;
53 uint32_t *mods;
54
55 REQUEST(xXIPassiveGrabDeviceReq);
56 REQUEST_AT_LEAST_SIZE(xXIPassiveGrabDeviceReq);
57
58 swaps(&stuff->length);
59 swaps(&stuff->deviceid);
60 swapl(&stuff->grab_window);
61 swapl(&stuff->cursor);
62 swapl(&stuff->time);
63 swapl(&stuff->detail);
64 swaps(&stuff->mask_len);
65 swaps(&stuff->num_modifiers);
66
67 REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq,
68 ((uint32_t) stuff->mask_len + stuff->num_modifiers) *4);
69 mods = (uint32_t *) &stuff[1] + stuff->mask_len;
70
71 for (i = 0; i < stuff->num_modifiers; i++, mods++) {
72 swapl(mods);
73 }
74
75 return ProcXIPassiveGrabDevice(client);
76 }
77
78 int
ProcXIPassiveGrabDevice(ClientPtr client)79 ProcXIPassiveGrabDevice(ClientPtr client)
80 {
81 DeviceIntPtr dev, mod_dev;
82 xXIPassiveGrabDeviceReply rep = {
83 .repType = X_Reply,
84 .RepType = X_XIPassiveGrabDevice,
85 .sequenceNumber = client->sequence,
86 .length = 0,
87 .num_modifiers = 0
88 };
89 int i, ret = Success;
90 uint32_t *modifiers;
91 xXIGrabModifierInfo *modifiers_failed = NULL;
92 GrabMask mask = { 0 };
93 GrabParameters param;
94 void *tmp;
95 int mask_len;
96
97 REQUEST(xXIPassiveGrabDeviceReq);
98 REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq,
99 ((uint32_t) stuff->mask_len + stuff->num_modifiers) * 4);
100
101 if (stuff->deviceid == XIAllDevices)
102 dev = inputInfo.all_devices;
103 else if (stuff->deviceid == XIAllMasterDevices)
104 dev = inputInfo.all_master_devices;
105 else {
106 ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess);
107 if (ret != Success) {
108 client->errorValue = stuff->deviceid;
109 return ret;
110 }
111 }
112
113 if (stuff->grab_type != XIGrabtypeButton &&
114 stuff->grab_type != XIGrabtypeKeycode &&
115 stuff->grab_type != XIGrabtypeEnter &&
116 stuff->grab_type != XIGrabtypeFocusIn &&
117 stuff->grab_type != XIGrabtypeTouchBegin) {
118 client->errorValue = stuff->grab_type;
119 return BadValue;
120 }
121
122 if ((stuff->grab_type == XIGrabtypeEnter ||
123 stuff->grab_type == XIGrabtypeFocusIn ||
124 stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
125 client->errorValue = stuff->detail;
126 return BadValue;
127 }
128
129 if (stuff->grab_type == XIGrabtypeTouchBegin &&
130 (stuff->grab_mode != XIGrabModeTouch ||
131 stuff->paired_device_mode != GrabModeAsync)) {
132 client->errorValue = stuff->grab_mode;
133 return BadValue;
134 }
135
136 if (XICheckInvalidMaskBits(client, (unsigned char *) &stuff[1],
137 stuff->mask_len * 4) != Success)
138 return BadValue;
139
140 mask.xi2mask = xi2mask_new();
141 if (!mask.xi2mask)
142 return BadAlloc;
143
144 mask_len = min(xi2mask_mask_size(mask.xi2mask), stuff->mask_len * 4);
145 xi2mask_set_one_mask(mask.xi2mask, stuff->deviceid,
146 (unsigned char *) &stuff[1], mask_len * 4);
147
148 memset(¶m, 0, sizeof(param));
149 param.grabtype = XI2;
150 param.ownerEvents = stuff->owner_events;
151 param.grabWindow = stuff->grab_window;
152 param.cursor = stuff->cursor;
153
154 if (IsKeyboardDevice(dev)) {
155 param.this_device_mode = stuff->grab_mode;
156 param.other_devices_mode = stuff->paired_device_mode;
157 }
158 else {
159 param.this_device_mode = stuff->paired_device_mode;
160 param.other_devices_mode = stuff->grab_mode;
161 }
162
163 if (stuff->cursor != None) {
164 ret = dixLookupResourceByType(&tmp, stuff->cursor,
165 RT_CURSOR, client, DixUseAccess);
166 if (ret != Success) {
167 client->errorValue = stuff->cursor;
168 goto out;
169 }
170 }
171
172 ret =
173 dixLookupWindow((WindowPtr *) &tmp, stuff->grab_window, client,
174 DixSetAttrAccess);
175 if (ret != Success)
176 goto out;
177
178 ret = CheckGrabValues(client, ¶m);
179 if (ret != Success)
180 goto out;
181
182 modifiers = (uint32_t *) &stuff[1] + stuff->mask_len;
183 modifiers_failed =
184 calloc(stuff->num_modifiers, sizeof(xXIGrabModifierInfo));
185 if (!modifiers_failed) {
186 ret = BadAlloc;
187 goto out;
188 }
189
190 mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD);
191
192 for (i = 0; i < stuff->num_modifiers; i++, modifiers++) {
193 uint8_t status = Success;
194
195 param.modifiers = *modifiers;
196 ret = CheckGrabValues(client, ¶m);
197 if (ret != Success)
198 goto out;
199
200 switch (stuff->grab_type) {
201 case XIGrabtypeButton:
202 status = GrabButton(client, dev, mod_dev, stuff->detail,
203 ¶m, XI2, &mask);
204 break;
205 case XIGrabtypeKeycode:
206 /* XI2 allows 32-bit keycodes but thanks to XKB we can never
207 * implement this. Just return an error for all keycodes that
208 * cannot work anyway */
209 if (stuff->detail > 255)
210 status = XIAlreadyGrabbed;
211 else
212 status = GrabKey(client, dev, mod_dev, stuff->detail,
213 ¶m, XI2, &mask);
214 break;
215 case XIGrabtypeEnter:
216 case XIGrabtypeFocusIn:
217 status = GrabWindow(client, dev, stuff->grab_type, ¶m, &mask);
218 break;
219 case XIGrabtypeTouchBegin:
220 status = GrabTouch(client, dev, mod_dev, ¶m, &mask);
221 break;
222 }
223
224 if (status != GrabSuccess) {
225 xXIGrabModifierInfo *info = modifiers_failed + rep.num_modifiers;
226
227 info->status = status;
228 info->modifiers = *modifiers;
229 if (client->swapped)
230 swapl(&info->modifiers);
231
232 rep.num_modifiers++;
233 rep.length += bytes_to_int32(sizeof(xXIGrabModifierInfo));
234 }
235 }
236
237 WriteReplyToClient(client, sizeof(rep), &rep);
238 if (rep.num_modifiers)
239 WriteToClient(client, rep.length * 4, modifiers_failed);
240
241 out:
242 free(modifiers_failed);
243 xi2mask_free(&mask.xi2mask);
244 return ret;
245 }
246
247 void _X_COLD
SRepXIPassiveGrabDevice(ClientPtr client,int size,xXIPassiveGrabDeviceReply * rep)248 SRepXIPassiveGrabDevice(ClientPtr client, int size,
249 xXIPassiveGrabDeviceReply * rep)
250 {
251 swaps(&rep->sequenceNumber);
252 swapl(&rep->length);
253 swaps(&rep->num_modifiers);
254
255 WriteToClient(client, size, rep);
256 }
257
258 int _X_COLD
SProcXIPassiveUngrabDevice(ClientPtr client)259 SProcXIPassiveUngrabDevice(ClientPtr client)
260 {
261 int i;
262 uint32_t *modifiers;
263
264 REQUEST(xXIPassiveUngrabDeviceReq);
265 REQUEST_AT_LEAST_SIZE(xXIPassiveUngrabDeviceReq);
266
267 swaps(&stuff->length);
268 swapl(&stuff->grab_window);
269 swaps(&stuff->deviceid);
270 swapl(&stuff->detail);
271 swaps(&stuff->num_modifiers);
272
273 REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq,
274 ((uint32_t) stuff->num_modifiers) << 2);
275 modifiers = (uint32_t *) &stuff[1];
276
277 for (i = 0; i < stuff->num_modifiers; i++, modifiers++)
278 swapl(modifiers);
279
280 return ProcXIPassiveUngrabDevice(client);
281 }
282
283 int
ProcXIPassiveUngrabDevice(ClientPtr client)284 ProcXIPassiveUngrabDevice(ClientPtr client)
285 {
286 DeviceIntPtr dev, mod_dev;
287 WindowPtr win;
288 GrabPtr tempGrab;
289 uint32_t *modifiers;
290 int i, rc;
291
292 REQUEST(xXIPassiveUngrabDeviceReq);
293 REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq,
294 ((uint32_t) stuff->num_modifiers) << 2);
295
296 if (stuff->deviceid == XIAllDevices)
297 dev = inputInfo.all_devices;
298 else if (stuff->deviceid == XIAllMasterDevices)
299 dev = inputInfo.all_master_devices;
300 else {
301 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess);
302 if (rc != Success)
303 return rc;
304 }
305
306 if (stuff->grab_type != XIGrabtypeButton &&
307 stuff->grab_type != XIGrabtypeKeycode &&
308 stuff->grab_type != XIGrabtypeEnter &&
309 stuff->grab_type != XIGrabtypeFocusIn &&
310 stuff->grab_type != XIGrabtypeTouchBegin) {
311 client->errorValue = stuff->grab_type;
312 return BadValue;
313 }
314
315 if ((stuff->grab_type == XIGrabtypeEnter ||
316 stuff->grab_type == XIGrabtypeFocusIn ||
317 stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
318 client->errorValue = stuff->detail;
319 return BadValue;
320 }
321
322 rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess);
323 if (rc != Success)
324 return rc;
325
326 mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD);
327
328 tempGrab = AllocGrab(NULL);
329 if (!tempGrab)
330 return BadAlloc;
331
332 tempGrab->resource = client->clientAsMask;
333 tempGrab->device = dev;
334 tempGrab->window = win;
335 switch (stuff->grab_type) {
336 case XIGrabtypeButton:
337 tempGrab->type = XI_ButtonPress;
338 break;
339 case XIGrabtypeKeycode:
340 tempGrab->type = XI_KeyPress;
341 break;
342 case XIGrabtypeEnter:
343 tempGrab->type = XI_Enter;
344 break;
345 case XIGrabtypeFocusIn:
346 tempGrab->type = XI_FocusIn;
347 break;
348 case XIGrabtypeTouchBegin:
349 tempGrab->type = XI_TouchBegin;
350 break;
351 }
352 tempGrab->grabtype = XI2;
353 tempGrab->modifierDevice = mod_dev;
354 tempGrab->modifiersDetail.pMask = NULL;
355 tempGrab->detail.exact = stuff->detail;
356 tempGrab->detail.pMask = NULL;
357
358 modifiers = (uint32_t *) &stuff[1];
359
360 for (i = 0; i < stuff->num_modifiers; i++, modifiers++) {
361 tempGrab->modifiersDetail.exact = *modifiers;
362 DeletePassiveGrabFromList(tempGrab);
363 }
364
365 FreeGrab(tempGrab);
366
367 return Success;
368 }
369