Use correct swap{l,s} (or none at all for CARD8)
[gstreamer-omap:xserver.git] / Xi / xichangehierarchy.c
1 /*
2  * Copyright 2007-2008 Peter Hutterer
3  * Copyright 2009 Red Hat, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Author: Peter Hutterer, University of South Australia, NICTA
25  */
26
27 /***********************************************************************
28  *
29  * Request change in the device hierarchy.
30  *
31  */
32
33
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
36 #endif
37
38 #include <X11/X.h>      /* for inputstr.h    */
39 #include <X11/Xproto.h> /* Request macro     */
40 #include "inputstr.h"   /* DeviceIntPtr      */
41 #include "windowstr.h"  /* window structure  */
42 #include "scrnintstr.h" /* screen structure  */
43 #include <X11/extensions/XI.h>
44 #include <X11/extensions/XI2proto.h>
45 #include <X11/extensions/geproto.h>
46 #include "extnsionst.h"
47 #include "exevents.h"
48 #include "exglobals.h"
49 #include "geext.h"
50 #include "xace.h"
51 #include "xiquerydevice.h" /* for GetDeviceUse */
52
53 #include "xkbsrv.h"
54
55 #include "xichangehierarchy.h"
56
57 /**
58  * Send the current state of the device hierarchy to all clients.
59  */
60 void XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
61 {
62     xXIHierarchyEvent *ev;
63     xXIHierarchyInfo *info;
64     DeviceIntRec dummyDev;
65     DeviceIntPtr dev;
66     int i;
67
68     if (!flags)
69         return;
70
71     ev = calloc(1, sizeof(xXIHierarchyEvent) +
72                  MAXDEVICES * sizeof(xXIHierarchyInfo));
73     if (!ev)
74         return;
75     ev->type = GenericEvent;
76     ev->extension = IReqCode;
77     ev->evtype = XI_HierarchyChanged;
78     ev->time = GetTimeInMillis();
79     ev->flags = 0;
80     ev->num_info = inputInfo.numDevices;
81
82     info = (xXIHierarchyInfo*)&ev[1];
83     for (dev = inputInfo.devices; dev; dev = dev->next)
84     {
85         info->deviceid = dev->id;
86         info->enabled = dev->enabled;
87         info->use = GetDeviceUse(dev, &info->attachment);
88         info->flags = flags[dev->id];
89         ev->flags |= info->flags;
90         info++;
91     }
92     for (dev = inputInfo.off_devices; dev; dev = dev->next)
93     {
94         info->deviceid = dev->id;
95         info->enabled = dev->enabled;
96         info->use = GetDeviceUse(dev, &info->attachment);
97         info->flags = flags[dev->id];
98         ev->flags |= info->flags;
99         info++;
100     }
101
102
103     for (i = 0; i < MAXDEVICES; i++)
104     {
105         if (flags[i] & (XIMasterRemoved | XISlaveRemoved))
106         {
107             info->deviceid = i;
108             info->enabled = FALSE;
109             info->flags = flags[i];
110             info->use = 0;
111             ev->flags |= info->flags;
112             ev->num_info++;
113             info++;
114         }
115     }
116
117     ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
118
119     memset(&dummyDev, 0, sizeof(dummyDev));
120     dummyDev.id = XIAllDevices;
121     dummyDev.type = SLAVE;
122     SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1);
123     free(ev);
124 }
125
126
127 /***********************************************************************
128  *
129  * This procedure allows a client to change the device hierarchy through
130  * adding new master devices, removing them, etc.
131  *
132  */
133
134 int SProcXIChangeHierarchy(ClientPtr client)
135 {
136     REQUEST(xXIChangeHierarchyReq);
137     swaps(&stuff->length);
138     return (ProcXIChangeHierarchy(client));
139 }
140
141 static int
142 add_master(ClientPtr client, xXIAddMasterInfo *c, int flags[MAXDEVICES])
143 {
144     DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
145     char* name;
146     int rc;
147
148     name = calloc(c->name_len + 1, sizeof(char));
149     strncpy(name, (char*)&c[1], c->name_len);
150
151     rc = AllocDevicePair(client, name, &ptr, &keybd,
152                          CorePointerProc, CoreKeyboardProc, TRUE);
153     if (rc != Success)
154         goto unwind;
155
156     if (!c->send_core)
157         ptr->coreEvents = keybd->coreEvents =  FALSE;
158
159     /* Allocate virtual slave devices for xtest events */
160     rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
161     if (rc != Success)
162     {
163         DeleteInputDeviceRequest(ptr);
164         DeleteInputDeviceRequest(keybd);
165         goto unwind;
166     }
167
168     ActivateDevice(ptr, FALSE);
169     ActivateDevice(keybd, FALSE);
170     flags[ptr->id] |= XIMasterAdded;
171     flags[keybd->id] |= XIMasterAdded;
172
173     ActivateDevice(XTestptr, FALSE);
174     ActivateDevice(XTestkeybd, FALSE);
175     flags[XTestptr->id] |= XISlaveAdded;
176     flags[XTestkeybd->id] |= XISlaveAdded;
177
178     if (c->enable)
179     {
180         EnableDevice(ptr, FALSE);
181         EnableDevice(keybd, FALSE);
182         flags[ptr->id] |= XIDeviceEnabled;
183         flags[keybd->id] |= XIDeviceEnabled;
184
185         EnableDevice(XTestptr, FALSE);
186         EnableDevice(XTestkeybd, FALSE);
187         flags[XTestptr->id] |= XIDeviceEnabled;
188         flags[XTestkeybd->id] |= XIDeviceEnabled;
189     }
190
191     /* Attach the XTest virtual devices to the newly
192        created master device */
193     AttachDevice(NULL, XTestptr, ptr);
194     AttachDevice(NULL, XTestkeybd, keybd);
195     flags[XTestptr->id] |= XISlaveAttached;
196     flags[XTestkeybd->id] |= XISlaveAttached;
197
198 unwind:
199     free(name);
200     return rc;
201 }
202
203 static int
204 remove_master(ClientPtr client, xXIRemoveMasterInfo *r,
205               int flags[MAXDEVICES])
206 {
207     DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
208     int rc = Success;
209
210     if (r->return_mode != XIAttachToMaster &&
211         r->return_mode != XIFloating)
212         return BadValue;
213
214     rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
215     if (rc != Success)
216         goto unwind;
217
218     if (!IsMaster(ptr))
219     {
220         client->errorValue = r->deviceid;
221         rc = BadDevice;
222         goto unwind;
223     }
224
225     /* XXX: For now, don't allow removal of VCP, VCK */
226     if (ptr == inputInfo.pointer || ptr == inputInfo.keyboard)
227     {
228         rc = BadDevice;
229         goto unwind;
230     }
231
232
233     ptr = GetMaster(ptr, MASTER_POINTER);
234     rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
235     if (rc != Success)
236         goto unwind;
237     keybd = GetMaster(ptr, MASTER_KEYBOARD);
238     rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
239     if (rc != Success)
240         goto unwind;
241
242     XTestptr = GetXTestDevice(ptr);
243     rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
244     if (rc != Success)
245         goto unwind;
246
247     XTestkeybd = GetXTestDevice(keybd);
248     rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client,
249                          DixDestroyAccess);
250     if (rc != Success)
251         goto unwind;
252
253     /* Disabling sends the devices floating, reattach them if
254      * desired. */
255     if (r->return_mode == XIAttachToMaster)
256     {
257         DeviceIntPtr attached,
258                      newptr,
259                      newkeybd;
260
261         rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
262         if (rc != Success)
263             goto unwind;
264
265         if (!IsMaster(newptr))
266         {
267             client->errorValue = r->return_pointer;
268             rc = BadDevice;
269             goto unwind;
270         }
271
272         rc = dixLookupDevice(&newkeybd, r->return_keyboard,
273                              client, DixAddAccess);
274         if (rc != Success)
275             goto unwind;
276
277         if (!IsMaster(newkeybd))
278         {
279             client->errorValue = r->return_keyboard;
280             rc = BadDevice;
281             goto unwind;
282         }
283
284         for (attached = inputInfo.devices; attached; attached = attached->next)
285         {
286             if (!IsMaster(attached)) {
287                 if (GetMaster(attached, MASTER_ATTACHED) == ptr)
288                 {
289                     AttachDevice(client, attached, newptr);
290                     flags[attached->id] |= XISlaveAttached;
291                 }
292                 if (GetMaster(attached, MASTER_ATTACHED) == keybd)
293                 {
294                     AttachDevice(client, attached, newkeybd);
295                     flags[attached->id] |= XISlaveAttached;
296                 }
297             }
298         }
299     }
300
301     /* can't disable until we removed pairing */
302     keybd->spriteInfo->paired = NULL;
303     ptr->spriteInfo->paired = NULL;
304     XTestptr->spriteInfo->paired = NULL;
305     XTestkeybd->spriteInfo->paired = NULL;
306
307     /* disable the remove the devices, XTest devices must be done first
308        else the sprites they rely on will be destroyed  */
309     DisableDevice(XTestptr, FALSE);
310     DisableDevice(XTestkeybd, FALSE);
311     DisableDevice(keybd, FALSE);
312     DisableDevice(ptr, FALSE);
313     flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
314     flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
315     flags[keybd->id] |= XIDeviceDisabled;
316     flags[ptr->id] |= XIDeviceDisabled;
317
318     RemoveDevice(XTestptr, FALSE);
319     RemoveDevice(XTestkeybd, FALSE);
320     RemoveDevice(keybd, FALSE);
321     RemoveDevice(ptr, FALSE);
322     flags[XTestptr->id] |= XISlaveRemoved;
323     flags[XTestkeybd->id] |= XISlaveRemoved;
324     flags[keybd->id] |= XIMasterRemoved;
325     flags[ptr->id] |= XIMasterRemoved;
326
327 unwind:
328     return rc;
329 }
330
331 static int
332 detach_slave(ClientPtr client, xXIDetachSlaveInfo *c, int flags[MAXDEVICES])
333 {
334     DeviceIntPtr dev;
335     int rc;
336
337     rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
338     if (rc != Success)
339         goto unwind;
340
341     if (IsMaster(dev))
342     {
343         client->errorValue = c->deviceid;
344         rc = BadDevice;
345         goto unwind;
346     }
347
348     /* Don't allow changes to XTest Devices, these are fixed */
349     if (IsXTestDevice(dev, NULL))
350     {
351         client->errorValue = c->deviceid;
352         rc = BadDevice;
353         goto unwind;
354     }
355
356     ReleaseButtonsAndKeys(dev);
357     AttachDevice(client, dev, NULL);
358     flags[dev->id] |= XISlaveDetached;
359
360 unwind:
361     return rc;
362 }
363
364 static int
365 attach_slave(ClientPtr client, xXIAttachSlaveInfo *c,
366              int flags[MAXDEVICES])
367 {
368     DeviceIntPtr dev;
369     DeviceIntPtr newmaster;
370     int rc;
371
372     rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
373     if (rc != Success)
374         goto unwind;
375
376     if (IsMaster(dev))
377     {
378         client->errorValue = c->deviceid;
379         rc = BadDevice;
380         goto unwind;
381     }
382
383     /* Don't allow changes to XTest Devices, these are fixed */
384     if (IsXTestDevice(dev, NULL))
385     {
386         client->errorValue = c->deviceid;
387         rc = BadDevice;
388         goto unwind;
389     }
390
391     rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
392     if (rc != Success)
393         goto unwind;
394     if (!IsMaster(newmaster))
395     {
396         client->errorValue = c->new_master;
397         rc = BadDevice;
398         goto unwind;
399     }
400
401     if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
402         (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev))))
403     {
404         rc = BadDevice;
405         goto unwind;
406     }
407
408     ReleaseButtonsAndKeys(dev);
409     AttachDevice(client, dev, newmaster);
410     flags[dev->id] |= XISlaveAttached;
411
412 unwind:
413     return rc;
414 }
415
416
417
418 #define SWAPIF(cmd) if (client->swapped) { cmd; }
419
420 int
421 ProcXIChangeHierarchy(ClientPtr client)
422 {
423     xXIAnyHierarchyChangeInfo *any;
424     int required_len = sizeof(xXIChangeHierarchyReq);
425     int rc = Success;
426     int flags[MAXDEVICES] = {0};
427
428     REQUEST(xXIChangeHierarchyReq);
429     REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
430
431     if (!stuff->num_changes)
432         return rc;
433
434     any = (xXIAnyHierarchyChangeInfo*)&stuff[1];
435     while(stuff->num_changes--)
436     {
437         SWAPIF(swaps(&any->type));
438         SWAPIF(swaps(&any->length));
439
440         required_len += any->length;
441         if ((stuff->length * 4) < required_len)
442             return BadLength;
443
444         switch(any->type)
445         {
446             case XIAddMaster:
447                 {
448                     xXIAddMasterInfo* c = (xXIAddMasterInfo*)any;
449                     SWAPIF(swaps(&c->name_len));
450
451                     rc = add_master(client, c, flags);
452                     if (rc != Success)
453                         goto unwind;
454                 }
455                 break;
456             case XIRemoveMaster:
457                 {
458                     xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any;
459
460                     rc = remove_master(client, r, flags);
461                     if (rc != Success)
462                         goto unwind;
463                 }
464                 break;
465             case XIDetachSlave:
466                 {
467                     xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any;
468
469                     rc = detach_slave(client, c, flags);
470                     if (rc != Success)
471                        goto unwind;
472                 }
473                 break;
474             case XIAttachSlave:
475                 {
476                     xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any;
477
478                     rc = attach_slave(client, c, flags);
479                     if (rc != Success)
480                        goto unwind;
481                 }
482                 break;
483         }
484
485         any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4);
486     }
487
488 unwind:
489
490     XISendDeviceHierarchyEvent(flags);
491     return rc;
492 }
493