/* * Copyright © 2009 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /*********************************************************************** * XI2 property requests, list, change, delete and get properties. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "XIint.h" Atom* XIListProperties(Display* dpy, int deviceid, int *num_props_return) { xXIListPropertiesReq *req; xXIListPropertiesReply rep; XExtDisplayInfo *info = XInput_find_display(dpy); Atom *props = NULL; LockDisplay(dpy); *num_props_return = 0; if (_XiCheckExtInit(dpy, XInput_2, info) == -1) goto cleanup; GetReq(XIListProperties, req); req->reqType = info->codes->major_opcode; req->ReqType = X_XIListProperties; req->deviceid = deviceid; if (!_XReply(dpy, (xReply*)&rep, 0, xFalse)) goto cleanup; if (rep.num_properties) { props = (Atom*)Xmalloc(rep.num_properties * sizeof(Atom)); if (!props) { _XEatData(dpy, rep.num_properties << 2); goto cleanup; } _XRead32(dpy, props, rep.num_properties << 2); } *num_props_return = rep.num_properties; cleanup: UnlockDisplay(dpy); SyncHandle(); return props; } void XIDeleteProperty(Display* dpy, int deviceid, Atom property) { xXIDeletePropertyReq *req; XExtDisplayInfo *info = XInput_find_display(dpy); LockDisplay(dpy); if (_XiCheckExtInit(dpy, XInput_2, info) == -1) return; GetReq(XIDeleteProperty, req); req->reqType = info->codes->major_opcode; req->ReqType = X_XIDeleteProperty; req->deviceid = deviceid; req->property = property; UnlockDisplay(dpy); SyncHandle(); } void XIChangeProperty(Display* dpy, int deviceid, Atom property, Atom type, int format, int mode, unsigned char *data, int num_items) { xXIChangePropertyReq *req; int len; XExtDisplayInfo *info = XInput_find_display(dpy); LockDisplay(dpy); if (_XiCheckExtInit(dpy, XInput_2, info) == -1) return; GetReq(XIChangeProperty, req); req->reqType = info->codes->major_opcode; req->ReqType = X_XIChangeProperty; req->deviceid = deviceid; req->property = property; req->type = type; req->mode = mode; if (num_items < 0) { req->num_items = 0; req->format = 0; /* ask for garbage, get garbage */ } else { req->num_items = num_items; req->format = format; } switch (req->format) { case 8: len = (num_items + 3)/4; SetReqLen(req, len, len); len = num_items; break; case 16: len = (num_items + 1)/2; SetReqLen(req, len, len); len = num_items * 2; break; case 32: len = num_items; SetReqLen(req, len, len); len = num_items * 4; break; default: /* BadValue will be generated */ ; } /* we use data instead of Data32 and friends to avoid Xlib's braindead * 64 bit handling.*/ Data(dpy, (const char*)data, len); UnlockDisplay(dpy); SyncHandle(); } Status XIGetProperty(Display* dpy, int deviceid, Atom property, long offset, long length, Bool delete_property, Atom type, Atom *type_return, int *format_return, unsigned long *num_items_return,unsigned long *bytes_after_return, unsigned char **data) { xXIGetPropertyReq *req; xXIGetPropertyReply rep; long nbytes, rbytes; XExtDisplayInfo *info = XInput_find_display(dpy); LockDisplay(dpy); if (_XiCheckExtInit(dpy, XInput_2, info) == -1) return 1; GetReq(XIGetProperty, req); req->reqType = info->codes->major_opcode; req->ReqType = X_XIGetProperty; req->deviceid = deviceid; req->property = property; req->type = type; req->offset = offset; req->len = length; req->delete = delete_property; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { UnlockDisplay (dpy); SyncHandle (); return 1; } *data = NULL; if (rep.type != None) { /* * One extra byte is malloced than is needed to contain the property * data, but this last byte is null terminated and convenient for * returning string properties, so the client doesn't then have to * recopy the string to make it null terminated. */ switch (rep.format) { case 8: nbytes = rep.num_items; rbytes = rep.num_items + 1; if (rbytes > 0 && (*data = Xmalloc(rbytes))) _XReadPad (dpy, (char *) *data, nbytes); break; case 16: nbytes = rep.num_items << 1; rbytes = rep.num_items * sizeof(uint16_t) + 1; if (rbytes > 0 && (*data = Xmalloc(rbytes))) _XRead16Pad (dpy, (uint16_t*) *data, nbytes); break; case 32: nbytes = rep.num_items << 2; rbytes = rep.num_items * sizeof(uint32_t) + 1; if (rbytes > 0 && (*data = Xmalloc(rbytes))) _XRead32 (dpy, (uint32_t*) *data, nbytes); break; default: /* * This part of the code should never be reached. If it is, * the server sent back a property with an invalid format. */ nbytes = rep.length << 2; _XEatData(dpy, nbytes); UnlockDisplay(dpy); SyncHandle(); return(BadImplementation); } if (!(*data)) { _XEatData(dpy, nbytes); UnlockDisplay(dpy); SyncHandle(); return(BadAlloc); } (*data)[rbytes - 1] = '\0'; } *type_return = rep.type; *format_return = rep.format; *num_items_return = rep.num_items; *bytes_after_return = rep.bytes_after; UnlockDisplay (dpy); SyncHandle(); return Success; }