1c27c18e8Smrg/************************************************************ 2c27c18e8Smrg 3c27c18e8SmrgCopyright 2009 Red Hat, Inc. 4c27c18e8Smrg 5c27c18e8SmrgPermission to use, copy, modify, distribute, and sell this software and its 6c27c18e8Smrgdocumentation for any purpose is hereby granted without fee, provided that 7c27c18e8Smrgthe above copyright notice appear in all copies and that both that 8c27c18e8Smrgcopyright notice and this permission notice appear in supporting 9c27c18e8Smrgdocumentation. 10c27c18e8Smrg 11c27c18e8SmrgThe above copyright notice and this permission notice shall be included in 12c27c18e8Smrgall copies or substantial portions of the Software. 13c27c18e8Smrg 14c27c18e8SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15c27c18e8SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16c27c18e8SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17c27c18e8SmrgAUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18c27c18e8SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19c27c18e8SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20c27c18e8Smrg 21c27c18e8SmrgExcept as contained in this notice, the name of the author shall not be 22c27c18e8Smrgused in advertising or otherwise to promote the sale, use or other dealings 23c27c18e8Smrgin this Software without prior written authorization from the author. 24c27c18e8Smrg 25c27c18e8Smrg*/ 26c27c18e8Smrg 27c27c18e8Smrg/*********************************************************************** 28c27c18e8Smrg * 29c27c18e8Smrg * XISelectEvent - Select for XI2 events. 30c27c18e8Smrg * 31c27c18e8Smrg */ 32c27c18e8Smrg 33f1ee322dSmrg#ifdef HAVE_CONFIG_H 34f1ee322dSmrg#include <config.h> 35f1ee322dSmrg#endif 36c27c18e8Smrg 37c27c18e8Smrg#include <stdint.h> 38c27c18e8Smrg#include <X11/Xlibint.h> 39c27c18e8Smrg#include <X11/extensions/XI2proto.h> 40c27c18e8Smrg#include <X11/extensions/XInput2.h> 41c27c18e8Smrg#include <X11/extensions/extutil.h> 42c27c18e8Smrg#include <X11/extensions/ge.h> 43c27c18e8Smrg#include <X11/extensions/geproto.h> 44c27c18e8Smrg#include "XIint.h" 45190694daSmrg#include <limits.h> 46c27c18e8Smrg 47c27c18e8Smrgint 48c27c18e8SmrgXISelectEvents(Display* dpy, Window win, XIEventMask* masks, int num_masks) 49c27c18e8Smrg{ 50c27c18e8Smrg XIEventMask *current; 51c27c18e8Smrg xXISelectEventsReq *req; 52c27c18e8Smrg xXIEventMask mask; 53c27c18e8Smrg int i; 54c27c18e8Smrg int len = 0; 553e256790Smrg int r = Success; 5610baa824Smrg int max_mask_len = 0; 5710baa824Smrg char *buff; 58c27c18e8Smrg 59c27c18e8Smrg XExtDisplayInfo *info = XInput_find_display(dpy); 60c27c18e8Smrg LockDisplay(dpy); 61b789ec8aSmrg if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) { 623e256790Smrg r = NoSuchExtension; 6364276682Smrg goto out_unlocked; 643e256790Smrg } 6510baa824Smrg 6610baa824Smrg for (i = 0; i < num_masks; i++) { 6710baa824Smrg current = &masks[i]; 6810baa824Smrg if (current->mask_len > INT_MAX - 3 || 6910baa824Smrg (current->mask_len + 3)/4 >= 0xffff) { 7010baa824Smrg r = -1; 7110baa824Smrg goto out; 7210baa824Smrg } 7310baa824Smrg if (current->mask_len > max_mask_len) 7410baa824Smrg max_mask_len = current->mask_len; 7510baa824Smrg } 7610baa824Smrg 7710baa824Smrg /* max_mask_len is in bytes, but we need 4-byte units on the wire, 7810baa824Smrg * and they need to be padded with 0 */ 7910baa824Smrg buff = calloc(4, ((max_mask_len + 3)/4)); 8010baa824Smrg if (!buff) { 8110baa824Smrg r = -1; 8210baa824Smrg goto out; 8310baa824Smrg } 8410baa824Smrg 85c27c18e8Smrg GetReq(XISelectEvents, req); 86c27c18e8Smrg 87c27c18e8Smrg req->reqType = info->codes->major_opcode; 88c27c18e8Smrg req->ReqType = X_XISelectEvents; 89c27c18e8Smrg req->win = win; 90c27c18e8Smrg req->num_masks = num_masks; 91c27c18e8Smrg 92c27c18e8Smrg /* get the right length */ 93c27c18e8Smrg for (i = 0; i < num_masks; i++) 94c27c18e8Smrg { 95c27c18e8Smrg len++; 96c27c18e8Smrg current = &masks[i]; 97c27c18e8Smrg len += (current->mask_len + 3)/4; 98c27c18e8Smrg } 99c27c18e8Smrg 100c27c18e8Smrg SetReqLen(req, len, len); 101c27c18e8Smrg 102c27c18e8Smrg for (i = 0; i < num_masks; i++) 103c27c18e8Smrg { 104c27c18e8Smrg current = &masks[i]; 105c27c18e8Smrg mask.deviceid = current->deviceid; 106c27c18e8Smrg mask.mask_len = (current->mask_len + 3)/4; 10710baa824Smrg 10810baa824Smrg memset(buff, 0, max_mask_len); 109c27c18e8Smrg memcpy(buff, current->mask, current->mask_len); 110b789ec8aSmrg Data(dpy, (char*)&mask, sizeof(xXIEventMask)); 111c27c18e8Smrg Data(dpy, buff, mask.mask_len * 4); 112c27c18e8Smrg } 113c27c18e8Smrg 11410baa824Smrg free(buff); 1153e256790Smrgout: 116c27c18e8Smrg UnlockDisplay(dpy); 11764276682Smrgout_unlocked: 118c27c18e8Smrg SyncHandle(); 1193e256790Smrg return r; 120c27c18e8Smrg 121c27c18e8Smrg} 122c27c18e8Smrg 123c27c18e8SmrgXIEventMask* 124c27c18e8SmrgXIGetSelectedEvents(Display* dpy, Window win, int *num_masks_return) 125c27c18e8Smrg{ 126190694daSmrg unsigned int i, len = 0; 127c27c18e8Smrg unsigned char *mask; 128c27c18e8Smrg XIEventMask *mask_out = NULL; 129c27c18e8Smrg xXIEventMask *mask_in = NULL, *mi; 130c27c18e8Smrg xXIGetSelectedEventsReq *req; 131c27c18e8Smrg xXIGetSelectedEventsReply reply; 13237eb1ca1Smrg XExtDisplayInfo *info = XInput_find_display(dpy); 133190694daSmrg size_t rbytes; 134c27c18e8Smrg 1353e256790Smrg *num_masks_return = -1; 136c27c18e8Smrg LockDisplay(dpy); 137b789ec8aSmrg if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) 13864276682Smrg goto out_unlocked; 139c27c18e8Smrg 140c27c18e8Smrg GetReq(XIGetSelectedEvents, req); 141c27c18e8Smrg 142c27c18e8Smrg req->reqType = info->codes->major_opcode; 143c27c18e8Smrg req->ReqType = X_XIGetSelectedEvents; 144c27c18e8Smrg req->win = win; 145c27c18e8Smrg 146c27c18e8Smrg if (!_XReply(dpy, (xReply *) &reply, 0, xFalse)) 1473e256790Smrg goto out; 148c27c18e8Smrg 149c27c18e8Smrg if (reply.num_masks == 0) 150c27c18e8Smrg { 151c27c18e8Smrg *num_masks_return = 0; 1523e256790Smrg goto out; 153c27c18e8Smrg } 154c27c18e8Smrg 155190694daSmrg if (reply.length < (INT_MAX >> 2)) { 156190694daSmrg rbytes = (unsigned long) reply.length << 2; 157190694daSmrg mask_in = Xmalloc(rbytes); 158190694daSmrg } 159190694daSmrg if (!mask_in) { 160190694daSmrg _XEatDataWords(dpy, reply.length); 1613e256790Smrg goto out; 162190694daSmrg } 163c27c18e8Smrg 164190694daSmrg _XRead(dpy, (char*)mask_in, rbytes); 165c27c18e8Smrg 16610baa824Smrg /* 16710baa824Smrg * This function takes interleaved xXIEventMask structs & masks off 16810baa824Smrg * the wire, such as this 3 mask reply: 16910baa824Smrg * [struct a][masks a][struct b][masks b][struct c][masks c] 17010baa824Smrg * And generates a memory buffer to be returned to callers in which 17110baa824Smrg * they are not interleaved, so that callers can treat the returned 17210baa824Smrg * pointer as a simple array of XIEventMask structs, such as: 17310baa824Smrg * [struct a][struct b][struct c][masks a][masks b][masks c] 174c27c18e8Smrg */ 175c27c18e8Smrg len = reply.num_masks * sizeof(XIEventMask); 176c27c18e8Smrg 177c27c18e8Smrg for (i = 0, mi = mask_in; i < reply.num_masks; i++) 178c27c18e8Smrg { 179190694daSmrg unsigned int mask_bytes = mi->mask_len * 4; 180190694daSmrg len += mask_bytes; 181190694daSmrg if (len > INT_MAX) 182190694daSmrg goto out; 183190694daSmrg if ((sizeof(xXIEventMask) + mask_bytes) > rbytes) 184190694daSmrg goto out; 185190694daSmrg rbytes -= (sizeof(xXIEventMask) + mask_bytes); 186190694daSmrg mi = (xXIEventMask*)((char*)mi + mask_bytes); 187c27c18e8Smrg mi++; 188c27c18e8Smrg } 189c27c18e8Smrg 190c27c18e8Smrg mask_out = Xmalloc(len); 191c27c18e8Smrg if (!mask_out) 1923e256790Smrg goto out; 193c27c18e8Smrg 194c27c18e8Smrg mi = mask_in; 195c27c18e8Smrg mask = (unsigned char*)&mask_out[reply.num_masks]; 196c27c18e8Smrg for (i = 0; i < reply.num_masks; i++) 197c27c18e8Smrg { 198c27c18e8Smrg mask_out[i].deviceid = mi->deviceid; 199c27c18e8Smrg mask_out[i].mask_len = mi->mask_len * 4; 200c27c18e8Smrg mask_out[i].mask = mask; 201c27c18e8Smrg memcpy(mask_out[i].mask, &mi[1], mask_out[i].mask_len); 202c27c18e8Smrg mask += mask_out[i].mask_len; 203c27c18e8Smrg mi = (xXIEventMask*)((char*)mi + mi->mask_len * 4); 204c27c18e8Smrg mi++; 205c27c18e8Smrg } 206c27c18e8Smrg 207c27c18e8Smrg *num_masks_return = reply.num_masks; 208c27c18e8Smrg 2093e256790Smrgout: 2103e256790Smrg Xfree(mask_in); 211c27c18e8Smrg 212c27c18e8Smrg UnlockDisplay(dpy); 21364276682Smrg 21464276682Smrgout_unlocked: 215c27c18e8Smrg SyncHandle(); 216c27c18e8Smrg 2173e256790Smrg return mask_out; 218c27c18e8Smrg} 219