1/* 2 * Copyright © 2003 Keith Packard 3 * Copyright © 2007 Eric Anholt 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 "xdamageint.h" 28#include <X11/Xfuncproto.h> 29 30XDamageExtInfo XDamageExtensionInfo; 31 32const char XDamageExtensionName[] = DAMAGE_NAME; 33 34static int 35XDamageCloseDisplay (Display *dpy, XExtCodes *codes); 36 37static Bool 38XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire); 39 40static Status 41XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire); 42 43/* 44 * XDamageExtAddDisplay - add a display to this extension. (Replaces 45 * XextAddDisplay) 46 */ 47static XDamageExtDisplayInfo * 48XDamageExtAddDisplay (XDamageExtInfo *extinfo, 49 Display *dpy, 50 const char *ext_name) 51{ 52 XDamageExtDisplayInfo *info; 53 54 info = Xmalloc (sizeof (XDamageExtDisplayInfo)); 55 if (!info) return NULL; 56 info->display = dpy; 57 58 info->codes = XInitExtension (dpy, ext_name); 59 60 /* 61 * if the server has the extension, then we can initialize the 62 * appropriate function vectors 63 */ 64 if (info->codes) { 65 xDamageQueryVersionReply rep; 66 xDamageQueryVersionReq *req; 67 XESetCloseDisplay (dpy, info->codes->extension, 68 XDamageCloseDisplay); 69 for (int ev = info->codes->first_event; 70 ev < info->codes->first_event + XDamageNumberEvents; 71 ev++) 72 { 73 XESetWireToEvent (dpy, ev, XDamageWireToEvent); 74 XESetEventToWire (dpy, ev, XDamageEventToWire); 75 } 76 /* 77 * Get the version info 78 */ 79 LockDisplay (dpy); 80 GetReq (DamageQueryVersion, req); 81 req->reqType = (CARD8) info->codes->major_opcode; 82 req->damageReqType = X_DamageQueryVersion; 83 req->majorVersion = DAMAGE_MAJOR; 84 req->minorVersion = DAMAGE_MINOR; 85 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) 86 { 87 UnlockDisplay (dpy); 88 SyncHandle (); 89 Xfree(info); 90 return NULL; 91 } 92 info->major_version = rep.majorVersion; 93 info->minor_version = rep.minorVersion; 94 UnlockDisplay (dpy); 95 SyncHandle (); 96 } else { 97 /* The server doesn't have this extension. 98 * Use a private Xlib-internal extension to hang the close_display 99 * hook on so that the "cache" (extinfo->cur) is properly cleaned. 100 * (XBUG 7955) 101 */ 102 XExtCodes *codes = XAddExtension(dpy); 103 if (!codes) { 104 Xfree(info); 105 return NULL; 106 } 107 XESetCloseDisplay (dpy, codes->extension, XDamageCloseDisplay); 108 } 109 110 /* 111 * now, chain it onto the list 112 */ 113 _XLockMutex(_Xglobal_lock); 114 info->next = extinfo->head; 115 extinfo->head = info; 116 extinfo->cur = info; 117 extinfo->ndisplays++; 118 _XUnlockMutex(_Xglobal_lock); 119 return info; 120} 121 122 123/* 124 * XDamageExtRemoveDisplay - remove the indicated display from the 125 * extension object. (Replaces XextRemoveDisplay.) 126 */ 127static int 128XDamageExtRemoveDisplay (XDamageExtInfo *extinfo, const Display *dpy) 129{ 130 XDamageExtDisplayInfo *info, *prev; 131 132 /* 133 * locate this display and its back link so that it can be removed 134 */ 135 _XLockMutex(_Xglobal_lock); 136 prev = NULL; 137 for (info = extinfo->head; info; info = info->next) { 138 if (info->display == dpy) break; 139 prev = info; 140 } 141 if (!info) { 142 _XUnlockMutex(_Xglobal_lock); 143 return 0; /* hmm, actually an error */ 144 } 145 146 /* 147 * remove the display from the list; handles going to zero 148 */ 149 if (prev) 150 prev->next = info->next; 151 else 152 extinfo->head = info->next; 153 154 extinfo->ndisplays--; 155 if (info == extinfo->cur) extinfo->cur = NULL; /* flush cache */ 156 _XUnlockMutex(_Xglobal_lock); 157 158 Xfree (info); 159 return 1; 160} 161 162/* 163 * XDamageExtFindDisplay - look for a display in this extension; keeps a 164 * cache of the most-recently used for efficiency. (Replaces 165 * XextFindDisplay.) 166 */ 167static XDamageExtDisplayInfo * 168XDamageExtFindDisplay (XDamageExtInfo *extinfo, 169 const Display *dpy) 170{ 171 XDamageExtDisplayInfo *info; 172 173 /* 174 * see if this was the most recently accessed display 175 */ 176 if ((info = extinfo->cur) && info->display == dpy) 177 return info; 178 179 /* 180 * look for display in list 181 */ 182 _XLockMutex(_Xglobal_lock); 183 for (info = extinfo->head; info; info = info->next) { 184 if (info->display == dpy) { 185 extinfo->cur = info; /* cache most recently used */ 186 _XUnlockMutex(_Xglobal_lock); 187 return info; 188 } 189 } 190 _XUnlockMutex(_Xglobal_lock); 191 192 return NULL; 193} 194 195XDamageExtDisplayInfo * 196XDamageFindDisplay (Display *dpy) 197{ 198 XDamageExtDisplayInfo *info; 199 200 info = XDamageExtFindDisplay (&XDamageExtensionInfo, dpy); 201 if (!info) 202 info = XDamageExtAddDisplay (&XDamageExtensionInfo, dpy, 203 XDamageExtensionName); 204 return info; 205} 206 207static int 208XDamageCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes) 209{ 210 return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy); 211} 212 213static Bool 214XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire) 215{ 216 XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy); 217 218 XDamageCheckExtension(dpy, info, False); 219 220 switch ((wire->u.u.type & 0x7F) - info->codes->first_event) 221 { 222 case XDamageNotify: { 223 XDamageNotifyEvent *aevent = (XDamageNotifyEvent *) event; 224 xDamageNotifyEvent *awire = (xDamageNotifyEvent *) wire; 225 226 aevent->type = awire->type & 0x7F; 227 aevent->serial = _XSetLastRequestRead(dpy, 228 (xGenericReply *) wire); 229 aevent->send_event = (awire->type & 0x80) != 0; 230 aevent->display = dpy; 231 aevent->drawable = awire->drawable; 232 aevent->damage = awire->damage; 233 aevent->level = awire->level & ~DamageNotifyMore; 234 aevent->more = (awire->level & DamageNotifyMore) ? True : False; 235 aevent->timestamp = awire->timestamp; 236 aevent->area.x = awire->area.x; 237 aevent->area.y = awire->area.y; 238 aevent->area.width = awire->area.width; 239 aevent->area.height = awire->area.height; 240 aevent->geometry.x = awire->geometry.x; 241 aevent->geometry.y = awire->geometry.y; 242 aevent->geometry.width = awire->geometry.width; 243 aevent->geometry.height = awire->geometry.height; 244 return True; 245 } 246 } 247 return False; 248} 249 250static Status 251XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire) 252{ 253 XDamageExtDisplayInfo *info = XDamageFindDisplay(dpy); 254 255 XDamageCheckExtension(dpy, info, False); 256 257 switch ((event->type & 0x7F) - info->codes->first_event) 258 { 259 case XDamageNotify: { 260 XDamageNotifyEvent *aevent; 261 xDamageNotifyEvent *awire; 262 awire = (xDamageNotifyEvent *) wire; 263 aevent = (XDamageNotifyEvent *) event; 264 awire->type = (CARD8) aevent->type | (aevent->send_event ? 0x80 : 0); 265 awire->drawable = (CARD32) aevent->drawable; 266 awire->damage = (CARD32) aevent->damage; 267 awire->level = (CARD8) aevent->level | (aevent->more ? DamageNotifyMore : 0); 268 awire->timestamp = (CARD32) aevent->timestamp; 269 awire->area.x = aevent->area.x; 270 awire->area.y = aevent->area.y; 271 awire->area.width = aevent->area.width; 272 awire->area.height = aevent->area.height; 273 awire->geometry.x = aevent->geometry.x; 274 awire->geometry.y = aevent->geometry.y; 275 awire->geometry.width = aevent->geometry.width; 276 awire->geometry.height = aevent->geometry.height; 277 return True; 278 } 279 } 280 return False; 281} 282 283Bool 284XDamageQueryExtension (Display *dpy, 285 int *event_base_return, 286 int *error_base_return) 287{ 288 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy); 289 290 if (XDamageHasExtension(info)) 291 { 292 *event_base_return = info->codes->first_event; 293 *error_base_return = info->codes->first_error; 294 return True; 295 } 296 else 297 return False; 298} 299 300Status 301XDamageQueryVersion (Display *dpy, 302 int *major_version_return, 303 int *minor_version_return) 304{ 305 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy); 306 307 XDamageCheckExtension (dpy, info, 0); 308 309 *major_version_return = info->major_version; 310 *minor_version_return = info->minor_version; 311 return 1; 312} 313 314Damage 315XDamageCreate (Display *dpy, Drawable drawable, int level) 316{ 317 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy); 318 xDamageCreateReq *req; 319 Damage damage; 320 321 XDamageCheckExtension (dpy, info, 0); 322 LockDisplay (dpy); 323 GetReq (DamageCreate, req); 324 req->reqType = (CARD8) info->codes->major_opcode; 325 req->damageReqType = X_DamageCreate; 326 damage = XAllocID (dpy); 327 req->damage = (CARD32) damage; 328 req->drawable = (CARD32) drawable; 329 req->level = (CARD8) level; 330 UnlockDisplay (dpy); 331 SyncHandle (); 332 return damage; 333} 334 335void 336XDamageDestroy (Display *dpy, Damage damage) 337{ 338 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy); 339 xDamageDestroyReq *req; 340 341 XDamageSimpleCheckExtension (dpy, info); 342 LockDisplay (dpy); 343 GetReq (DamageDestroy, req); 344 req->reqType = (CARD8) info->codes->major_opcode; 345 req->damageReqType = X_DamageDestroy; 346 req->damage = (CARD32) damage; 347 UnlockDisplay (dpy); 348 SyncHandle (); 349} 350 351void 352XDamageSubtract (Display *dpy, Damage damage, 353 XserverRegion repair, XserverRegion parts) 354{ 355 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy); 356 xDamageSubtractReq *req; 357 358 XDamageSimpleCheckExtension (dpy, info); 359 LockDisplay (dpy); 360 GetReq (DamageSubtract, req); 361 req->reqType = (CARD8) info->codes->major_opcode; 362 req->damageReqType = X_DamageSubtract; 363 req->damage = (CARD32) damage; 364 req->repair = (CARD32) repair; 365 req->parts = (CARD32) parts; 366 UnlockDisplay (dpy); 367 SyncHandle (); 368} 369 370void 371XDamageAdd (Display *dpy, Drawable drawable, XserverRegion region) 372{ 373 XDamageExtDisplayInfo *info = XDamageFindDisplay (dpy); 374 xDamageAddReq *req; 375 376 XDamageSimpleCheckExtension (dpy, info); 377 LockDisplay (dpy); 378 GetReq (DamageAdd, req); 379 req->reqType = (CARD8) info->codes->major_opcode; 380 req->damageReqType = X_DamageAdd; 381 req->drawable = (CARD32) drawable; 382 req->region = (CARD32) region; 383 384 UnlockDisplay (dpy); 385 SyncHandle (); 386} 387