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 30 XDamageExtInfo XDamageExtensionInfo; 31 32 const char XDamageExtensionName[] = DAMAGE_NAME; 33 34 static int 35 XDamageCloseDisplay (Display *dpy, XExtCodes *codes); 36 37 static Bool 38 XDamageWireToEvent(Display *dpy, XEvent *event, xEvent *wire); 39 40 static Status 41 XDamageEventToWire(Display *dpy, XEvent *event, xEvent *wire); 42 43 /* 44 * XDamageExtAddDisplay - add a display to this extension. (Replaces 45 * XextAddDisplay) 46 */ 47 static XDamageExtDisplayInfo * 48 XDamageExtAddDisplay (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 */ 127 static int 128 XDamageExtRemoveDisplay (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 */ 167 static XDamageExtDisplayInfo * 168 XDamageExtFindDisplay (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 195 XDamageExtDisplayInfo * 196 XDamageFindDisplay (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 207 static int 208 XDamageCloseDisplay (Display *dpy, _X_UNUSED XExtCodes *codes) 209 { 210 return XDamageExtRemoveDisplay (&XDamageExtensionInfo, dpy); 211 } 212 213 static Bool 214 XDamageWireToEvent(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 250 static Status 251 XDamageEventToWire(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 283 Bool 284 XDamageQueryExtension (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 300 Status 301 XDamageQueryVersion (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 314 Damage 315 XDamageCreate (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 335 void 336 XDamageDestroy (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 351 void 352 XDamageSubtract (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 370 void 371 XDamageAdd (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