xichangehierarchy.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. * Request change in the device hierarchy.
  29. *
  30. */
  31. #ifdef HAVE_DIX_CONFIG_H
  32. #include <dix-config.h>
  33. #endif
  34. #include <X11/X.h> /* for inputstr.h */
  35. #include <X11/Xproto.h> /* Request macro */
  36. #include "inputstr.h" /* DeviceIntPtr */
  37. #include "windowstr.h" /* window structure */
  38. #include "scrnintstr.h" /* screen structure */
  39. #include <X11/extensions/XI.h>
  40. #include <X11/extensions/XI2proto.h>
  41. #include <X11/extensions/geproto.h>
  42. #include "extnsionst.h"
  43. #include "exevents.h"
  44. #include "exglobals.h"
  45. #include "geext.h"
  46. #include "xace.h"
  47. #include "xiquerydevice.h" /* for GetDeviceUse */
  48. #include "xkbsrv.h"
  49. #include "xichangehierarchy.h"
  50. #include "xibarriers.h"
  51. /**
  52. * Send the current state of the device hierarchy to all clients.
  53. */
  54. void
  55. XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
  56. {
  57. xXIHierarchyEvent *ev;
  58. xXIHierarchyInfo *info;
  59. DeviceIntRec dummyDev;
  60. DeviceIntPtr dev;
  61. int i;
  62. if (!flags)
  63. return;
  64. ev = calloc(1, sizeof(xXIHierarchyEvent) +
  65. MAXDEVICES * sizeof(xXIHierarchyInfo));
  66. if (!ev)
  67. return;
  68. ev->type = GenericEvent;
  69. ev->extension = IReqCode;
  70. ev->evtype = XI_HierarchyChanged;
  71. ev->time = GetTimeInMillis();
  72. ev->flags = 0;
  73. ev->num_info = inputInfo.numDevices;
  74. info = (xXIHierarchyInfo *) &ev[1];
  75. for (dev = inputInfo.devices; dev; dev = dev->next) {
  76. info->deviceid = dev->id;
  77. info->enabled = dev->enabled;
  78. info->use = GetDeviceUse(dev, &info->attachment);
  79. info->flags = flags[dev->id];
  80. ev->flags |= info->flags;
  81. info++;
  82. }
  83. for (dev = inputInfo.off_devices; dev; dev = dev->next) {
  84. info->deviceid = dev->id;
  85. info->enabled = dev->enabled;
  86. info->use = GetDeviceUse(dev, &info->attachment);
  87. info->flags = flags[dev->id];
  88. ev->flags |= info->flags;
  89. info++;
  90. }
  91. for (i = 0; i < MAXDEVICES; i++) {
  92. if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) {
  93. info->deviceid = i;
  94. info->enabled = FALSE;
  95. info->flags = flags[i];
  96. info->use = 0;
  97. ev->flags |= info->flags;
  98. ev->num_info++;
  99. info++;
  100. }
  101. }
  102. ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
  103. memset(&dummyDev, 0, sizeof(dummyDev));
  104. dummyDev.id = XIAllDevices;
  105. dummyDev.type = SLAVE;
  106. SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8),
  107. (xEvent *) ev, 1);
  108. free(ev);
  109. }
  110. /***********************************************************************
  111. *
  112. * This procedure allows a client to change the device hierarchy through
  113. * adding new master devices, removing them, etc.
  114. *
  115. */
  116. int
  117. SProcXIChangeHierarchy(ClientPtr client)
  118. {
  119. REQUEST(xXIChangeHierarchyReq);
  120. swaps(&stuff->length);
  121. return (ProcXIChangeHierarchy(client));
  122. }
  123. static int
  124. add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES])
  125. {
  126. DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
  127. char *name;
  128. int rc;
  129. name = calloc(c->name_len + 1, sizeof(char));
  130. if (name == NULL) {
  131. rc = BadAlloc;
  132. goto unwind;
  133. }
  134. strncpy(name, (char *) &c[1], c->name_len);
  135. rc = AllocDevicePair(client, name, &ptr, &keybd,
  136. CorePointerProc, CoreKeyboardProc, TRUE);
  137. if (rc != Success)
  138. goto unwind;
  139. if (!c->send_core)
  140. ptr->coreEvents = keybd->coreEvents = FALSE;
  141. /* Allocate virtual slave devices for xtest events */
  142. rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
  143. if (rc != Success) {
  144. DeleteInputDeviceRequest(ptr);
  145. DeleteInputDeviceRequest(keybd);
  146. goto unwind;
  147. }
  148. ActivateDevice(ptr, FALSE);
  149. ActivateDevice(keybd, FALSE);
  150. flags[ptr->id] |= XIMasterAdded;
  151. flags[keybd->id] |= XIMasterAdded;
  152. ActivateDevice(XTestptr, FALSE);
  153. ActivateDevice(XTestkeybd, FALSE);
  154. flags[XTestptr->id] |= XISlaveAdded;
  155. flags[XTestkeybd->id] |= XISlaveAdded;
  156. if (c->enable) {
  157. EnableDevice(ptr, FALSE);
  158. EnableDevice(keybd, FALSE);
  159. flags[ptr->id] |= XIDeviceEnabled;
  160. flags[keybd->id] |= XIDeviceEnabled;
  161. EnableDevice(XTestptr, FALSE);
  162. EnableDevice(XTestkeybd, FALSE);
  163. flags[XTestptr->id] |= XIDeviceEnabled;
  164. flags[XTestkeybd->id] |= XIDeviceEnabled;
  165. }
  166. /* Attach the XTest virtual devices to the newly
  167. created master device */
  168. AttachDevice(NULL, XTestptr, ptr);
  169. AttachDevice(NULL, XTestkeybd, keybd);
  170. flags[XTestptr->id] |= XISlaveAttached;
  171. flags[XTestkeybd->id] |= XISlaveAttached;
  172. XIBarrierNewMasterDevice(client, ptr->id);
  173. unwind:
  174. free(name);
  175. return rc;
  176. }
  177. static void
  178. disable_clientpointer(DeviceIntPtr dev)
  179. {
  180. int i;
  181. for (i = 0; i < currentMaxClients; i++) {
  182. ClientPtr client = clients[i];
  183. if (client && client->clientPtr == dev)
  184. client->clientPtr = NULL;
  185. }
  186. }
  187. static int
  188. remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
  189. {
  190. DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
  191. int rc = Success;
  192. if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
  193. return BadValue;
  194. rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
  195. if (rc != Success)
  196. goto unwind;
  197. if (!IsMaster(ptr)) {
  198. client->errorValue = r->deviceid;
  199. rc = BadDevice;
  200. goto unwind;
  201. }
  202. /* XXX: For now, don't allow removal of VCP, VCK */
  203. if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
  204. rc = BadDevice;
  205. goto unwind;
  206. }
  207. ptr = GetMaster(ptr, MASTER_POINTER);
  208. rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
  209. if (rc != Success)
  210. goto unwind;
  211. keybd = GetMaster(ptr, MASTER_KEYBOARD);
  212. rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
  213. if (rc != Success)
  214. goto unwind;
  215. XTestptr = GetXTestDevice(ptr);
  216. rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
  217. if (rc != Success)
  218. goto unwind;
  219. XTestkeybd = GetXTestDevice(keybd);
  220. rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
  221. if (rc != Success)
  222. goto unwind;
  223. disable_clientpointer(ptr);
  224. /* Disabling sends the devices floating, reattach them if
  225. * desired. */
  226. if (r->return_mode == XIAttachToMaster) {
  227. DeviceIntPtr attached, newptr, newkeybd;
  228. rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
  229. if (rc != Success)
  230. goto unwind;
  231. if (!IsMaster(newptr)) {
  232. client->errorValue = r->return_pointer;
  233. rc = BadDevice;
  234. goto unwind;
  235. }
  236. rc = dixLookupDevice(&newkeybd, r->return_keyboard,
  237. client, DixAddAccess);
  238. if (rc != Success)
  239. goto unwind;
  240. if (!IsMaster(newkeybd)) {
  241. client->errorValue = r->return_keyboard;
  242. rc = BadDevice;
  243. goto unwind;
  244. }
  245. for (attached = inputInfo.devices; attached; attached = attached->next) {
  246. if (!IsMaster(attached)) {
  247. if (GetMaster(attached, MASTER_ATTACHED) == ptr) {
  248. AttachDevice(client, attached, newptr);
  249. flags[attached->id] |= XISlaveAttached;
  250. }
  251. if (GetMaster(attached, MASTER_ATTACHED) == keybd) {
  252. AttachDevice(client, attached, newkeybd);
  253. flags[attached->id] |= XISlaveAttached;
  254. }
  255. }
  256. }
  257. }
  258. XIBarrierRemoveMasterDevice(client, ptr->id);
  259. /* disable the remove the devices, XTest devices must be done first
  260. else the sprites they rely on will be destroyed */
  261. DisableDevice(XTestptr, FALSE);
  262. DisableDevice(XTestkeybd, FALSE);
  263. DisableDevice(keybd, FALSE);
  264. DisableDevice(ptr, FALSE);
  265. flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
  266. flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
  267. flags[keybd->id] |= XIDeviceDisabled;
  268. flags[ptr->id] |= XIDeviceDisabled;
  269. flags[XTestptr->id] |= XISlaveRemoved;
  270. flags[XTestkeybd->id] |= XISlaveRemoved;
  271. flags[keybd->id] |= XIMasterRemoved;
  272. flags[ptr->id] |= XIMasterRemoved;
  273. RemoveDevice(XTestptr, FALSE);
  274. RemoveDevice(XTestkeybd, FALSE);
  275. RemoveDevice(keybd, FALSE);
  276. RemoveDevice(ptr, FALSE);
  277. unwind:
  278. return rc;
  279. }
  280. static int
  281. detach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES])
  282. {
  283. DeviceIntPtr dev;
  284. int rc;
  285. rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
  286. if (rc != Success)
  287. goto unwind;
  288. if (IsMaster(dev)) {
  289. client->errorValue = c->deviceid;
  290. rc = BadDevice;
  291. goto unwind;
  292. }
  293. /* Don't allow changes to XTest Devices, these are fixed */
  294. if (IsXTestDevice(dev, NULL)) {
  295. client->errorValue = c->deviceid;
  296. rc = BadDevice;
  297. goto unwind;
  298. }
  299. ReleaseButtonsAndKeys(dev);
  300. AttachDevice(client, dev, NULL);
  301. flags[dev->id] |= XISlaveDetached;
  302. unwind:
  303. return rc;
  304. }
  305. static int
  306. attach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES])
  307. {
  308. DeviceIntPtr dev;
  309. DeviceIntPtr newmaster;
  310. int rc;
  311. rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
  312. if (rc != Success)
  313. goto unwind;
  314. if (IsMaster(dev)) {
  315. client->errorValue = c->deviceid;
  316. rc = BadDevice;
  317. goto unwind;
  318. }
  319. /* Don't allow changes to XTest Devices, these are fixed */
  320. if (IsXTestDevice(dev, NULL)) {
  321. client->errorValue = c->deviceid;
  322. rc = BadDevice;
  323. goto unwind;
  324. }
  325. rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
  326. if (rc != Success)
  327. goto unwind;
  328. if (!IsMaster(newmaster)) {
  329. client->errorValue = c->new_master;
  330. rc = BadDevice;
  331. goto unwind;
  332. }
  333. if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
  334. (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) {
  335. rc = BadDevice;
  336. goto unwind;
  337. }
  338. ReleaseButtonsAndKeys(dev);
  339. AttachDevice(client, dev, newmaster);
  340. flags[dev->id] |= XISlaveAttached;
  341. unwind:
  342. return rc;
  343. }
  344. #define SWAPIF(cmd) if (client->swapped) { cmd; }
  345. int
  346. ProcXIChangeHierarchy(ClientPtr client)
  347. {
  348. xXIAnyHierarchyChangeInfo *any;
  349. size_t len; /* length of data remaining in request */
  350. int rc = Success;
  351. int flags[MAXDEVICES] = { 0 };
  352. REQUEST(xXIChangeHierarchyReq);
  353. REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
  354. if (!stuff->num_changes)
  355. return rc;
  356. if (stuff->length > (INT_MAX >> 2))
  357. return BadAlloc;
  358. len = (stuff->length << 2) - sizeof(xXIAnyHierarchyChangeInfo);
  359. any = (xXIAnyHierarchyChangeInfo *) &stuff[1];
  360. while (stuff->num_changes--) {
  361. if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
  362. rc = BadLength;
  363. goto unwind;
  364. }
  365. SWAPIF(swaps(&any->type));
  366. SWAPIF(swaps(&any->length));
  367. if ((any->length > (INT_MAX >> 2)) || (len < (any->length << 2)))
  368. return BadLength;
  369. #define CHANGE_SIZE_MATCH(type) \
  370. do { \
  371. if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
  372. rc = BadLength; \
  373. goto unwind; \
  374. } \
  375. } while(0)
  376. switch (any->type) {
  377. case XIAddMaster:
  378. {
  379. xXIAddMasterInfo *c = (xXIAddMasterInfo *) any;
  380. /* Variable length, due to appended name string */
  381. if (len < sizeof(xXIAddMasterInfo)) {
  382. rc = BadLength;
  383. goto unwind;
  384. }
  385. SWAPIF(swaps(&c->name_len));
  386. if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
  387. rc = BadLength;
  388. goto unwind;
  389. }
  390. rc = add_master(client, c, flags);
  391. if (rc != Success)
  392. goto unwind;
  393. }
  394. break;
  395. case XIRemoveMaster:
  396. {
  397. xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
  398. CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
  399. rc = remove_master(client, r, flags);
  400. if (rc != Success)
  401. goto unwind;
  402. }
  403. break;
  404. case XIDetachSlave:
  405. {
  406. xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
  407. CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
  408. rc = detach_slave(client, c, flags);
  409. if (rc != Success)
  410. goto unwind;
  411. }
  412. break;
  413. case XIAttachSlave:
  414. {
  415. xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
  416. CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
  417. rc = attach_slave(client, c, flags);
  418. if (rc != Success)
  419. goto unwind;
  420. }
  421. break;
  422. }
  423. len -= any->length * 4;
  424. any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
  425. }
  426. unwind:
  427. XISendDeviceHierarchyEvent(flags);
  428. return rc;
  429. }