XISelEv.c revision 64276682
1/************************************************************ 2 3Copyright 2009 Red Hat, Inc. 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of the author shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from the author. 24 25*/ 26 27/*********************************************************************** 28 * 29 * XISelectEvent - Select for XI2 events. 30 * 31 */ 32 33#ifdef HAVE_CONFIG_H 34#include <config.h> 35#endif 36 37#include <stdint.h> 38#include <X11/Xlibint.h> 39#include <X11/extensions/XI2proto.h> 40#include <X11/extensions/XInput2.h> 41#include <X11/extensions/extutil.h> 42#include <X11/extensions/ge.h> 43#include <X11/extensions/geproto.h> 44#include "XIint.h" 45#include <limits.h> 46 47int 48XISelectEvents(Display* dpy, Window win, XIEventMask* masks, int num_masks) 49{ 50 XIEventMask *current; 51 xXISelectEventsReq *req; 52 xXIEventMask mask; 53 int i; 54 int len = 0; 55 int r = Success; 56 int max_mask_len = 0; 57 char *buff; 58 59 XExtDisplayInfo *info = XInput_find_display(dpy); 60 LockDisplay(dpy); 61 if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) { 62 r = NoSuchExtension; 63 goto out_unlocked; 64 } 65 66 for (i = 0; i < num_masks; i++) { 67 current = &masks[i]; 68 if (current->mask_len > INT_MAX - 3 || 69 (current->mask_len + 3)/4 >= 0xffff) { 70 r = -1; 71 goto out; 72 } 73 if (current->mask_len > max_mask_len) 74 max_mask_len = current->mask_len; 75 } 76 77 /* max_mask_len is in bytes, but we need 4-byte units on the wire, 78 * and they need to be padded with 0 */ 79 buff = calloc(4, ((max_mask_len + 3)/4)); 80 if (!buff) { 81 r = -1; 82 goto out; 83 } 84 85 GetReq(XISelectEvents, req); 86 87 req->reqType = info->codes->major_opcode; 88 req->ReqType = X_XISelectEvents; 89 req->win = win; 90 req->num_masks = num_masks; 91 92 /* get the right length */ 93 for (i = 0; i < num_masks; i++) 94 { 95 len++; 96 current = &masks[i]; 97 len += (current->mask_len + 3)/4; 98 } 99 100 SetReqLen(req, len, len); 101 102 for (i = 0; i < num_masks; i++) 103 { 104 current = &masks[i]; 105 mask.deviceid = current->deviceid; 106 mask.mask_len = (current->mask_len + 3)/4; 107 108 memset(buff, 0, max_mask_len); 109 memcpy(buff, current->mask, current->mask_len); 110 Data(dpy, (char*)&mask, sizeof(xXIEventMask)); 111 Data(dpy, buff, mask.mask_len * 4); 112 } 113 114 free(buff); 115out: 116 UnlockDisplay(dpy); 117out_unlocked: 118 SyncHandle(); 119 return r; 120 121} 122 123XIEventMask* 124XIGetSelectedEvents(Display* dpy, Window win, int *num_masks_return) 125{ 126 unsigned int i, len = 0; 127 unsigned char *mask; 128 XIEventMask *mask_out = NULL; 129 xXIEventMask *mask_in = NULL, *mi; 130 xXIGetSelectedEventsReq *req; 131 xXIGetSelectedEventsReply reply; 132 XExtDisplayInfo *info = XInput_find_display(dpy); 133 size_t rbytes; 134 135 *num_masks_return = -1; 136 LockDisplay(dpy); 137 if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) 138 goto out_unlocked; 139 140 GetReq(XIGetSelectedEvents, req); 141 142 req->reqType = info->codes->major_opcode; 143 req->ReqType = X_XIGetSelectedEvents; 144 req->win = win; 145 146 if (!_XReply(dpy, (xReply *) &reply, 0, xFalse)) 147 goto out; 148 149 if (reply.num_masks == 0) 150 { 151 *num_masks_return = 0; 152 goto out; 153 } 154 155 if (reply.length < (INT_MAX >> 2)) { 156 rbytes = (unsigned long) reply.length << 2; 157 mask_in = Xmalloc(rbytes); 158 } 159 if (!mask_in) { 160 _XEatDataWords(dpy, reply.length); 161 goto out; 162 } 163 164 _XRead(dpy, (char*)mask_in, rbytes); 165 166 /* 167 * This function takes interleaved xXIEventMask structs & masks off 168 * the wire, such as this 3 mask reply: 169 * [struct a][masks a][struct b][masks b][struct c][masks c] 170 * And generates a memory buffer to be returned to callers in which 171 * they are not interleaved, so that callers can treat the returned 172 * pointer as a simple array of XIEventMask structs, such as: 173 * [struct a][struct b][struct c][masks a][masks b][masks c] 174 */ 175 len = reply.num_masks * sizeof(XIEventMask); 176 177 for (i = 0, mi = mask_in; i < reply.num_masks; i++) 178 { 179 unsigned int mask_bytes = mi->mask_len * 4; 180 len += mask_bytes; 181 if (len > INT_MAX) 182 goto out; 183 if ((sizeof(xXIEventMask) + mask_bytes) > rbytes) 184 goto out; 185 rbytes -= (sizeof(xXIEventMask) + mask_bytes); 186 mi = (xXIEventMask*)((char*)mi + mask_bytes); 187 mi++; 188 } 189 190 mask_out = Xmalloc(len); 191 if (!mask_out) 192 goto out; 193 194 mi = mask_in; 195 mask = (unsigned char*)&mask_out[reply.num_masks]; 196 for (i = 0; i < reply.num_masks; i++) 197 { 198 mask_out[i].deviceid = mi->deviceid; 199 mask_out[i].mask_len = mi->mask_len * 4; 200 mask_out[i].mask = mask; 201 memcpy(mask_out[i].mask, &mi[1], mask_out[i].mask_len); 202 mask += mask_out[i].mask_len; 203 mi = (xXIEventMask*)((char*)mi + mi->mask_len * 4); 204 mi++; 205 } 206 207 *num_masks_return = reply.num_masks; 208 209out: 210 Xfree(mask_in); 211 212 UnlockDisplay(dpy); 213 214out_unlocked: 215 SyncHandle(); 216 217 return mask_out; 218} 219