1706f2543Smrg/*
2706f2543Smrg * Copyright © 2009 Red Hat, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice (including the next
12706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the
13706f2543Smrg * Software.
14706f2543Smrg *
15706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21706f2543Smrg * DEALINGS IN THE SOFTWARE.
22706f2543Smrg *
23706f2543Smrg * Author: Peter Hutterer
24706f2543Smrg */
25706f2543Smrg
26706f2543Smrg/***********************************************************************
27706f2543Smrg *
28706f2543Smrg * Request to grab or ungrab input device.
29706f2543Smrg *
30706f2543Smrg */
31706f2543Smrg
32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
33706f2543Smrg#include <dix-config.h>
34706f2543Smrg#endif
35706f2543Smrg
36706f2543Smrg#include "inputstr.h"	/* DeviceIntPtr      */
37706f2543Smrg#include "windowstr.h"	/* window structure  */
38706f2543Smrg#include <X11/extensions/XI2.h>
39706f2543Smrg#include <X11/extensions/XI2proto.h>
40706f2543Smrg#include "swaprep.h"
41706f2543Smrg
42706f2543Smrg#include "exglobals.h" /* BadDevice */
43706f2543Smrg#include "exevents.h"
44706f2543Smrg#include "xipassivegrab.h"
45706f2543Smrg#include "dixgrabs.h"
46706f2543Smrg#include "misc.h"
47706f2543Smrg
48706f2543Smrgint
49706f2543SmrgSProcXIPassiveGrabDevice(ClientPtr client)
50706f2543Smrg{
51706f2543Smrg    int i;
52706f2543Smrg    char n;
53706f2543Smrg    xXIModifierInfo *mods;
54706f2543Smrg
55706f2543Smrg    REQUEST(xXIPassiveGrabDeviceReq);
56706f2543Smrg    REQUEST_AT_LEAST_SIZE(xXIPassiveGrabDeviceReq);
57706f2543Smrg
58706f2543Smrg    swaps(&stuff->length, n);
59706f2543Smrg    swaps(&stuff->deviceid, n);
60706f2543Smrg    swapl(&stuff->grab_window, n);
61706f2543Smrg    swapl(&stuff->cursor, n);
62706f2543Smrg    swapl(&stuff->time, n);
63706f2543Smrg    swapl(&stuff->detail, n);
64706f2543Smrg    swaps(&stuff->mask_len, n);
65706f2543Smrg    swaps(&stuff->num_modifiers, n);
66706f2543Smrg
67706f2543Smrg    REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq,
68706f2543Smrg        ((uint32_t) stuff->mask_len + stuff->num_modifiers) *4);
69706f2543Smrg    mods = (xXIModifierInfo*)&stuff[1];
70706f2543Smrg
71706f2543Smrg    for (i = 0; i < stuff->num_modifiers; i++, mods++)
72706f2543Smrg    {
73706f2543Smrg        swapl(&mods->base_mods, n);
74706f2543Smrg        swapl(&mods->latched_mods, n);
75706f2543Smrg        swapl(&mods->locked_mods, n);
76706f2543Smrg    }
77706f2543Smrg
78706f2543Smrg    return ProcXIPassiveGrabDevice(client);
79706f2543Smrg}
80706f2543Smrg
81706f2543Smrgint
82706f2543SmrgProcXIPassiveGrabDevice(ClientPtr client)
83706f2543Smrg{
84706f2543Smrg    DeviceIntPtr dev, mod_dev;
85706f2543Smrg    xXIPassiveGrabDeviceReply rep;
86706f2543Smrg    int i, ret = Success;
87706f2543Smrg    uint8_t status;
88706f2543Smrg    uint32_t *modifiers;
89706f2543Smrg    xXIGrabModifierInfo *modifiers_failed;
90706f2543Smrg    GrabMask mask;
91706f2543Smrg    GrabParameters param;
92706f2543Smrg    void *tmp;
93706f2543Smrg    int mask_len;
94706f2543Smrg    int n;
9515d5bffaSmrg    uint32_t length;
96706f2543Smrg
97706f2543Smrg    REQUEST(xXIPassiveGrabDeviceReq);
98706f2543Smrg    REQUEST_FIXED_SIZE(xXIPassiveGrabDeviceReq,
99706f2543Smrg        ((uint32_t) stuff->mask_len + stuff->num_modifiers) * 4);
100706f2543Smrg
101706f2543Smrg    if (stuff->deviceid == XIAllDevices)
102706f2543Smrg        dev = inputInfo.all_devices;
103706f2543Smrg    else if (stuff->deviceid == XIAllMasterDevices)
104706f2543Smrg        dev = inputInfo.all_master_devices;
105706f2543Smrg    else
106706f2543Smrg    {
107706f2543Smrg        ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess);
108706f2543Smrg        if (ret != Success)
109706f2543Smrg        {
110706f2543Smrg            client->errorValue = stuff->deviceid;
111706f2543Smrg            return ret;
112706f2543Smrg        }
113706f2543Smrg    }
114706f2543Smrg
115706f2543Smrg    if (stuff->grab_type != XIGrabtypeButton &&
116706f2543Smrg        stuff->grab_type != XIGrabtypeKeycode &&
117706f2543Smrg        stuff->grab_type != XIGrabtypeEnter &&
118706f2543Smrg        stuff->grab_type != XIGrabtypeFocusIn)
119706f2543Smrg    {
120706f2543Smrg        client->errorValue = stuff->grab_type;
121706f2543Smrg        return BadValue;
122706f2543Smrg    }
123706f2543Smrg
124706f2543Smrg    if ((stuff->grab_type == XIGrabtypeEnter ||
125706f2543Smrg         stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0)
126706f2543Smrg    {
127706f2543Smrg        client->errorValue = stuff->detail;
128706f2543Smrg        return BadValue;
129706f2543Smrg    }
130706f2543Smrg
131706f2543Smrg    if (XICheckInvalidMaskBits(client, (unsigned char*)&stuff[1],
132706f2543Smrg                               stuff->mask_len * 4) != Success)
133706f2543Smrg        return BadValue;
134706f2543Smrg
135706f2543Smrg    mask_len = min(sizeof(mask.xi2mask[stuff->deviceid]), stuff->mask_len * 4);
136706f2543Smrg    memset(mask.xi2mask, 0, sizeof(mask.xi2mask));
137706f2543Smrg    memcpy(mask.xi2mask[stuff->deviceid], &stuff[1], mask_len * 4);
138706f2543Smrg
139706f2543Smrg    rep.repType = X_Reply;
140706f2543Smrg    rep.RepType = X_XIPassiveGrabDevice;
141706f2543Smrg    rep.length = 0;
142706f2543Smrg    rep.sequenceNumber = client->sequence;
143706f2543Smrg    rep.num_modifiers = 0;
144706f2543Smrg
145706f2543Smrg    memset(&param, 0, sizeof(param));
146706f2543Smrg    param.grabtype = GRABTYPE_XI2;
147706f2543Smrg    param.ownerEvents = stuff->owner_events;
148706f2543Smrg    param.grabWindow = stuff->grab_window;
149706f2543Smrg    param.cursor = stuff->cursor;
150706f2543Smrg
151706f2543Smrg    if (IsKeyboardDevice(dev)) {
152706f2543Smrg        param.this_device_mode = stuff->grab_mode;
153706f2543Smrg        param.other_devices_mode = stuff->paired_device_mode;
154706f2543Smrg    } else {
155706f2543Smrg        param.this_device_mode = stuff->paired_device_mode;
156706f2543Smrg        param.other_devices_mode = stuff->grab_mode;
157706f2543Smrg    }
158706f2543Smrg
159706f2543Smrg    if (stuff->cursor != None)
160706f2543Smrg    {
161706f2543Smrg        status = dixLookupResourceByType(&tmp, stuff->cursor,
162706f2543Smrg                                         RT_CURSOR, client, DixUseAccess);
163706f2543Smrg	if (status != Success)
164706f2543Smrg	{
165706f2543Smrg	    client->errorValue = stuff->cursor;
166706f2543Smrg	    return status;
167706f2543Smrg	}
168706f2543Smrg    }
169706f2543Smrg
170706f2543Smrg    status = dixLookupWindow((WindowPtr*)&tmp, stuff->grab_window, client, DixSetAttrAccess);
171706f2543Smrg    if (status != Success)
172706f2543Smrg	return status;
173706f2543Smrg
174706f2543Smrg    status = CheckGrabValues(client, &param);
175706f2543Smrg    if (status != Success)
176706f2543Smrg        return status;
177706f2543Smrg
178706f2543Smrg    modifiers = (uint32_t*)&stuff[1] + stuff->mask_len;
179706f2543Smrg    modifiers_failed = calloc(stuff->num_modifiers, sizeof(xXIGrabModifierInfo));
180706f2543Smrg    if (!modifiers_failed)
181706f2543Smrg        return BadAlloc;
182706f2543Smrg
183706f2543Smrg    if (!IsMaster(dev) && dev->u.master)
184706f2543Smrg        mod_dev = GetMaster(dev, MASTER_KEYBOARD);
185706f2543Smrg    else
186706f2543Smrg        mod_dev = dev;
187706f2543Smrg
188706f2543Smrg    for (i = 0; i < stuff->num_modifiers; i++, modifiers++)
189706f2543Smrg    {
190706f2543Smrg        param.modifiers = *modifiers;
191706f2543Smrg        switch(stuff->grab_type)
192706f2543Smrg        {
193706f2543Smrg            case XIGrabtypeButton:
194706f2543Smrg                status = GrabButton(client, dev, mod_dev, stuff->detail,
195706f2543Smrg                                    &param, GRABTYPE_XI2, &mask);
196706f2543Smrg                break;
197706f2543Smrg            case XIGrabtypeKeycode:
198706f2543Smrg                status = GrabKey(client, dev, mod_dev, stuff->detail,
199706f2543Smrg                                 &param, GRABTYPE_XI2, &mask);
200706f2543Smrg                break;
201706f2543Smrg            case XIGrabtypeEnter:
202706f2543Smrg            case XIGrabtypeFocusIn:
203706f2543Smrg                status = GrabWindow(client, dev, stuff->grab_type,
204706f2543Smrg                                    &param, &mask);
205706f2543Smrg                break;
206706f2543Smrg        }
207706f2543Smrg
208706f2543Smrg        if (status != GrabSuccess)
209706f2543Smrg        {
210706f2543Smrg            xXIGrabModifierInfo *info = modifiers_failed + rep.num_modifiers;
211706f2543Smrg
212706f2543Smrg            info->status = status;
213706f2543Smrg            info->modifiers = *modifiers;
214706f2543Smrg            if (client->swapped)
215706f2543Smrg                swapl(&info->modifiers, n);
216706f2543Smrg
217706f2543Smrg            rep.num_modifiers++;
218706f2543Smrg            rep.length += bytes_to_int32(sizeof(xXIGrabModifierInfo));
219706f2543Smrg        }
220706f2543Smrg    }
221706f2543Smrg
22215d5bffaSmrg    /* save the value before SRepXIPassiveGrabDevice swaps it */
22315d5bffaSmrg    length = rep.length;
224706f2543Smrg    WriteReplyToClient(client, sizeof(rep), &rep);
225706f2543Smrg    if (rep.num_modifiers)
22615d5bffaSmrg        WriteToClient(client, length * 4, (char*)modifiers_failed);
227706f2543Smrg
228706f2543Smrg    free(modifiers_failed);
229706f2543Smrg    return ret;
230706f2543Smrg}
231706f2543Smrg
232706f2543Smrgvoid
233706f2543SmrgSRepXIPassiveGrabDevice(ClientPtr client, int size,
234706f2543Smrg                        xXIPassiveGrabDeviceReply * rep)
235706f2543Smrg{
236706f2543Smrg    char n;
237706f2543Smrg
238706f2543Smrg    swaps(&rep->sequenceNumber, n);
239706f2543Smrg    swapl(&rep->length, n);
240706f2543Smrg    swaps(&rep->num_modifiers, n);
241706f2543Smrg
242706f2543Smrg    WriteToClient(client, size, (char *)rep);
243706f2543Smrg}
244706f2543Smrg
245706f2543Smrgint
246706f2543SmrgSProcXIPassiveUngrabDevice(ClientPtr client)
247706f2543Smrg{
248706f2543Smrg    char n;
249706f2543Smrg    int i;
250706f2543Smrg    uint32_t *modifiers;
251706f2543Smrg
252706f2543Smrg    REQUEST(xXIPassiveUngrabDeviceReq);
253706f2543Smrg    REQUEST_AT_LEAST_SIZE(xXIPassiveUngrabDeviceReq);
254706f2543Smrg
255706f2543Smrg    swaps(&stuff->length, n);
256706f2543Smrg    swapl(&stuff->grab_window, n);
257706f2543Smrg    swaps(&stuff->deviceid, n);
258706f2543Smrg    swapl(&stuff->detail, n);
259706f2543Smrg    swaps(&stuff->num_modifiers, n);
260706f2543Smrg
261706f2543Smrg    REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq,
262706f2543Smrg                       ((uint32_t) stuff->num_modifiers) << 2);
263706f2543Smrg    modifiers = (uint32_t*)&stuff[1];
264706f2543Smrg
265706f2543Smrg    for (i = 0; i < stuff->num_modifiers; i++, modifiers++)
266706f2543Smrg        swapl(modifiers, n);
267706f2543Smrg
268706f2543Smrg    return ProcXIPassiveUngrabDevice(client);
269706f2543Smrg}
270706f2543Smrg
271706f2543Smrgint
272706f2543SmrgProcXIPassiveUngrabDevice(ClientPtr client)
273706f2543Smrg{
274706f2543Smrg    DeviceIntPtr dev, mod_dev;
275706f2543Smrg    WindowPtr win;
276706f2543Smrg    GrabRec tempGrab;
277706f2543Smrg    uint32_t* modifiers;
278706f2543Smrg    int i, rc;
279706f2543Smrg
280706f2543Smrg    REQUEST(xXIPassiveUngrabDeviceReq);
281706f2543Smrg    REQUEST_FIXED_SIZE(xXIPassiveUngrabDeviceReq,
282706f2543Smrg                       ((uint32_t) stuff->num_modifiers) << 2);
283706f2543Smrg
284706f2543Smrg    if (stuff->deviceid == XIAllDevices)
285706f2543Smrg        dev = inputInfo.all_devices;
286706f2543Smrg    else if (stuff->deviceid == XIAllMasterDevices)
287706f2543Smrg        dev = inputInfo.all_master_devices;
288706f2543Smrg    else
289706f2543Smrg    {
290706f2543Smrg        rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGrabAccess);
291706f2543Smrg        if (rc != Success)
292706f2543Smrg	    return rc;
293706f2543Smrg    }
294706f2543Smrg
295706f2543Smrg    if (stuff->grab_type != XIGrabtypeButton &&
296706f2543Smrg        stuff->grab_type != XIGrabtypeKeycode &&
297706f2543Smrg        stuff->grab_type != XIGrabtypeEnter &&
298706f2543Smrg        stuff->grab_type != XIGrabtypeFocusIn)
299706f2543Smrg    {
300706f2543Smrg        client->errorValue = stuff->grab_type;
301706f2543Smrg        return BadValue;
302706f2543Smrg    }
303706f2543Smrg
304706f2543Smrg    if ((stuff->grab_type == XIGrabtypeEnter ||
305706f2543Smrg         stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0)
306706f2543Smrg    {
307706f2543Smrg        client->errorValue = stuff->detail;
308706f2543Smrg        return BadValue;
309706f2543Smrg    }
310706f2543Smrg
311706f2543Smrg    rc = dixLookupWindow(&win, stuff->grab_window, client, DixSetAttrAccess);
312706f2543Smrg    if (rc != Success)
313706f2543Smrg        return rc;
314706f2543Smrg
315706f2543Smrg    if (!IsMaster(dev) && dev->u.master)
316706f2543Smrg        mod_dev = GetMaster(dev, MASTER_KEYBOARD);
317706f2543Smrg    else
318706f2543Smrg        mod_dev = dev;
319706f2543Smrg
320706f2543Smrg    tempGrab.resource = client->clientAsMask;
321706f2543Smrg    tempGrab.device = dev;
322706f2543Smrg    tempGrab.window = win;
323706f2543Smrg    switch(stuff->grab_type)
324706f2543Smrg    {
325706f2543Smrg        case XIGrabtypeButton:  tempGrab.type = XI_ButtonPress; break;
326706f2543Smrg        case XIGrabtypeKeycode:  tempGrab.type = XI_KeyPress;    break;
327706f2543Smrg        case XIGrabtypeEnter:   tempGrab.type = XI_Enter;       break;
328706f2543Smrg        case XIGrabtypeFocusIn: tempGrab.type = XI_FocusIn;     break;
329706f2543Smrg    }
330706f2543Smrg    tempGrab.grabtype = GRABTYPE_XI2;
331706f2543Smrg    tempGrab.modifierDevice = mod_dev;
332706f2543Smrg    tempGrab.modifiersDetail.pMask = NULL;
333706f2543Smrg    tempGrab.detail.exact = stuff->detail;
334706f2543Smrg    tempGrab.detail.pMask = NULL;
335706f2543Smrg
336706f2543Smrg    modifiers = (uint32_t*)&stuff[1];
337706f2543Smrg
338706f2543Smrg    for (i = 0; i < stuff->num_modifiers; i++, modifiers++)
339706f2543Smrg    {
340706f2543Smrg        tempGrab.modifiersDetail.exact = *modifiers;
341706f2543Smrg        DeletePassiveGrabFromList(&tempGrab);
342706f2543Smrg    }
343706f2543Smrg
344706f2543Smrg    return Success;
345706f2543Smrg}
346