First import
[xorg_rtime.git] / xorg-server-1.4 / damageext / damageext.c
blobe1724ecc7f7194c8f764888f05a1bdac4d3c5e23
1 /*
2 * Copyright © 2002 Keith Packard
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.
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.
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
27 #include "damageextint.h"
29 static unsigned char DamageReqCode;
30 static int DamageEventBase;
31 static int DamageErrorBase;
32 static int DamageClientPrivateIndex;
33 static RESTYPE DamageExtType;
34 static RESTYPE DamageExtWinType;
36 /* Version of the damage extension supported by the server, as opposed to the
37 * DAMAGE_* defines from damageproto for what version the proto header
38 * supports.
40 #define SERVER_DAMAGE_MAJOR 1
41 #define SERVER_DAMAGE_MINOR 1
43 #define prScreen screenInfo.screens[0]
45 static void
46 DamageExtNotify (DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes)
48 ClientPtr pClient = pDamageExt->pClient;
49 DamageClientPtr pDamageClient = GetDamageClient (pClient);
50 DrawablePtr pDrawable = pDamageExt->pDrawable;
51 xDamageNotifyEvent ev;
52 int i;
54 UpdateCurrentTimeIf ();
55 ev.type = DamageEventBase + XDamageNotify;
56 ev.level = pDamageExt->level;
57 ev.sequenceNumber = pClient->sequence;
58 ev.drawable = pDrawable->id;
59 ev.damage = pDamageExt->id;
60 ev.timestamp = currentTime.milliseconds;
61 ev.geometry.x = pDrawable->x;
62 ev.geometry.y = pDrawable->y;
63 ev.geometry.width = pDrawable->width;
64 ev.geometry.height = pDrawable->height;
65 if (pBoxes)
67 for (i = 0; i < nBoxes; i++)
69 ev.level = pDamageExt->level;
70 if (i < nBoxes - 1)
71 ev.level |= DamageNotifyMore;
72 ev.area.x = pBoxes[i].x1;
73 ev.area.y = pBoxes[i].y1;
74 ev.area.width = pBoxes[i].x2 - pBoxes[i].x1;
75 ev.area.height = pBoxes[i].y2 - pBoxes[i].y1;
76 if (!pClient->clientGone)
77 WriteEventsToClient (pClient, 1, (xEvent *) &ev);
80 else
82 ev.area.x = 0;
83 ev.area.y = 0;
84 ev.area.width = pDrawable->width;
85 ev.area.height = pDrawable->height;
86 if (!pClient->clientGone)
87 WriteEventsToClient (pClient, 1, (xEvent *) &ev);
89 /* Composite extension marks clients with manual Subwindows as critical */
90 if (pDamageClient->critical > 0)
92 SetCriticalOutputPending ();
93 #ifdef SMART_SCHEDULE
94 pClient->smart_priority = SMART_MAX_PRIORITY;
95 #endif
99 static void
100 DamageExtReport (DamagePtr pDamage, RegionPtr pRegion, void *closure)
102 DamageExtPtr pDamageExt = closure;
104 switch (pDamageExt->level) {
105 case DamageReportRawRegion:
106 case DamageReportDeltaRegion:
107 DamageExtNotify (pDamageExt, REGION_RECTS(pRegion), REGION_NUM_RECTS(pRegion));
108 break;
109 case DamageReportBoundingBox:
110 DamageExtNotify (pDamageExt, REGION_EXTENTS(prScreen, pRegion), 1);
111 break;
112 case DamageReportNonEmpty:
113 DamageExtNotify (pDamageExt, NullBox, 0);
114 break;
115 case DamageReportNone:
116 break;
120 static void
121 DamageExtDestroy (DamagePtr pDamage, void *closure)
123 DamageExtPtr pDamageExt = closure;
125 pDamageExt->pDamage = 0;
126 if (pDamageExt->id)
127 FreeResource (pDamageExt->id, RT_NONE);
130 void
131 DamageExtSetCritical (ClientPtr pClient, Bool critical)
133 DamageClientPtr pDamageClient = GetDamageClient (pClient);
135 if (pDamageClient)
136 pDamageClient->critical += critical ? 1 : -1;
139 static int
140 ProcDamageQueryVersion(ClientPtr client)
142 DamageClientPtr pDamageClient = GetDamageClient (client);
143 xDamageQueryVersionReply rep;
144 register int n;
145 REQUEST(xDamageQueryVersionReq);
147 REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
148 rep.type = X_Reply;
149 rep.length = 0;
150 rep.sequenceNumber = client->sequence;
151 if (stuff->majorVersion < SERVER_DAMAGE_MAJOR) {
152 rep.majorVersion = stuff->majorVersion;
153 rep.minorVersion = stuff->minorVersion;
154 } else {
155 rep.majorVersion = SERVER_DAMAGE_MAJOR;
156 if (stuff->majorVersion == SERVER_DAMAGE_MAJOR &&
157 stuff->minorVersion < SERVER_DAMAGE_MINOR)
158 rep.minorVersion = stuff->minorVersion;
159 else
160 rep.minorVersion = SERVER_DAMAGE_MINOR;
162 pDamageClient->major_version = rep.majorVersion;
163 pDamageClient->minor_version = rep.minorVersion;
164 if (client->swapped) {
165 swaps(&rep.sequenceNumber, n);
166 swapl(&rep.length, n);
167 swapl(&rep.majorVersion, n);
168 swapl(&rep.minorVersion, n);
170 WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep);
171 return(client->noClientException);
174 static int
175 ProcDamageCreate (ClientPtr client)
177 DrawablePtr pDrawable;
178 DamageExtPtr pDamageExt;
179 DamageReportLevel level;
180 RegionPtr pRegion;
181 int rc;
183 REQUEST(xDamageCreateReq);
185 REQUEST_SIZE_MATCH(xDamageCreateReq);
186 LEGAL_NEW_RESOURCE(stuff->damage, client);
187 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
188 DixReadAccess);
189 if (rc != Success)
190 return rc;
192 switch (stuff->level) {
193 case XDamageReportRawRectangles:
194 level = DamageReportRawRegion;
195 break;
196 case XDamageReportDeltaRectangles:
197 level = DamageReportDeltaRegion;
198 break;
199 case XDamageReportBoundingBox:
200 level = DamageReportBoundingBox;
201 break;
202 case XDamageReportNonEmpty:
203 level = DamageReportNonEmpty;
204 break;
205 default:
206 client->errorValue = stuff->level;
207 return BadValue;
210 pDamageExt = xalloc (sizeof (DamageExtRec));
211 if (!pDamageExt)
212 return BadAlloc;
213 pDamageExt->id = stuff->damage;
214 pDamageExt->pDrawable = pDrawable;
215 pDamageExt->level = level;
216 pDamageExt->pClient = client;
217 pDamageExt->pDamage = DamageCreate (DamageExtReport,
218 DamageExtDestroy,
219 level,
220 FALSE,
221 pDrawable->pScreen,
222 pDamageExt);
223 if (!pDamageExt->pDamage)
225 xfree (pDamageExt);
226 return BadAlloc;
228 if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt))
229 return BadAlloc;
231 DamageRegister (pDamageExt->pDrawable, pDamageExt->pDamage);
233 if (pDrawable->type == DRAWABLE_WINDOW)
235 pRegion = &((WindowPtr) pDrawable)->borderClip;
236 DamageDamageRegion (pDrawable, pRegion);
239 return (client->noClientException);
242 static int
243 ProcDamageDestroy (ClientPtr client)
245 REQUEST(xDamageDestroyReq);
246 DamageExtPtr pDamageExt;
248 REQUEST_SIZE_MATCH(xDamageDestroyReq);
249 VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
250 FreeResource (stuff->damage, RT_NONE);
251 return (client->noClientException);
254 static int
255 ProcDamageSubtract (ClientPtr client)
257 REQUEST(xDamageSubtractReq);
258 DamageExtPtr pDamageExt;
259 RegionPtr pRepair;
260 RegionPtr pParts;
262 REQUEST_SIZE_MATCH(xDamageSubtractReq);
263 VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, DixWriteAccess);
264 VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, DixWriteAccess);
265 VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, DixWriteAccess);
267 if (pDamageExt->level != DamageReportRawRegion)
269 DamagePtr pDamage = pDamageExt->pDamage;
270 if (pRepair)
272 if (pParts)
273 REGION_INTERSECT (prScreen, pParts, DamageRegion (pDamage), pRepair);
274 if (DamageSubtract (pDamage, pRepair))
275 DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt);
277 else
279 if (pParts)
280 REGION_COPY (prScreen, pParts, DamageRegion (pDamage));
281 DamageEmpty (pDamage);
284 return (client->noClientException);
287 static int
288 ProcDamageAdd (ClientPtr client)
290 REQUEST(xDamageAddReq);
291 DrawablePtr pDrawable;
292 RegionPtr pRegion;
293 int rc;
295 REQUEST_SIZE_MATCH(xDamageAddReq);
296 VERIFY_REGION(pRegion, stuff->region, client, DixWriteAccess);
297 rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
298 DixReadAccess);
299 if (rc != Success)
300 return rc;
302 /* The region is relative to the drawable origin, so translate it out to
303 * screen coordinates like damage expects.
305 REGION_TRANSLATE(pScreen, pRegion, pDrawable->x, pDrawable->y);
306 DamageDamageRegion(pDrawable, pRegion);
307 REGION_TRANSLATE(pScreen, pRegion, -pDrawable->x, -pDrawable->y);
309 return (client->noClientException);
312 /* Major version controls available requests */
313 static const int version_requests[] = {
314 X_DamageQueryVersion, /* before client sends QueryVersion */
315 X_DamageAdd, /* Version 1 */
318 #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
320 static int (*ProcDamageVector[XDamageNumberRequests])(ClientPtr) = {
321 /*************** Version 1 ******************/
322 ProcDamageQueryVersion,
323 ProcDamageCreate,
324 ProcDamageDestroy,
325 ProcDamageSubtract,
326 /*************** Version 1.1 ****************/
327 ProcDamageAdd,
331 static int
332 ProcDamageDispatch (ClientPtr client)
334 REQUEST(xDamageReq);
335 DamageClientPtr pDamageClient = GetDamageClient (client);
337 if (pDamageClient->major_version >= NUM_VERSION_REQUESTS)
338 return BadRequest;
339 if (stuff->damageReqType > version_requests[pDamageClient->major_version])
340 return BadRequest;
341 return (*ProcDamageVector[stuff->damageReqType]) (client);
344 static int
345 SProcDamageQueryVersion(ClientPtr client)
347 register int n;
348 REQUEST(xDamageQueryVersionReq);
350 swaps(&stuff->length, n);
351 REQUEST_SIZE_MATCH(xDamageQueryVersionReq);
352 swapl(&stuff->majorVersion, n);
353 swapl(&stuff->minorVersion, n);
354 return (*ProcDamageVector[stuff->damageReqType]) (client);
357 static int
358 SProcDamageCreate (ClientPtr client)
360 register int n;
361 REQUEST(xDamageCreateReq);
363 swaps (&stuff->length, n);
364 REQUEST_SIZE_MATCH(xDamageCreateReq);
365 swapl (&stuff->damage, n);
366 swapl (&stuff->drawable, n);
367 return (*ProcDamageVector[stuff->damageReqType]) (client);
370 static int
371 SProcDamageDestroy (ClientPtr client)
373 register int n;
374 REQUEST(xDamageDestroyReq);
376 swaps (&stuff->length, n);
377 REQUEST_SIZE_MATCH(xDamageDestroyReq);
378 swapl (&stuff->damage, n);
379 return (*ProcDamageVector[stuff->damageReqType]) (client);
382 static int
383 SProcDamageSubtract (ClientPtr client)
385 register int n;
386 REQUEST(xDamageSubtractReq);
388 swaps (&stuff->length, n);
389 REQUEST_SIZE_MATCH(xDamageSubtractReq);
390 swapl (&stuff->damage, n);
391 swapl (&stuff->repair, n);
392 swapl (&stuff->parts, n);
393 return (*ProcDamageVector[stuff->damageReqType]) (client);
396 static int
397 SProcDamageAdd (ClientPtr client)
399 register int n;
400 REQUEST(xDamageAddReq);
402 swaps (&stuff->length, n);
403 REQUEST_SIZE_MATCH(xDamageSubtractReq);
404 swapl (&stuff->drawable, n);
405 swapl (&stuff->region, n);
406 return (*ProcDamageVector[stuff->damageReqType]) (client);
409 static int (*SProcDamageVector[XDamageNumberRequests])(ClientPtr) = {
410 /*************** Version 1 ******************/
411 SProcDamageQueryVersion,
412 SProcDamageCreate,
413 SProcDamageDestroy,
414 SProcDamageSubtract,
415 /*************** Version 1.1 ****************/
416 SProcDamageAdd,
419 static int
420 SProcDamageDispatch (ClientPtr client)
422 REQUEST(xDamageReq);
423 if (stuff->damageReqType >= XDamageNumberRequests)
424 return BadRequest;
425 return (*SProcDamageVector[stuff->damageReqType]) (client);
428 static void
429 DamageClientCallback (CallbackListPtr *list,
430 pointer closure,
431 pointer data)
433 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
434 ClientPtr pClient = clientinfo->client;
435 DamageClientPtr pDamageClient = GetDamageClient (pClient);
437 pDamageClient->critical = 0;
438 pDamageClient->major_version = 0;
439 pDamageClient->minor_version = 0;
442 /*ARGSUSED*/
443 static void
444 DamageResetProc (ExtensionEntry *extEntry)
446 DeleteCallback (&ClientStateCallback, DamageClientCallback, 0);
449 static int
450 FreeDamageExt (pointer value, XID did)
452 DamageExtPtr pDamageExt = (DamageExtPtr) value;
455 * Get rid of the resource table entry hanging from the window id
457 pDamageExt->id = 0;
458 if (WindowDrawable(pDamageExt->pDrawable->type))
459 FreeResourceByType (pDamageExt->pDrawable->id, DamageExtWinType, TRUE);
460 if (pDamageExt->pDamage)
462 DamageUnregister (pDamageExt->pDrawable, pDamageExt->pDamage);
463 DamageDestroy (pDamageExt->pDamage);
465 xfree (pDamageExt);
466 return Success;
469 static int
470 FreeDamageExtWin (pointer value, XID wid)
472 DamageExtPtr pDamageExt = (DamageExtPtr) value;
474 if (pDamageExt->id)
475 FreeResource (pDamageExt->id, RT_NONE);
476 return Success;
479 static void
480 SDamageNotifyEvent (xDamageNotifyEvent *from,
481 xDamageNotifyEvent *to)
483 to->type = from->type;
484 cpswaps (from->sequenceNumber, to->sequenceNumber);
485 cpswapl (from->drawable, to->drawable);
486 cpswapl (from->damage, to->damage);
487 cpswaps (from->area.x, to->area.x);
488 cpswaps (from->area.y, to->area.y);
489 cpswaps (from->area.width, to->area.width);
490 cpswaps (from->area.height, to->area.height);
491 cpswaps (from->geometry.x, to->geometry.x);
492 cpswaps (from->geometry.y, to->geometry.y);
493 cpswaps (from->geometry.width, to->geometry.width);
494 cpswaps (from->geometry.height, to->geometry.height);
497 void
498 DamageExtensionInit(void)
500 ExtensionEntry *extEntry;
501 int s;
503 for (s = 0; s < screenInfo.numScreens; s++)
504 DamageSetup (screenInfo.screens[s]);
506 DamageExtType = CreateNewResourceType (FreeDamageExt);
507 if (!DamageExtType)
508 return;
510 DamageExtWinType = CreateNewResourceType (FreeDamageExtWin);
511 if (!DamageExtWinType)
512 return;
514 DamageClientPrivateIndex = AllocateClientPrivateIndex ();
515 if (!AllocateClientPrivate (DamageClientPrivateIndex,
516 sizeof (DamageClientRec)))
517 return;
518 if (!AddCallback (&ClientStateCallback, DamageClientCallback, 0))
519 return;
521 if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents,
522 XDamageNumberErrors,
523 ProcDamageDispatch, SProcDamageDispatch,
524 DamageResetProc, StandardMinorOpcode)) != 0)
526 DamageReqCode = (unsigned char)extEntry->base;
527 DamageEventBase = extEntry->eventBase;
528 DamageErrorBase = extEntry->errorBase;
529 EventSwapVector[DamageEventBase + XDamageNotify] =
530 (EventSwapPtr) SDamageNotifyEvent;