1/* 2 * Copyright © 2002 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Keith Packard not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Keith Packard makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_DIX_CONFIG_H 24#include <dix-config.h> 25#endif 26 27#include "damageextint.h" 28#include "protocol-versions.h" 29 30static unsigned char DamageReqCode; 31static int DamageEventBase; 32static RESTYPE DamageExtType; 33static RESTYPE DamageExtWinType; 34 35static DevPrivateKeyRec DamageClientPrivateKeyRec; 36#define DamageClientPrivateKey (&DamageClientPrivateKeyRec) 37 38static void 39DamageExtNotify (DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) 40{ 41 ClientPtr pClient = pDamageExt->pClient; 42 DamageClientPtr pDamageClient = GetDamageClient (pClient); 43 DrawablePtr pDrawable = pDamageExt->pDrawable; 44 xDamageNotifyEvent ev; 45 int i; 46 47 UpdateCurrentTimeIf (); 48 ev.type = DamageEventBase + XDamageNotify; 49 ev.level = pDamageExt->level; 50 ev.drawable = pDamageExt->drawable; 51 ev.damage = pDamageExt->id; 52 ev.timestamp = currentTime.milliseconds; 53 ev.geometry.x = pDrawable->x; 54 ev.geometry.y = pDrawable->y; 55 ev.geometry.width = pDrawable->width; 56 ev.geometry.height = pDrawable->height; 57 if (pBoxes) 58 { 59 for (i = 0; i < nBoxes; i++) 60 { 61 ev.level = pDamageExt->level; 62 if (i < nBoxes - 1) 63 ev.level |= DamageNotifyMore; 64 ev.area.x = pBoxes[i].x1; 65 ev.area.y = pBoxes[i].y1; 66 ev.area.width = pBoxes[i].x2 - pBoxes[i].x1; 67 ev.area.height = pBoxes[i].y2 - pBoxes[i].y1; 68 WriteEventsToClient (pClient, 1, (xEvent *) &ev); 69 } 70 } 71 else 72 { 73 ev.area.x = 0; 74 ev.area.y = 0; 75 ev.area.width = pDrawable->width; 76 ev.area.height = pDrawable->height; 77 WriteEventsToClient (pClient, 1, (xEvent *) &ev); 78 } 79 /* Composite extension marks clients with manual Subwindows as critical */ 80 if (pDamageClient->critical > 0) 81 { 82 SetCriticalOutputPending (); 83 pClient->smart_priority = SMART_MAX_PRIORITY; 84 } 85} 86 87static void 88DamageExtReport (DamagePtr pDamage, RegionPtr pRegion, void *closure) 89{ 90 DamageExtPtr pDamageExt = closure; 91 92 switch (pDamageExt->level) { 93 case DamageReportRawRegion: 94 case DamageReportDeltaRegion: 95 DamageExtNotify (pDamageExt, RegionRects(pRegion), RegionNumRects(pRegion)); 96 break; 97 case DamageReportBoundingBox: 98 DamageExtNotify (pDamageExt, RegionExtents(pRegion), 1); 99 break; 100 case DamageReportNonEmpty: 101 DamageExtNotify (pDamageExt, NullBox, 0); 102 break; 103 case DamageReportNone: 104 break; 105 } 106} 107 108static void 109DamageExtDestroy (DamagePtr pDamage, void *closure) 110{ 111 DamageExtPtr pDamageExt = closure; 112 113 pDamageExt->pDamage = 0; 114 if (pDamageExt->id) 115 FreeResource (pDamageExt->id, RT_NONE); 116} 117 118void 119DamageExtSetCritical (ClientPtr pClient, Bool critical) 120{ 121 DamageClientPtr pDamageClient = GetDamageClient (pClient); 122 123 if (pDamageClient) 124 pDamageClient->critical += critical ? 1 : -1; 125} 126 127static int 128ProcDamageQueryVersion(ClientPtr client) 129{ 130 DamageClientPtr pDamageClient = GetDamageClient (client); 131 xDamageQueryVersionReply rep; 132 register int n; 133 REQUEST(xDamageQueryVersionReq); 134 135 REQUEST_SIZE_MATCH(xDamageQueryVersionReq); 136 rep.type = X_Reply; 137 rep.length = 0; 138 rep.sequenceNumber = client->sequence; 139 if (stuff->majorVersion < SERVER_DAMAGE_MAJOR_VERSION) { 140 rep.majorVersion = stuff->majorVersion; 141 rep.minorVersion = stuff->minorVersion; 142 } else { 143 rep.majorVersion = SERVER_DAMAGE_MAJOR_VERSION; 144 if (stuff->majorVersion == SERVER_DAMAGE_MAJOR_VERSION && 145 stuff->minorVersion < SERVER_DAMAGE_MINOR_VERSION) 146 rep.minorVersion = stuff->minorVersion; 147 else 148 rep.minorVersion = SERVER_DAMAGE_MINOR_VERSION; 149 } 150 pDamageClient->major_version = rep.majorVersion; 151 pDamageClient->minor_version = rep.minorVersion; 152 if (client->swapped) { 153 swaps(&rep.sequenceNumber, n); 154 swapl(&rep.length, n); 155 swapl(&rep.majorVersion, n); 156 swapl(&rep.minorVersion, n); 157 } 158 WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep); 159 return Success; 160} 161 162static int 163ProcDamageCreate (ClientPtr client) 164{ 165 DrawablePtr pDrawable; 166 DamageExtPtr pDamageExt; 167 DamageReportLevel level; 168 RegionPtr pRegion; 169 int rc; 170 171 REQUEST(xDamageCreateReq); 172 173 REQUEST_SIZE_MATCH(xDamageCreateReq); 174 LEGAL_NEW_RESOURCE(stuff->damage, client); 175 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, 176 DixGetAttrAccess|DixReadAccess); 177 if (rc != Success) 178 return rc; 179 180 switch (stuff->level) { 181 case XDamageReportRawRectangles: 182 level = DamageReportRawRegion; 183 break; 184 case XDamageReportDeltaRectangles: 185 level = DamageReportDeltaRegion; 186 break; 187 case XDamageReportBoundingBox: 188 level = DamageReportBoundingBox; 189 break; 190 case XDamageReportNonEmpty: 191 level = DamageReportNonEmpty; 192 break; 193 default: 194 client->errorValue = stuff->level; 195 return BadValue; 196 } 197 198 pDamageExt = malloc(sizeof (DamageExtRec)); 199 if (!pDamageExt) 200 return BadAlloc; 201 pDamageExt->id = stuff->damage; 202 pDamageExt->drawable = stuff->drawable; 203 pDamageExt->pDrawable = pDrawable; 204 pDamageExt->level = level; 205 pDamageExt->pClient = client; 206 pDamageExt->pDamage = DamageCreate (DamageExtReport, 207 DamageExtDestroy, 208 level, 209 FALSE, 210 pDrawable->pScreen, 211 pDamageExt); 212 if (!pDamageExt->pDamage) 213 { 214 free(pDamageExt); 215 return BadAlloc; 216 } 217 if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt)) 218 return BadAlloc; 219 220 DamageSetReportAfterOp (pDamageExt->pDamage, TRUE); 221 DamageRegister (pDamageExt->pDrawable, pDamageExt->pDamage); 222 223 if (pDrawable->type == DRAWABLE_WINDOW) 224 { 225 pRegion = &((WindowPtr) pDrawable)->borderClip; 226 DamageDamageRegion(pDrawable, pRegion); 227 } 228 229 return Success; 230} 231 232static int 233ProcDamageDestroy (ClientPtr client) 234{ 235 REQUEST(xDamageDestroyReq); 236 DamageExtPtr pDamageExt; 237 238 REQUEST_SIZE_MATCH(xDamageDestroyReq); 239 VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess); 240 FreeResource (stuff->damage, RT_NONE); 241 return Success; 242} 243 244static int 245ProcDamageSubtract (ClientPtr client) 246{ 247 REQUEST(xDamageSubtractReq); 248 DamageExtPtr pDamageExt; 249 RegionPtr pRepair; 250 RegionPtr pParts; 251 252 REQUEST_SIZE_MATCH(xDamageSubtractReq); 253 VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess); 254 VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess); 255 VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess); 256 257 if (pDamageExt->level != DamageReportRawRegion) 258 { 259 DamagePtr pDamage = pDamageExt->pDamage; 260 if (pRepair) 261 { 262 if (pParts) 263 RegionIntersect(pParts, DamageRegion (pDamage), pRepair); 264 if (DamageSubtract (pDamage, pRepair)) 265 DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt); 266 } 267 else 268 { 269 if (pParts) 270 RegionCopy(pParts, DamageRegion (pDamage)); 271 DamageEmpty (pDamage); 272 } 273 } 274 return Success; 275} 276 277static int 278ProcDamageAdd (ClientPtr client) 279{ 280 REQUEST(xDamageAddReq); 281 DrawablePtr pDrawable; 282 RegionPtr pRegion; 283 int rc; 284 285 REQUEST_SIZE_MATCH(xDamageAddReq); 286 VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess); 287 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0, 288 DixWriteAccess); 289 if (rc != Success) 290 return rc; 291 292 /* The region is relative to the drawable origin, so translate it out to 293 * screen coordinates like damage expects. 294 */ 295 RegionTranslate(pRegion, pDrawable->x, pDrawable->y); 296 DamageDamageRegion(pDrawable, pRegion); 297 RegionTranslate(pRegion, -pDrawable->x, -pDrawable->y); 298 299 return Success; 300} 301 302/* Major version controls available requests */ 303static const int version_requests[] = { 304 X_DamageQueryVersion, /* before client sends QueryVersion */ 305 X_DamageAdd, /* Version 1 */ 306}; 307 308#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) 309 310static int (*ProcDamageVector[XDamageNumberRequests])(ClientPtr) = { 311/*************** Version 1 ******************/ 312 ProcDamageQueryVersion, 313 ProcDamageCreate, 314 ProcDamageDestroy, 315 ProcDamageSubtract, 316/*************** Version 1.1 ****************/ 317 ProcDamageAdd, 318}; 319 320 321static int 322ProcDamageDispatch (ClientPtr client) 323{ 324 REQUEST(xDamageReq); 325 DamageClientPtr pDamageClient = GetDamageClient (client); 326 327 if (pDamageClient->major_version >= NUM_VERSION_REQUESTS) 328 return BadRequest; 329 if (stuff->damageReqType > version_requests[pDamageClient->major_version]) 330 return BadRequest; 331 return (*ProcDamageVector[stuff->damageReqType]) (client); 332} 333 334static int 335SProcDamageQueryVersion(ClientPtr client) 336{ 337 register int n; 338 REQUEST(xDamageQueryVersionReq); 339 340 swaps(&stuff->length, n); 341 REQUEST_SIZE_MATCH(xDamageQueryVersionReq); 342 swapl(&stuff->majorVersion, n); 343 swapl(&stuff->minorVersion, n); 344 return (*ProcDamageVector[stuff->damageReqType]) (client); 345} 346 347static int 348SProcDamageCreate (ClientPtr client) 349{ 350 register int n; 351 REQUEST(xDamageCreateReq); 352 353 swaps (&stuff->length, n); 354 REQUEST_SIZE_MATCH(xDamageCreateReq); 355 swapl (&stuff->damage, n); 356 swapl (&stuff->drawable, n); 357 return (*ProcDamageVector[stuff->damageReqType]) (client); 358} 359 360static int 361SProcDamageDestroy (ClientPtr client) 362{ 363 register int n; 364 REQUEST(xDamageDestroyReq); 365 366 swaps (&stuff->length, n); 367 REQUEST_SIZE_MATCH(xDamageDestroyReq); 368 swapl (&stuff->damage, n); 369 return (*ProcDamageVector[stuff->damageReqType]) (client); 370} 371 372static int 373SProcDamageSubtract (ClientPtr client) 374{ 375 register int n; 376 REQUEST(xDamageSubtractReq); 377 378 swaps (&stuff->length, n); 379 REQUEST_SIZE_MATCH(xDamageSubtractReq); 380 swapl (&stuff->damage, n); 381 swapl (&stuff->repair, n); 382 swapl (&stuff->parts, n); 383 return (*ProcDamageVector[stuff->damageReqType]) (client); 384} 385 386static int 387SProcDamageAdd (ClientPtr client) 388{ 389 register int n; 390 REQUEST(xDamageAddReq); 391 392 swaps (&stuff->length, n); 393 REQUEST_SIZE_MATCH(xDamageSubtractReq); 394 swapl (&stuff->drawable, n); 395 swapl (&stuff->region, n); 396 return (*ProcDamageVector[stuff->damageReqType]) (client); 397} 398 399static int (*SProcDamageVector[XDamageNumberRequests])(ClientPtr) = { 400/*************** Version 1 ******************/ 401 SProcDamageQueryVersion, 402 SProcDamageCreate, 403 SProcDamageDestroy, 404 SProcDamageSubtract, 405/*************** Version 1.1 ****************/ 406 SProcDamageAdd, 407}; 408 409static int 410SProcDamageDispatch (ClientPtr client) 411{ 412 REQUEST(xDamageReq); 413 if (stuff->damageReqType >= XDamageNumberRequests) 414 return BadRequest; 415 return (*SProcDamageVector[stuff->damageReqType]) (client); 416} 417 418static void 419DamageClientCallback (CallbackListPtr *list, 420 pointer closure, 421 pointer data) 422{ 423 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; 424 ClientPtr pClient = clientinfo->client; 425 DamageClientPtr pDamageClient = GetDamageClient (pClient); 426 427 pDamageClient->critical = 0; 428 pDamageClient->major_version = 0; 429 pDamageClient->minor_version = 0; 430} 431 432/*ARGSUSED*/ 433static void 434DamageResetProc (ExtensionEntry *extEntry) 435{ 436 DeleteCallback (&ClientStateCallback, DamageClientCallback, 0); 437} 438 439static int 440FreeDamageExt (pointer value, XID did) 441{ 442 DamageExtPtr pDamageExt = (DamageExtPtr) value; 443 444 /* 445 * Get rid of the resource table entry hanging from the window id 446 */ 447 pDamageExt->id = 0; 448 if (WindowDrawable(pDamageExt->pDrawable->type)) 449 FreeResourceByType (pDamageExt->pDrawable->id, DamageExtWinType, TRUE); 450 if (pDamageExt->pDamage) 451 { 452 DamageUnregister (pDamageExt->pDrawable, pDamageExt->pDamage); 453 DamageDestroy (pDamageExt->pDamage); 454 } 455 free(pDamageExt); 456 return Success; 457} 458 459static int 460FreeDamageExtWin (pointer value, XID wid) 461{ 462 DamageExtPtr pDamageExt = (DamageExtPtr) value; 463 464 if (pDamageExt->id) 465 FreeResource (pDamageExt->id, RT_NONE); 466 return Success; 467} 468 469static void 470SDamageNotifyEvent (xDamageNotifyEvent *from, 471 xDamageNotifyEvent *to) 472{ 473 to->type = from->type; 474 cpswaps (from->sequenceNumber, to->sequenceNumber); 475 cpswapl (from->drawable, to->drawable); 476 cpswapl (from->damage, to->damage); 477 cpswaps (from->area.x, to->area.x); 478 cpswaps (from->area.y, to->area.y); 479 cpswaps (from->area.width, to->area.width); 480 cpswaps (from->area.height, to->area.height); 481 cpswaps (from->geometry.x, to->geometry.x); 482 cpswaps (from->geometry.y, to->geometry.y); 483 cpswaps (from->geometry.width, to->geometry.width); 484 cpswaps (from->geometry.height, to->geometry.height); 485} 486 487void 488DamageExtensionInit(void) 489{ 490 ExtensionEntry *extEntry; 491 int s; 492 493 for (s = 0; s < screenInfo.numScreens; s++) 494 DamageSetup (screenInfo.screens[s]); 495 496 DamageExtType = CreateNewResourceType (FreeDamageExt, "DamageExt"); 497 if (!DamageExtType) 498 return; 499 500 DamageExtWinType = CreateNewResourceType (FreeDamageExtWin, "DamageExtWin"); 501 if (!DamageExtWinType) 502 return; 503 504 if (!dixRegisterPrivateKey(&DamageClientPrivateKeyRec, PRIVATE_CLIENT, sizeof (DamageClientRec))) 505 return; 506 507 if (!AddCallback (&ClientStateCallback, DamageClientCallback, 0)) 508 return; 509 510 if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents, 511 XDamageNumberErrors, 512 ProcDamageDispatch, SProcDamageDispatch, 513 DamageResetProc, StandardMinorOpcode)) != 0) 514 { 515 DamageReqCode = (unsigned char)extEntry->base; 516 DamageEventBase = extEntry->eventBase; 517 EventSwapVector[DamageEventBase + XDamageNotify] = 518 (EventSwapPtr) SDamageNotifyEvent; 519 SetResourceTypeErrorValue(DamageExtType, extEntry->errorBase + BadDamage); 520 } 521} 522