os: if inet_ntop() is available, use it for IPv4 addresses as well
[xserver.git] / Xi / xichangehierarchy.c
blobcd4c1f5f0b23d3c03ba5d95b3bf6bef7807f76a0
1 /*
2 * Copyright 2007-2008 Peter Hutterer
3 * Copyright 2009 Red Hat, Inc.
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:
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.
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.
24 * Author: Peter Hutterer, University of South Australia, NICTA
27 /***********************************************************************
29 * Request change in the device hierarchy.
33 #include <dix-config.h>
35 #include <X11/X.h> /* for inputstr.h */
36 #include <X11/Xproto.h> /* Request macro */
37 #include <X11/extensions/XI.h>
38 #include <X11/extensions/XI2proto.h>
39 #include <X11/extensions/geproto.h>
41 #include "dix/dix_priv.h"
42 #include "dix/exevents_priv.h"
43 #include "dix/input_priv.h"
45 #include "inputstr.h" /* DeviceIntPtr */
46 #include "windowstr.h" /* window structure */
47 #include "scrnintstr.h" /* screen structure */
48 #include "extnsionst.h"
49 #include "exglobals.h"
50 #include "geext.h"
51 #include "misc.h"
52 #include "xace.h"
53 #include "xiquerydevice.h" /* for GetDeviceUse */
54 #include "xkbsrv.h"
55 #include "xichangehierarchy.h"
56 #include "xibarriers.h"
58 /**
59 * Send the current state of the device hierarchy to all clients.
61 void
62 XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
64 xXIHierarchyEvent *ev;
65 xXIHierarchyInfo *info;
66 DeviceIntRec dummyDev;
67 DeviceIntPtr dev;
68 int i;
70 if (!flags)
71 return;
73 ev = calloc(1, sizeof(xXIHierarchyEvent) +
74 MAXDEVICES * sizeof(xXIHierarchyInfo));
75 if (!ev)
76 return;
77 ev->type = GenericEvent;
78 ev->extension = IReqCode;
79 ev->evtype = XI_HierarchyChanged;
80 ev->time = GetTimeInMillis();
81 ev->flags = 0;
82 ev->num_info = inputInfo.numDevices;
84 info = (xXIHierarchyInfo *) &ev[1];
85 for (dev = inputInfo.devices; dev; dev = dev->next) {
86 info->deviceid = dev->id;
87 info->enabled = dev->enabled;
88 info->use = GetDeviceUse(dev, &info->attachment);
89 info->flags = flags[dev->id];
90 ev->flags |= info->flags;
91 info++;
93 for (dev = inputInfo.off_devices; dev; dev = dev->next) {
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++;
102 for (i = 0; i < MAXDEVICES; i++) {
103 if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) {
104 info->deviceid = i;
105 info->enabled = FALSE;
106 info->flags = flags[i];
107 info->use = 0;
108 ev->flags |= info->flags;
109 ev->num_info++;
110 info++;
114 ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
116 memset(&dummyDev, 0, sizeof(dummyDev));
117 dummyDev.id = XIAllDevices;
118 dummyDev.type = SLAVE;
119 SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8),
120 (xEvent *) ev, 1);
121 free(ev);
124 /***********************************************************************
126 * This procedure allows a client to change the device hierarchy through
127 * adding new master devices, removing them, etc.
131 int _X_COLD
132 SProcXIChangeHierarchy(ClientPtr client)
134 REQUEST(xXIChangeHierarchyReq);
135 swaps(&stuff->length);
136 return (ProcXIChangeHierarchy(client));
139 static int
140 add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES])
142 DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
143 char *name;
144 int rc;
146 name = calloc(c->name_len + 1, sizeof(char));
147 if (name == NULL) {
148 rc = BadAlloc;
149 goto unwind;
151 strncpy(name, (char *) &c[1], c->name_len);
153 rc = AllocDevicePair(client, name, &ptr, &keybd,
154 CorePointerProc, CoreKeyboardProc, TRUE);
155 if (rc != Success)
156 goto unwind;
158 if (!c->send_core)
159 ptr->coreEvents = keybd->coreEvents = FALSE;
161 /* Allocate virtual slave devices for xtest events */
162 rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
163 if (rc != Success) {
164 DeleteInputDeviceRequest(ptr);
165 DeleteInputDeviceRequest(keybd);
166 goto unwind;
169 ActivateDevice(ptr, FALSE);
170 ActivateDevice(keybd, FALSE);
171 flags[ptr->id] |= XIMasterAdded;
172 flags[keybd->id] |= XIMasterAdded;
174 ActivateDevice(XTestptr, FALSE);
175 ActivateDevice(XTestkeybd, FALSE);
176 flags[XTestptr->id] |= XISlaveAdded;
177 flags[XTestkeybd->id] |= XISlaveAdded;
179 if (c->enable) {
180 EnableDevice(ptr, FALSE);
181 EnableDevice(keybd, FALSE);
182 flags[ptr->id] |= XIDeviceEnabled;
183 flags[keybd->id] |= XIDeviceEnabled;
185 EnableDevice(XTestptr, FALSE);
186 EnableDevice(XTestkeybd, FALSE);
187 flags[XTestptr->id] |= XIDeviceEnabled;
188 flags[XTestkeybd->id] |= XIDeviceEnabled;
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;
198 for (int i = 0; i < currentMaxClients; i++)
199 XIBarrierNewMasterDevice(clients[i], ptr->id);
201 unwind:
202 free(name);
203 return rc;
206 static void
207 disable_clientpointer(DeviceIntPtr dev)
209 int i;
211 for (i = 0; i < currentMaxClients; i++) {
212 ClientPtr client = clients[i];
214 if (client && client->clientPtr == dev)
215 client->clientPtr = NULL;
219 static DeviceIntPtr
220 find_disabled_master(int type)
222 DeviceIntPtr dev;
224 /* Once a master device is disabled it loses the pairing, so returning the first
225 * match is good enough */
226 for (dev = inputInfo.off_devices; dev; dev = dev->next) {
227 if (dev->type == type)
228 return dev;
231 return NULL;
234 static int
235 remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
237 DeviceIntPtr dev, ptr, keybd, XTestptr, XTestkeybd;
238 int rc = Success;
240 if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
241 return BadValue;
243 rc = dixLookupDevice(&dev, r->deviceid, client, DixDestroyAccess);
244 if (rc != Success)
245 goto unwind;
247 if (!IsMaster(dev)) {
248 client->errorValue = r->deviceid;
249 rc = BadDevice;
250 goto unwind;
253 /* XXX: For now, don't allow removal of VCP, VCK */
254 if (dev == inputInfo.pointer || dev == inputInfo.keyboard) {
255 rc = BadDevice;
256 goto unwind;
259 if ((ptr = GetMaster(dev, MASTER_POINTER)) == NULL)
260 ptr = find_disabled_master(MASTER_POINTER);
261 BUG_RETURN_VAL(ptr == NULL, BadDevice);
262 rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
263 if (rc != Success)
264 goto unwind;
266 if ((keybd = GetMaster(dev, MASTER_KEYBOARD)) == NULL)
267 keybd = find_disabled_master(MASTER_KEYBOARD);
268 BUG_RETURN_VAL(keybd == NULL, BadDevice);
269 rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
270 if (rc != Success)
271 goto unwind;
273 XTestptr = GetXTestDevice(ptr);
274 BUG_RETURN_VAL(XTestptr == NULL, BadDevice);
275 rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
276 if (rc != Success)
277 goto unwind;
279 XTestkeybd = GetXTestDevice(keybd);
280 BUG_RETURN_VAL(XTestkeybd == NULL, BadDevice);
281 rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
282 if (rc != Success)
283 goto unwind;
285 disable_clientpointer(ptr);
287 /* Disabling sends the devices floating, reattach them if
288 * desired. */
289 if (r->return_mode == XIAttachToMaster) {
290 DeviceIntPtr attached, newptr, newkeybd;
292 rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
293 if (rc != Success)
294 goto unwind;
296 if (!IsMaster(newptr) || !IsPointerDevice(newptr)) {
297 client->errorValue = r->return_pointer;
298 rc = BadDevice;
299 goto unwind;
302 rc = dixLookupDevice(&newkeybd, r->return_keyboard,
303 client, DixAddAccess);
304 if (rc != Success)
305 goto unwind;
307 if (!IsMaster(newkeybd) || !IsKeyboardDevice(newkeybd)) {
308 client->errorValue = r->return_keyboard;
309 rc = BadDevice;
310 goto unwind;
313 for (attached = inputInfo.devices; attached; attached = attached->next) {
314 if (!IsMaster(attached)) {
315 if (GetMaster(attached, MASTER_ATTACHED) == ptr) {
316 AttachDevice(client, attached, newptr);
317 flags[attached->id] |= XISlaveAttached;
319 if (GetMaster(attached, MASTER_ATTACHED) == keybd) {
320 AttachDevice(client, attached, newkeybd);
321 flags[attached->id] |= XISlaveAttached;
327 for (int i = 0; i < currentMaxClients; i++)
328 XIBarrierRemoveMasterDevice(clients[i], ptr->id);
330 /* disable the remove the devices, XTest devices must be done first
331 else the sprites they rely on will be destroyed */
332 DisableDevice(XTestptr, FALSE);
333 DisableDevice(XTestkeybd, FALSE);
334 DisableDevice(keybd, FALSE);
335 DisableDevice(ptr, FALSE);
336 flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
337 flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
338 flags[keybd->id] |= XIDeviceDisabled;
339 flags[ptr->id] |= XIDeviceDisabled;
341 flags[XTestptr->id] |= XISlaveRemoved;
342 flags[XTestkeybd->id] |= XISlaveRemoved;
343 flags[keybd->id] |= XIMasterRemoved;
344 flags[ptr->id] |= XIMasterRemoved;
346 RemoveDevice(XTestptr, FALSE);
347 RemoveDevice(XTestkeybd, FALSE);
348 RemoveDevice(keybd, FALSE);
349 RemoveDevice(ptr, FALSE);
351 unwind:
352 return rc;
355 static int
356 detach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES])
358 DeviceIntPtr dev;
359 int rc;
361 rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
362 if (rc != Success)
363 goto unwind;
365 if (IsMaster(dev)) {
366 client->errorValue = c->deviceid;
367 rc = BadDevice;
368 goto unwind;
371 /* Don't allow changes to XTest Devices, these are fixed */
372 if (IsXTestDevice(dev, NULL)) {
373 client->errorValue = c->deviceid;
374 rc = BadDevice;
375 goto unwind;
378 ReleaseButtonsAndKeys(dev);
379 AttachDevice(client, dev, NULL);
380 flags[dev->id] |= XISlaveDetached;
382 unwind:
383 return rc;
386 static int
387 attach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES])
389 DeviceIntPtr dev;
390 DeviceIntPtr newmaster;
391 int rc;
393 rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
394 if (rc != Success)
395 goto unwind;
397 if (IsMaster(dev)) {
398 client->errorValue = c->deviceid;
399 rc = BadDevice;
400 goto unwind;
403 /* Don't allow changes to XTest Devices, these are fixed */
404 if (IsXTestDevice(dev, NULL)) {
405 client->errorValue = c->deviceid;
406 rc = BadDevice;
407 goto unwind;
410 rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
411 if (rc != Success)
412 goto unwind;
413 if (!IsMaster(newmaster)) {
414 client->errorValue = c->new_master;
415 rc = BadDevice;
416 goto unwind;
419 if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
420 (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) {
421 rc = BadDevice;
422 goto unwind;
425 ReleaseButtonsAndKeys(dev);
426 AttachDevice(client, dev, newmaster);
427 flags[dev->id] |= XISlaveAttached;
429 unwind:
430 return rc;
433 #define SWAPIF(cmd) if (client->swapped) { cmd; }
436 ProcXIChangeHierarchy(ClientPtr client)
438 xXIAnyHierarchyChangeInfo *any;
439 size_t len; /* length of data remaining in request */
440 int rc = Success;
441 int flags[MAXDEVICES] = { 0 };
442 enum {
443 NO_CHANGE,
444 FLUSH,
445 CHANGED,
446 } changes = NO_CHANGE;
448 REQUEST(xXIChangeHierarchyReq);
449 REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
451 if (!stuff->num_changes)
452 return rc;
454 len = ((size_t)client->req_len << 2) - sizeof(xXIChangeHierarchyReq);
456 any = (xXIAnyHierarchyChangeInfo *) &stuff[1];
457 while (stuff->num_changes--) {
458 if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
459 rc = BadLength;
460 goto unwind;
463 SWAPIF(swaps(&any->type));
464 SWAPIF(swaps(&any->length));
466 if (len < ((size_t)any->length << 2))
467 return BadLength;
469 #define CHANGE_SIZE_MATCH(type) \
470 do { \
471 if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
472 rc = BadLength; \
473 goto unwind; \
475 } while(0)
477 switch (any->type) {
478 case XIAddMaster:
480 xXIAddMasterInfo *c = (xXIAddMasterInfo *) any;
482 /* Variable length, due to appended name string */
483 if (len < sizeof(xXIAddMasterInfo)) {
484 rc = BadLength;
485 goto unwind;
487 SWAPIF(swaps(&c->name_len));
488 if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
489 rc = BadLength;
490 goto unwind;
493 rc = add_master(client, c, flags);
494 if (rc != Success)
495 goto unwind;
496 changes = FLUSH;
497 break;
499 case XIRemoveMaster:
501 xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
503 CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
504 rc = remove_master(client, r, flags);
505 if (rc != Success)
506 goto unwind;
507 changes = FLUSH;
508 break;
510 case XIDetachSlave:
512 xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
514 CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
515 rc = detach_slave(client, c, flags);
516 if (rc != Success)
517 goto unwind;
518 changes = CHANGED;
519 break;
521 case XIAttachSlave:
523 xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
525 CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
526 rc = attach_slave(client, c, flags);
527 if (rc != Success)
528 goto unwind;
529 changes = CHANGED;
530 break;
532 default:
533 break;
536 if (changes == FLUSH) {
537 XISendDeviceHierarchyEvent(flags);
538 memset(flags, 0, sizeof(flags));
539 changes = NO_CHANGE;
542 len -= any->length * 4;
543 any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
546 unwind:
547 if (changes != NO_CHANGE)
548 XISendDeviceHierarchyEvent(flags);
549 return rc;