1/* 2 * 3 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27#include <X11/Xfuncproto.h> 28#include "Xfixesint.h" 29 30XFixesExtInfo XFixesExtensionInfo; 31char XFixesExtensionName[] = XFIXES_NAME; 32 33static int 34XFixesCloseDisplay (Display *dpy, XExtCodes *codes); 35 36static Bool 37XFixesWireToEvent(Display *dpy, XEvent *event, xEvent *wire); 38 39static Status 40XFixesEventToWire(Display *dpy, XEvent *event, xEvent *wire); 41 42/* 43 * XFixesExtAddDisplay - add a display to this extension. (Replaces 44 * XextAddDisplay) 45 */ 46static XFixesExtDisplayInfo * 47XFixesExtAddDisplay (XFixesExtInfo *extinfo, 48 Display *dpy, 49 char *ext_name) 50{ 51 XFixesExtDisplayInfo *info; 52 53 info = Xmalloc (sizeof (XFixesExtDisplayInfo)); 54 if (!info) return NULL; 55 info->display = dpy; 56 57 info->codes = XInitExtension (dpy, ext_name); 58 59 /* 60 * if the server has the extension, then we can initialize the 61 * appropriate function vectors 62 */ 63 if (info->codes) { 64 xXFixesQueryVersionReply rep; 65 xXFixesQueryVersionReq *req; 66 XESetCloseDisplay (dpy, info->codes->extension, 67 XFixesCloseDisplay); 68 for (int ev = info->codes->first_event; 69 ev < info->codes->first_event + XFixesNumberEvents; 70 ev++) 71 { 72 XESetWireToEvent (dpy, ev, XFixesWireToEvent); 73 XESetEventToWire (dpy, ev, XFixesEventToWire); 74 } 75 /* 76 * Get the version info 77 */ 78 LockDisplay (dpy); 79 GetReq (XFixesQueryVersion, req); 80 req->reqType = (CARD8) info->codes->major_opcode; 81 req->xfixesReqType = X_XFixesQueryVersion; 82 req->majorVersion = XFIXES_MAJOR; 83 req->minorVersion = XFIXES_MINOR; 84 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) 85 { 86 UnlockDisplay (dpy); 87 SyncHandle (); 88 Xfree(info); 89 return NULL; 90 } 91 info->major_version = (int) rep.majorVersion; 92 info->minor_version = (int) rep.minorVersion; 93 UnlockDisplay (dpy); 94 SyncHandle (); 95 } else { 96 /* The server doesn't have this extension. 97 * Use a private Xlib-internal extension to hang the close_display 98 * hook on so that the "cache" (extinfo->cur) is properly cleaned. 99 * (XBUG 7955) 100 */ 101 XExtCodes *codes = XAddExtension(dpy); 102 if (!codes) { 103 XFree(info); 104 return NULL; 105 } 106 XESetCloseDisplay (dpy, codes->extension, XFixesCloseDisplay); 107 } 108 109 /* 110 * now, chain it onto the list 111 */ 112 _XLockMutex(_Xglobal_lock); 113 info->next = extinfo->head; 114 extinfo->head = info; 115 extinfo->cur = info; 116 extinfo->ndisplays++; 117 _XUnlockMutex(_Xglobal_lock); 118 return info; 119} 120 121 122/* 123 * XFixesExtRemoveDisplay - remove the indicated display from the 124 * extension object. (Replaces XextRemoveDisplay.) 125 */ 126static int 127XFixesExtRemoveDisplay (XFixesExtInfo *extinfo, const Display *dpy) 128{ 129 XFixesExtDisplayInfo *info, *prev; 130 131 /* 132 * locate this display and its back link so that it can be removed 133 */ 134 _XLockMutex(_Xglobal_lock); 135 prev = NULL; 136 for (info = extinfo->head; info; info = info->next) { 137 if (info->display == dpy) break; 138 prev = info; 139 } 140 if (!info) { 141 _XUnlockMutex(_Xglobal_lock); 142 return 0; /* hmm, actually an error */ 143 } 144 145 /* 146 * remove the display from the list; handles going to zero 147 */ 148 if (prev) 149 prev->next = info->next; 150 else 151 extinfo->head = info->next; 152 153 extinfo->ndisplays--; 154 if (info == extinfo->cur) extinfo->cur = NULL; /* flush cache */ 155 _XUnlockMutex(_Xglobal_lock); 156 157 Xfree (info); 158 return 1; 159} 160 161/* 162 * XFixesExtFindDisplay - look for a display in this extension; keeps a 163 * cache of the most-recently used for efficiency. (Replaces 164 * XextFindDisplay.) 165 */ 166static XFixesExtDisplayInfo * 167XFixesExtFindDisplay (XFixesExtInfo *extinfo, 168 const Display *dpy) 169{ 170 XFixesExtDisplayInfo *info; 171 172 /* 173 * see if this was the most recently accessed display 174 */ 175 if ((info = extinfo->cur) && info->display == dpy) 176 return info; 177 178 /* 179 * look for display in list 180 */ 181 _XLockMutex(_Xglobal_lock); 182 for (info = extinfo->head; info; info = info->next) { 183 if (info->display == dpy) { 184 extinfo->cur = info; /* cache most recently used */ 185 _XUnlockMutex(_Xglobal_lock); 186 return info; 187 } 188 } 189 _XUnlockMutex(_Xglobal_lock); 190 191 return NULL; 192} 193 194XFixesExtDisplayInfo * 195XFixesFindDisplay (Display *dpy) 196{ 197 XFixesExtDisplayInfo *info; 198 199 info = XFixesExtFindDisplay (&XFixesExtensionInfo, dpy); 200 if (!info) 201 info = XFixesExtAddDisplay (&XFixesExtensionInfo, dpy, 202 XFixesExtensionName); 203 return info; 204} 205 206static int 207XFixesCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes) 208{ 209 return XFixesExtRemoveDisplay (&XFixesExtensionInfo, dpy); 210} 211 212static Bool 213XFixesWireToEvent(Display *dpy, XEvent *event, xEvent *wire) 214{ 215 XFixesExtDisplayInfo *info = XFixesFindDisplay(dpy); 216 217 XFixesCheckExtension(dpy, info, False); 218 219 switch ((wire->u.u.type & 0x7F) - info->codes->first_event) 220 { 221 case XFixesSelectionNotify: { 222 XFixesSelectionNotifyEvent *aevent; 223 xXFixesSelectionNotifyEvent *awire; 224 awire = (xXFixesSelectionNotifyEvent *) wire; 225 aevent = (XFixesSelectionNotifyEvent *) event; 226 aevent->type = awire->type & 0x7F; 227 aevent->subtype = awire->subtype; 228 aevent->serial = _XSetLastRequestRead(dpy, 229 (xGenericReply *) wire); 230 aevent->send_event = (awire->type & 0x80) != 0; 231 aevent->display = dpy; 232 aevent->window = awire->window; 233 aevent->owner = awire->owner; 234 aevent->selection = awire->selection; 235 aevent->timestamp = awire->timestamp; 236 aevent->selection_timestamp = awire->selectionTimestamp; 237 return True; 238 } 239 case XFixesCursorNotify: { 240 XFixesCursorNotifyEvent *aevent; 241 xXFixesCursorNotifyEvent *awire; 242 awire = (xXFixesCursorNotifyEvent *) wire; 243 aevent = (XFixesCursorNotifyEvent *) event; 244 aevent->type = awire->type & 0x7F; 245 aevent->subtype = awire->subtype; 246 aevent->serial = _XSetLastRequestRead(dpy, 247 (xGenericReply *) wire); 248 aevent->send_event = (awire->type & 0x80) != 0; 249 aevent->display = dpy; 250 aevent->window = awire->window; 251 aevent->cursor_serial = awire->cursorSerial; 252 aevent->timestamp = awire->timestamp; 253 aevent->cursor_name = awire->name; 254 return True; 255 } 256 } 257 return False; 258} 259 260static Status 261XFixesEventToWire(Display *dpy, XEvent *event, xEvent *wire) 262{ 263 XFixesExtDisplayInfo *info = XFixesFindDisplay(dpy); 264 265 XFixesCheckExtension(dpy, info, False); 266 267 switch ((event->type & 0x7F) - info->codes->first_event) 268 { 269 case XFixesSelectionNotify: { 270 XFixesSelectionNotifyEvent *aevent; 271 xXFixesSelectionNotifyEvent *awire; 272 awire = (xXFixesSelectionNotifyEvent *) wire; 273 aevent = (XFixesSelectionNotifyEvent *) event; 274 awire->type = (CARD8) (aevent->type | (aevent->send_event ? 0x80 : 0)); 275 awire->subtype = (CARD8) aevent->subtype; 276 awire->window = (CARD32) aevent->window; 277 awire->owner = (CARD32) aevent->owner; 278 awire->selection = (CARD32) aevent->selection; 279 awire->timestamp = (CARD32) aevent->timestamp; 280 awire->selectionTimestamp = (CARD32) aevent->selection_timestamp; 281 return True; 282 } 283 case XFixesCursorNotify: { 284 XFixesCursorNotifyEvent *aevent; 285 xXFixesCursorNotifyEvent *awire; 286 awire = (xXFixesCursorNotifyEvent *) wire; 287 aevent = (XFixesCursorNotifyEvent *) event; 288 awire->type = (CARD8) (aevent->type | (aevent->send_event ? 0x80 : 0)); 289 awire->subtype = (CARD8) aevent->subtype; 290 awire->window = (CARD32) aevent->window; 291 awire->timestamp = (CARD32) aevent->timestamp; 292 awire->cursorSerial = (CARD32) aevent->cursor_serial; 293 awire->name = (CARD32) aevent->cursor_name; 294 } 295 } 296 return False; 297} 298 299Bool 300XFixesQueryExtension (Display *dpy, 301 int *event_base_return, 302 int *error_base_return) 303{ 304 XFixesExtDisplayInfo *info = XFixesFindDisplay (dpy); 305 306 if (XFixesHasExtension(info)) 307 { 308 *event_base_return = info->codes->first_event; 309 *error_base_return = info->codes->first_error; 310 return True; 311 } 312 else 313 return False; 314} 315 316Status 317XFixesQueryVersion (Display *dpy, 318 int *major_version_return, 319 int *minor_version_return) 320{ 321 XFixesExtDisplayInfo *info = XFixesFindDisplay (dpy); 322 323 XFixesCheckExtension (dpy, info, 0); 324 325 *major_version_return = info->major_version; 326 *minor_version_return = info->minor_version; 327 return 1; 328} 329 330int 331XFixesVersion (void) 332{ 333 return XFIXES_VERSION; 334} 335