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>
27 #include "damageextint.h"
28 #include "protocol-versions.h"
30 static unsigned char DamageReqCode
;
31 static int DamageEventBase
;
32 static RESTYPE DamageExtType
;
33 static RESTYPE DamageExtWinType
;
35 static DevPrivateKeyRec DamageClientPrivateKeyRec
;
37 #define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
40 DamageExtNotify(DamageExtPtr pDamageExt
, BoxPtr pBoxes
, int nBoxes
)
42 ClientPtr pClient
= pDamageExt
->pClient
;
43 DamageClientPtr pDamageClient
= GetDamageClient(pClient
);
44 DrawablePtr pDrawable
= pDamageExt
->pDrawable
;
45 xDamageNotifyEvent ev
;
48 UpdateCurrentTimeIf();
49 ev
.type
= DamageEventBase
+ XDamageNotify
;
50 ev
.level
= pDamageExt
->level
;
51 ev
.drawable
= pDamageExt
->drawable
;
52 ev
.damage
= pDamageExt
->id
;
53 ev
.timestamp
= currentTime
.milliseconds
;
54 ev
.geometry
.x
= pDrawable
->x
;
55 ev
.geometry
.y
= pDrawable
->y
;
56 ev
.geometry
.width
= pDrawable
->width
;
57 ev
.geometry
.height
= pDrawable
->height
;
59 for (i
= 0; i
< nBoxes
; i
++) {
60 ev
.level
= pDamageExt
->level
;
62 ev
.level
|= DamageNotifyMore
;
63 ev
.area
.x
= pBoxes
[i
].x1
;
64 ev
.area
.y
= pBoxes
[i
].y1
;
65 ev
.area
.width
= pBoxes
[i
].x2
- pBoxes
[i
].x1
;
66 ev
.area
.height
= pBoxes
[i
].y2
- pBoxes
[i
].y1
;
67 WriteEventsToClient(pClient
, 1, (xEvent
*) &ev
);
73 ev
.area
.width
= pDrawable
->width
;
74 ev
.area
.height
= pDrawable
->height
;
75 WriteEventsToClient(pClient
, 1, (xEvent
*) &ev
);
77 /* Composite extension marks clients with manual Subwindows as critical */
78 if (pDamageClient
->critical
> 0) {
79 SetCriticalOutputPending();
80 pClient
->smart_priority
= SMART_MAX_PRIORITY
;
85 DamageExtReport(DamagePtr pDamage
, RegionPtr pRegion
, void *closure
)
87 DamageExtPtr pDamageExt
= closure
;
89 switch (pDamageExt
->level
) {
90 case DamageReportRawRegion
:
91 case DamageReportDeltaRegion
:
92 DamageExtNotify(pDamageExt
, RegionRects(pRegion
),
93 RegionNumRects(pRegion
));
95 case DamageReportBoundingBox
:
96 DamageExtNotify(pDamageExt
, RegionExtents(pRegion
), 1);
98 case DamageReportNonEmpty
:
99 DamageExtNotify(pDamageExt
, NullBox
, 0);
101 case DamageReportNone
:
107 DamageExtDestroy(DamagePtr pDamage
, void *closure
)
109 DamageExtPtr pDamageExt
= closure
;
111 pDamageExt
->pDamage
= 0;
113 FreeResource(pDamageExt
->id
, RT_NONE
);
117 DamageExtSetCritical(ClientPtr pClient
, Bool critical
)
119 DamageClientPtr pDamageClient
= GetDamageClient(pClient
);
122 pDamageClient
->critical
+= critical
? 1 : -1;
126 ProcDamageQueryVersion(ClientPtr client
)
128 DamageClientPtr pDamageClient
= GetDamageClient(client
);
129 xDamageQueryVersionReply rep
;
131 REQUEST(xDamageQueryVersionReq
);
133 REQUEST_SIZE_MATCH(xDamageQueryVersionReq
);
136 rep
.sequenceNumber
= client
->sequence
;
137 if (stuff
->majorVersion
< SERVER_DAMAGE_MAJOR_VERSION
) {
138 rep
.majorVersion
= stuff
->majorVersion
;
139 rep
.minorVersion
= stuff
->minorVersion
;
142 rep
.majorVersion
= SERVER_DAMAGE_MAJOR_VERSION
;
143 if (stuff
->majorVersion
== SERVER_DAMAGE_MAJOR_VERSION
&&
144 stuff
->minorVersion
< SERVER_DAMAGE_MINOR_VERSION
)
145 rep
.minorVersion
= stuff
->minorVersion
;
147 rep
.minorVersion
= SERVER_DAMAGE_MINOR_VERSION
;
149 pDamageClient
->major_version
= rep
.majorVersion
;
150 pDamageClient
->minor_version
= rep
.minorVersion
;
151 if (client
->swapped
) {
152 swaps(&rep
.sequenceNumber
);
154 swapl(&rep
.majorVersion
);
155 swapl(&rep
.minorVersion
);
157 WriteToClient(client
, sizeof(xDamageQueryVersionReply
), (char *) &rep
);
162 ProcDamageCreate(ClientPtr client
)
164 DrawablePtr pDrawable
;
165 DamageExtPtr pDamageExt
;
166 DamageReportLevel level
;
170 REQUEST(xDamageCreateReq
);
172 REQUEST_SIZE_MATCH(xDamageCreateReq
);
173 LEGAL_NEW_RESOURCE(stuff
->damage
, client
);
174 rc
= dixLookupDrawable(&pDrawable
, stuff
->drawable
, client
, 0,
175 DixGetAttrAccess
| DixReadAccess
);
179 switch (stuff
->level
) {
180 case XDamageReportRawRectangles
:
181 level
= DamageReportRawRegion
;
183 case XDamageReportDeltaRectangles
:
184 level
= DamageReportDeltaRegion
;
186 case XDamageReportBoundingBox
:
187 level
= DamageReportBoundingBox
;
189 case XDamageReportNonEmpty
:
190 level
= DamageReportNonEmpty
;
193 client
->errorValue
= stuff
->level
;
197 pDamageExt
= malloc(sizeof(DamageExtRec
));
200 pDamageExt
->id
= stuff
->damage
;
201 pDamageExt
->drawable
= stuff
->drawable
;
202 pDamageExt
->pDrawable
= pDrawable
;
203 pDamageExt
->level
= level
;
204 pDamageExt
->pClient
= client
;
205 pDamageExt
->pDamage
= DamageCreate(DamageExtReport
,
208 FALSE
, pDrawable
->pScreen
, pDamageExt
);
209 if (!pDamageExt
->pDamage
) {
213 if (!AddResource(stuff
->damage
, DamageExtType
, (pointer
) pDamageExt
))
216 DamageSetReportAfterOp(pDamageExt
->pDamage
, TRUE
);
217 DamageRegister(pDamageExt
->pDrawable
, pDamageExt
->pDamage
);
219 if (pDrawable
->type
== DRAWABLE_WINDOW
) {
220 pRegion
= &((WindowPtr
) pDrawable
)->borderClip
;
221 DamageReportDamage(pDamageExt
->pDamage
, pRegion
);
228 ProcDamageDestroy(ClientPtr client
)
230 REQUEST(xDamageDestroyReq
);
231 DamageExtPtr pDamageExt
;
233 REQUEST_SIZE_MATCH(xDamageDestroyReq
);
234 VERIFY_DAMAGEEXT(pDamageExt
, stuff
->damage
, client
, DixWriteAccess
);
235 FreeResource(stuff
->damage
, RT_NONE
);
240 ProcDamageSubtract(ClientPtr client
)
242 REQUEST(xDamageSubtractReq
);
243 DamageExtPtr pDamageExt
;
247 REQUEST_SIZE_MATCH(xDamageSubtractReq
);
248 VERIFY_DAMAGEEXT(pDamageExt
, stuff
->damage
, client
, DixWriteAccess
);
249 VERIFY_REGION_OR_NONE(pRepair
, stuff
->repair
, client
, DixWriteAccess
);
250 VERIFY_REGION_OR_NONE(pParts
, stuff
->parts
, client
, DixWriteAccess
);
252 if (pDamageExt
->level
!= DamageReportRawRegion
) {
253 DamagePtr pDamage
= pDamageExt
->pDamage
;
257 RegionIntersect(pParts
, DamageRegion(pDamage
), pRepair
);
258 if (DamageSubtract(pDamage
, pRepair
))
259 DamageExtReport(pDamage
, DamageRegion(pDamage
),
260 (void *) pDamageExt
);
264 RegionCopy(pParts
, DamageRegion(pDamage
));
265 DamageEmpty(pDamage
);
272 ProcDamageAdd(ClientPtr client
)
274 REQUEST(xDamageAddReq
);
275 DrawablePtr pDrawable
;
279 REQUEST_SIZE_MATCH(xDamageAddReq
);
280 VERIFY_REGION(pRegion
, stuff
->region
, client
, DixWriteAccess
);
281 rc
= dixLookupDrawable(&pDrawable
, stuff
->drawable
, client
, 0,
286 /* The region is relative to the drawable origin, so translate it out to
287 * screen coordinates like damage expects.
289 RegionTranslate(pRegion
, pDrawable
->x
, pDrawable
->y
);
290 DamageDamageRegion(pDrawable
, pRegion
);
291 RegionTranslate(pRegion
, -pDrawable
->x
, -pDrawable
->y
);
296 /* Major version controls available requests */
297 static const int version_requests
[] = {
298 X_DamageQueryVersion
, /* before client sends QueryVersion */
299 X_DamageAdd
, /* Version 1 */
302 #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
304 static int (*ProcDamageVector
[XDamageNumberRequests
]) (ClientPtr
) = {
305 /*************** Version 1 ******************/
306 ProcDamageQueryVersion
,
307 ProcDamageCreate
, ProcDamageDestroy
, ProcDamageSubtract
,
308 /*************** Version 1.1 ****************/
312 ProcDamageDispatch(ClientPtr client
)
315 DamageClientPtr pDamageClient
= GetDamageClient(client
);
317 if (pDamageClient
->major_version
>= NUM_VERSION_REQUESTS
)
319 if (stuff
->damageReqType
> version_requests
[pDamageClient
->major_version
])
321 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
325 SProcDamageQueryVersion(ClientPtr client
)
327 REQUEST(xDamageQueryVersionReq
);
329 swaps(&stuff
->length
);
330 REQUEST_SIZE_MATCH(xDamageQueryVersionReq
);
331 swapl(&stuff
->majorVersion
);
332 swapl(&stuff
->minorVersion
);
333 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
337 SProcDamageCreate(ClientPtr client
)
339 REQUEST(xDamageCreateReq
);
341 swaps(&stuff
->length
);
342 REQUEST_SIZE_MATCH(xDamageCreateReq
);
343 swapl(&stuff
->damage
);
344 swapl(&stuff
->drawable
);
345 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
349 SProcDamageDestroy(ClientPtr client
)
351 REQUEST(xDamageDestroyReq
);
353 swaps(&stuff
->length
);
354 REQUEST_SIZE_MATCH(xDamageDestroyReq
);
355 swapl(&stuff
->damage
);
356 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
360 SProcDamageSubtract(ClientPtr client
)
362 REQUEST(xDamageSubtractReq
);
364 swaps(&stuff
->length
);
365 REQUEST_SIZE_MATCH(xDamageSubtractReq
);
366 swapl(&stuff
->damage
);
367 swapl(&stuff
->repair
);
368 swapl(&stuff
->parts
);
369 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
373 SProcDamageAdd(ClientPtr client
)
375 REQUEST(xDamageAddReq
);
377 swaps(&stuff
->length
);
378 REQUEST_SIZE_MATCH(xDamageSubtractReq
);
379 swapl(&stuff
->drawable
);
380 swapl(&stuff
->region
);
381 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
384 static int (*SProcDamageVector
[XDamageNumberRequests
]) (ClientPtr
) = {
385 /*************** Version 1 ******************/
386 SProcDamageQueryVersion
,
387 SProcDamageCreate
, SProcDamageDestroy
, SProcDamageSubtract
,
388 /*************** Version 1.1 ****************/
392 SProcDamageDispatch(ClientPtr client
)
395 if (stuff
->damageReqType
>= XDamageNumberRequests
)
397 return (*SProcDamageVector
[stuff
->damageReqType
]) (client
);
401 DamageClientCallback(CallbackListPtr
*list
, pointer closure
, pointer data
)
403 NewClientInfoRec
*clientinfo
= (NewClientInfoRec
*) data
;
404 ClientPtr pClient
= clientinfo
->client
;
405 DamageClientPtr pDamageClient
= GetDamageClient(pClient
);
407 pDamageClient
->critical
= 0;
408 pDamageClient
->major_version
= 0;
409 pDamageClient
->minor_version
= 0;
412 /*ARGSUSED*/ static void
413 DamageResetProc(ExtensionEntry
* extEntry
)
415 DeleteCallback(&ClientStateCallback
, DamageClientCallback
, 0);
419 FreeDamageExt(pointer value
, XID did
)
421 DamageExtPtr pDamageExt
= (DamageExtPtr
) value
;
424 * Get rid of the resource table entry hanging from the window id
427 if (WindowDrawable(pDamageExt
->pDrawable
->type
))
428 FreeResourceByType(pDamageExt
->pDrawable
->id
, DamageExtWinType
, TRUE
);
429 if (pDamageExt
->pDamage
) {
430 DamageUnregister(pDamageExt
->pDrawable
, pDamageExt
->pDamage
);
431 DamageDestroy(pDamageExt
->pDamage
);
438 FreeDamageExtWin(pointer value
, XID wid
)
440 DamageExtPtr pDamageExt
= (DamageExtPtr
) value
;
443 FreeResource(pDamageExt
->id
, RT_NONE
);
448 SDamageNotifyEvent(xDamageNotifyEvent
* from
, xDamageNotifyEvent
* to
)
450 to
->type
= from
->type
;
451 cpswaps(from
->sequenceNumber
, to
->sequenceNumber
);
452 cpswapl(from
->drawable
, to
->drawable
);
453 cpswapl(from
->damage
, to
->damage
);
454 cpswaps(from
->area
.x
, to
->area
.x
);
455 cpswaps(from
->area
.y
, to
->area
.y
);
456 cpswaps(from
->area
.width
, to
->area
.width
);
457 cpswaps(from
->area
.height
, to
->area
.height
);
458 cpswaps(from
->geometry
.x
, to
->geometry
.x
);
459 cpswaps(from
->geometry
.y
, to
->geometry
.y
);
460 cpswaps(from
->geometry
.width
, to
->geometry
.width
);
461 cpswaps(from
->geometry
.height
, to
->geometry
.height
);
465 DamageExtensionInit(void)
467 ExtensionEntry
*extEntry
;
470 for (s
= 0; s
< screenInfo
.numScreens
; s
++)
471 DamageSetup(screenInfo
.screens
[s
]);
473 DamageExtType
= CreateNewResourceType(FreeDamageExt
, "DamageExt");
477 DamageExtWinType
= CreateNewResourceType(FreeDamageExtWin
, "DamageExtWin");
478 if (!DamageExtWinType
)
481 if (!dixRegisterPrivateKey
482 (&DamageClientPrivateKeyRec
, PRIVATE_CLIENT
, sizeof(DamageClientRec
)))
485 if (!AddCallback(&ClientStateCallback
, DamageClientCallback
, 0))
488 if ((extEntry
= AddExtension(DAMAGE_NAME
, XDamageNumberEvents
,
490 ProcDamageDispatch
, SProcDamageDispatch
,
491 DamageResetProc
, StandardMinorOpcode
)) != 0) {
492 DamageReqCode
= (unsigned char) extEntry
->base
;
493 DamageEventBase
= extEntry
->eventBase
;
494 EventSwapVector
[DamageEventBase
+ XDamageNotify
] =
495 (EventSwapPtr
) SDamageNotifyEvent
;
496 SetResourceTypeErrorValue(DamageExtType
,
497 extEntry
->errorBase
+ BadDamage
);