XISelEv.c revision 10baa824
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; 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); 117 SyncHandle(); 118 return r; 119 120} 121 122XIEventMask* 123XIGetSelectedEvents(Display* dpy, Window win, int *num_masks_return) 124{ 125 unsigned int i, len = 0; 126 unsigned char *mask; 127 XIEventMask *mask_out = NULL; 128 xXIEventMask *mask_in = NULL, *mi; 129 xXIGetSelectedEventsReq *req; 130 xXIGetSelectedEventsReply reply; 131 XExtDisplayInfo *info = XInput_find_display(dpy); 132 size_t rbytes; 133 134 *num_masks_return = -1; 135 LockDisplay(dpy); 136 if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) 137 goto out; 138 139 GetReq(XIGetSelectedEvents, req); 140 141 req->reqType = info->codes->major_opcode; 142 req->ReqType = X_XIGetSelectedEvents; 143 req->win = win; 144 145 if (!_XReply(dpy, (xReply *) &reply, 0, xFalse)) 146 goto out; 147 148 if (reply.num_masks == 0) 149 { 150 *num_masks_return = 0; 151 goto out; 152 } 153 154 if (reply.length < (INT_MAX >> 2)) { 155 rbytes = (unsigned long) reply.length << 2; 156 mask_in = Xmalloc(rbytes); 157 } 158 if (!mask_in) { 159 _XEatDataWords(dpy, reply.length); 160 goto out; 161 } 162 163 _XRead(dpy, (char*)mask_in, rbytes); 164 165 /* 166 * This function takes interleaved xXIEventMask structs & masks off 167 * the wire, such as this 3 mask reply: 168 * [struct a][masks a][struct b][masks b][struct c][masks c] 169 * And generates a memory buffer to be returned to callers in which 170 * they are not interleaved, so that callers can treat the returned 171 * pointer as a simple array of XIEventMask structs, such as: 172 * [struct a][struct b][struct c][masks a][masks b][masks c] 173 */ 174 len = reply.num_masks * sizeof(XIEventMask); 175 176 for (i = 0, mi = mask_in; i < reply.num_masks; i++) 177 { 178 unsigned int mask_bytes = mi->mask_len * 4; 179 len += mask_bytes; 180 if (len > INT_MAX) 181 goto out; 182 if ((sizeof(xXIEventMask) + mask_bytes) > rbytes) 183 goto out; 184 rbytes -= (sizeof(xXIEventMask) + mask_bytes); 185 mi = (xXIEventMask*)((char*)mi + mask_bytes); 186 mi++; 187 } 188 189 mask_out = Xmalloc(len); 190 if (!mask_out) 191 goto out; 192 193 mi = mask_in; 194 mask = (unsigned char*)&mask_out[reply.num_masks]; 195 for (i = 0; i < reply.num_masks; i++) 196 { 197 mask_out[i].deviceid = mi->deviceid; 198 mask_out[i].mask_len = mi->mask_len * 4; 199 mask_out[i].mask = mask; 200 memcpy(mask_out[i].mask, &mi[1], mask_out[i].mask_len); 201 mask += mask_out[i].mask_len; 202 mi = (xXIEventMask*)((char*)mi + mi->mask_len * 4); 203 mi++; 204 } 205 206 *num_masks_return = reply.num_masks; 207 208out: 209 Xfree(mask_in); 210 211 UnlockDisplay(dpy); 212 SyncHandle(); 213 214 return mask_out; 215} 216