2 * Copyright © 2002 Keith Packard
3 * Copyright 2013 Red Hat, Inc.
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.
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.
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
28 #include "damageextint.h"
29 #include "damagestr.h"
30 #include "protocol-versions.h"
34 #include "panoramiX.h"
35 #include "panoramiXsrv.h"
39 DamagePtr damage
[MAXSCREENS
];
42 static RESTYPE XRT_DAMAGE
;
43 static int (*PanoramiXSaveDamageCreate
) (ClientPtr
);
47 static unsigned char DamageReqCode
;
48 static int DamageEventBase
;
49 static RESTYPE DamageExtType
;
51 static DevPrivateKeyRec DamageClientPrivateKeyRec
;
53 #define DamageClientPrivateKey (&DamageClientPrivateKeyRec)
56 DamageNoteCritical(ClientPtr pClient
)
58 DamageClientPtr pDamageClient
= GetDamageClient(pClient
);
60 /* Composite extension marks clients with manual Subwindows as critical */
61 if (pDamageClient
->critical
> 0) {
62 SetCriticalOutputPending();
63 pClient
->smart_priority
= SMART_MAX_PRIORITY
;
68 damageGetGeometry(DrawablePtr draw
, int *x
, int *y
, int *w
, int *h
)
71 if (!noPanoramiXExtension
&& draw
->type
== DRAWABLE_WINDOW
) {
72 WindowPtr win
= (WindowPtr
)draw
;
77 *w
= screenInfo
.width
;
78 *h
= screenInfo
.height
;
91 DamageExtNotify(DamageExtPtr pDamageExt
, BoxPtr pBoxes
, int nBoxes
)
93 ClientPtr pClient
= pDamageExt
->pClient
;
94 DrawablePtr pDrawable
= pDamageExt
->pDrawable
;
95 xDamageNotifyEvent ev
;
98 damageGetGeometry(pDrawable
, &x
, &y
, &w
, &h
);
100 UpdateCurrentTimeIf();
101 ev
= (xDamageNotifyEvent
) {
102 .type
= DamageEventBase
+ XDamageNotify
,
103 .level
= pDamageExt
->level
,
104 .drawable
= pDamageExt
->drawable
,
105 .damage
= pDamageExt
->id
,
106 .timestamp
= currentTime
.milliseconds
,
113 for (i
= 0; i
< nBoxes
; i
++) {
114 ev
.level
= pDamageExt
->level
;
116 ev
.level
|= DamageNotifyMore
;
117 ev
.area
.x
= pBoxes
[i
].x1
;
118 ev
.area
.y
= pBoxes
[i
].y1
;
119 ev
.area
.width
= pBoxes
[i
].x2
- pBoxes
[i
].x1
;
120 ev
.area
.height
= pBoxes
[i
].y2
- pBoxes
[i
].y1
;
121 WriteEventsToClient(pClient
, 1, (xEvent
*) &ev
);
129 WriteEventsToClient(pClient
, 1, (xEvent
*) &ev
);
132 DamageNoteCritical(pClient
);
136 DamageExtReport(DamagePtr pDamage
, RegionPtr pRegion
, void *closure
)
138 DamageExtPtr pDamageExt
= closure
;
140 switch (pDamageExt
->level
) {
141 case DamageReportRawRegion
:
142 case DamageReportDeltaRegion
:
143 DamageExtNotify(pDamageExt
, RegionRects(pRegion
),
144 RegionNumRects(pRegion
));
146 case DamageReportBoundingBox
:
147 DamageExtNotify(pDamageExt
, RegionExtents(pRegion
), 1);
149 case DamageReportNonEmpty
:
150 DamageExtNotify(pDamageExt
, NullBox
, 0);
152 case DamageReportNone
:
158 DamageExtDestroy(DamagePtr pDamage
, void *closure
)
160 DamageExtPtr pDamageExt
= closure
;
162 pDamageExt
->pDamage
= 0;
164 FreeResource(pDamageExt
->id
, RT_NONE
);
168 DamageExtSetCritical(ClientPtr pClient
, Bool critical
)
170 DamageClientPtr pDamageClient
= GetDamageClient(pClient
);
173 pDamageClient
->critical
+= critical
? 1 : -1;
177 ProcDamageQueryVersion(ClientPtr client
)
179 DamageClientPtr pDamageClient
= GetDamageClient(client
);
180 xDamageQueryVersionReply rep
= {
182 .sequenceNumber
= client
->sequence
,
186 REQUEST(xDamageQueryVersionReq
);
188 REQUEST_SIZE_MATCH(xDamageQueryVersionReq
);
190 if (stuff
->majorVersion
< SERVER_DAMAGE_MAJOR_VERSION
) {
191 rep
.majorVersion
= stuff
->majorVersion
;
192 rep
.minorVersion
= stuff
->minorVersion
;
195 rep
.majorVersion
= SERVER_DAMAGE_MAJOR_VERSION
;
196 if (stuff
->majorVersion
== SERVER_DAMAGE_MAJOR_VERSION
&&
197 stuff
->minorVersion
< SERVER_DAMAGE_MINOR_VERSION
)
198 rep
.minorVersion
= stuff
->minorVersion
;
200 rep
.minorVersion
= SERVER_DAMAGE_MINOR_VERSION
;
202 pDamageClient
->major_version
= rep
.majorVersion
;
203 pDamageClient
->minor_version
= rep
.minorVersion
;
204 if (client
->swapped
) {
205 swaps(&rep
.sequenceNumber
);
207 swapl(&rep
.majorVersion
);
208 swapl(&rep
.minorVersion
);
210 WriteToClient(client
, sizeof(xDamageQueryVersionReply
), &rep
);
215 DamageExtRegister(DrawablePtr pDrawable
, DamagePtr pDamage
, Bool report
)
217 DamageSetReportAfterOp(pDamage
, TRUE
);
218 DamageRegister(pDrawable
, pDamage
);
221 RegionPtr pRegion
= &((WindowPtr
) pDrawable
)->borderClip
;
222 RegionTranslate(pRegion
, -pDrawable
->x
, -pDrawable
->y
);
223 DamageReportDamage(pDamage
, pRegion
);
224 RegionTranslate(pRegion
, pDrawable
->x
, pDrawable
->y
);
229 DamageExtCreate(DrawablePtr pDrawable
, DamageReportLevel level
,
230 ClientPtr client
, XID id
, XID drawable
)
232 DamageExtPtr pDamageExt
= malloc(sizeof(DamageExtRec
));
237 pDamageExt
->drawable
= drawable
;
238 pDamageExt
->pDrawable
= pDrawable
;
239 pDamageExt
->level
= level
;
240 pDamageExt
->pClient
= client
;
241 pDamageExt
->pDamage
= DamageCreate(DamageExtReport
, DamageExtDestroy
, level
,
242 FALSE
, pDrawable
->pScreen
, pDamageExt
);
243 if (!pDamageExt
->pDamage
) {
248 if (!AddResource(id
, DamageExtType
, (pointer
) pDamageExt
))
251 DamageExtRegister(pDrawable
, pDamageExt
->pDamage
,
252 pDrawable
->type
== DRAWABLE_WINDOW
);
258 doDamageCreate(ClientPtr client
, int *rc
)
260 DrawablePtr pDrawable
;
261 DamageExtPtr pDamageExt
;
262 DamageReportLevel level
;
264 REQUEST(xDamageCreateReq
);
266 *rc
= dixLookupDrawable(&pDrawable
, stuff
->drawable
, client
, 0,
267 DixGetAttrAccess
| DixReadAccess
);
271 switch (stuff
->level
) {
272 case XDamageReportRawRectangles
:
273 level
= DamageReportRawRegion
;
275 case XDamageReportDeltaRectangles
:
276 level
= DamageReportDeltaRegion
;
278 case XDamageReportBoundingBox
:
279 level
= DamageReportBoundingBox
;
281 case XDamageReportNonEmpty
:
282 level
= DamageReportNonEmpty
;
285 client
->errorValue
= stuff
->level
;
290 pDamageExt
= DamageExtCreate(pDrawable
, level
, client
, stuff
->damage
,
299 ProcDamageCreate(ClientPtr client
)
302 REQUEST(xDamageCreateReq
);
303 REQUEST_SIZE_MATCH(xDamageCreateReq
);
304 LEGAL_NEW_RESOURCE(stuff
->damage
, client
);
305 doDamageCreate(client
, &rc
);
310 ProcDamageDestroy(ClientPtr client
)
312 REQUEST(xDamageDestroyReq
);
313 DamageExtPtr pDamageExt
;
315 REQUEST_SIZE_MATCH(xDamageDestroyReq
);
316 VERIFY_DAMAGEEXT(pDamageExt
, stuff
->damage
, client
, DixWriteAccess
);
317 FreeResource(stuff
->damage
, RT_NONE
);
323 DamageExtSubtractWindowClip(DamageExtPtr pDamageExt
)
325 WindowPtr win
= (WindowPtr
)pDamageExt
->pDrawable
;
326 PanoramiXRes
*res
= NULL
;
331 return &PanoramiXScreenRegion
;
333 dixLookupResourceByType((void **)&res
, win
->drawable
.id
, XRT_WINDOW
,
334 serverClient
, DixReadAccess
);
338 ret
= RegionCreate(NULL
, 0);
342 FOR_NSCREENS_FORWARD(i
) {
344 if (Success
!= dixLookupWindow(&win
, res
->info
[i
].id
, serverClient
,
348 screen
= win
->drawable
.pScreen
;
350 RegionTranslate(ret
, -screen
->x
, -screen
->y
);
351 if (!RegionUnion(ret
, ret
, &win
->borderClip
))
353 RegionTranslate(ret
, screen
->x
, screen
->y
);
364 DamageExtFreeWindowClip(RegionPtr reg
)
366 if (reg
!= &PanoramiXScreenRegion
)
372 * DamageSubtract intersects with borderClip, so we must reconstruct the
373 * protocol's perspective of same...
376 DamageExtSubtract(DamageExtPtr pDamageExt
, const RegionPtr pRegion
)
378 DamagePtr pDamage
= pDamageExt
->pDamage
;
381 if (!noPanoramiXExtension
) {
382 RegionPtr damage
= DamageRegion(pDamage
);
383 RegionSubtract(damage
, damage
, pRegion
);
385 if (pDamageExt
->pDrawable
->type
== DRAWABLE_WINDOW
) {
386 DrawablePtr pDraw
= pDamageExt
->pDrawable
;
387 RegionPtr clip
= DamageExtSubtractWindowClip(pDamageExt
);
389 RegionTranslate(clip
, -pDraw
->x
, -pDraw
->y
);
390 RegionIntersect(damage
, damage
, clip
);
391 RegionTranslate(clip
, pDraw
->x
, pDraw
->y
);
392 DamageExtFreeWindowClip(clip
);
396 return RegionNotEmpty(damage
);
400 return DamageSubtract(pDamage
, pRegion
);
404 ProcDamageSubtract(ClientPtr client
)
406 REQUEST(xDamageSubtractReq
);
407 DamageExtPtr pDamageExt
;
411 REQUEST_SIZE_MATCH(xDamageSubtractReq
);
412 VERIFY_DAMAGEEXT(pDamageExt
, stuff
->damage
, client
, DixWriteAccess
);
413 VERIFY_REGION_OR_NONE(pRepair
, stuff
->repair
, client
, DixWriteAccess
);
414 VERIFY_REGION_OR_NONE(pParts
, stuff
->parts
, client
, DixWriteAccess
);
416 if (pDamageExt
->level
!= DamageReportRawRegion
) {
417 DamagePtr pDamage
= pDamageExt
->pDamage
;
421 RegionIntersect(pParts
, DamageRegion(pDamage
), pRepair
);
422 if (DamageExtSubtract(pDamageExt
, pRepair
))
423 DamageExtReport(pDamage
, DamageRegion(pDamage
),
424 (void *) pDamageExt
);
428 RegionCopy(pParts
, DamageRegion(pDamage
));
429 DamageEmpty(pDamage
);
437 ProcDamageAdd(ClientPtr client
)
439 REQUEST(xDamageAddReq
);
440 DrawablePtr pDrawable
;
444 REQUEST_SIZE_MATCH(xDamageAddReq
);
445 VERIFY_REGION(pRegion
, stuff
->region
, client
, DixWriteAccess
);
446 rc
= dixLookupDrawable(&pDrawable
, stuff
->drawable
, client
, 0,
451 /* The region is relative to the drawable origin, so translate it out to
452 * screen coordinates like damage expects.
454 RegionTranslate(pRegion
, pDrawable
->x
, pDrawable
->y
);
455 DamageDamageRegion(pDrawable
, pRegion
);
456 RegionTranslate(pRegion
, -pDrawable
->x
, -pDrawable
->y
);
461 /* Major version controls available requests */
462 static const int version_requests
[] = {
463 X_DamageQueryVersion
, /* before client sends QueryVersion */
464 X_DamageAdd
, /* Version 1 */
467 #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0]))
469 static int (*ProcDamageVector
[XDamageNumberRequests
]) (ClientPtr
) = {
470 /*************** Version 1 ******************/
471 ProcDamageQueryVersion
,
475 /*************** Version 1.1 ****************/
480 ProcDamageDispatch(ClientPtr client
)
483 DamageClientPtr pDamageClient
= GetDamageClient(client
);
485 if (pDamageClient
->major_version
>= NUM_VERSION_REQUESTS
)
487 if (stuff
->damageReqType
> version_requests
[pDamageClient
->major_version
])
489 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
493 SProcDamageQueryVersion(ClientPtr client
)
495 REQUEST(xDamageQueryVersionReq
);
497 swaps(&stuff
->length
);
498 REQUEST_SIZE_MATCH(xDamageQueryVersionReq
);
499 swapl(&stuff
->majorVersion
);
500 swapl(&stuff
->minorVersion
);
501 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
505 SProcDamageCreate(ClientPtr client
)
507 REQUEST(xDamageCreateReq
);
509 swaps(&stuff
->length
);
510 REQUEST_SIZE_MATCH(xDamageCreateReq
);
511 swapl(&stuff
->damage
);
512 swapl(&stuff
->drawable
);
513 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
517 SProcDamageDestroy(ClientPtr client
)
519 REQUEST(xDamageDestroyReq
);
521 swaps(&stuff
->length
);
522 REQUEST_SIZE_MATCH(xDamageDestroyReq
);
523 swapl(&stuff
->damage
);
524 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
528 SProcDamageSubtract(ClientPtr client
)
530 REQUEST(xDamageSubtractReq
);
532 swaps(&stuff
->length
);
533 REQUEST_SIZE_MATCH(xDamageSubtractReq
);
534 swapl(&stuff
->damage
);
535 swapl(&stuff
->repair
);
536 swapl(&stuff
->parts
);
537 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
541 SProcDamageAdd(ClientPtr client
)
543 REQUEST(xDamageAddReq
);
545 swaps(&stuff
->length
);
546 REQUEST_SIZE_MATCH(xDamageSubtractReq
);
547 swapl(&stuff
->drawable
);
548 swapl(&stuff
->region
);
549 return (*ProcDamageVector
[stuff
->damageReqType
]) (client
);
552 static int (*SProcDamageVector
[XDamageNumberRequests
]) (ClientPtr
) = {
553 /*************** Version 1 ******************/
554 SProcDamageQueryVersion
,
558 /*************** Version 1.1 ****************/
563 SProcDamageDispatch(ClientPtr client
)
566 if (stuff
->damageReqType
>= XDamageNumberRequests
)
568 return (*SProcDamageVector
[stuff
->damageReqType
]) (client
);
572 DamageClientCallback(CallbackListPtr
*list
, pointer closure
, pointer data
)
574 NewClientInfoRec
*clientinfo
= (NewClientInfoRec
*) data
;
575 ClientPtr pClient
= clientinfo
->client
;
576 DamageClientPtr pDamageClient
= GetDamageClient(pClient
);
578 pDamageClient
->critical
= 0;
579 pDamageClient
->major_version
= 0;
580 pDamageClient
->minor_version
= 0;
583 /*ARGSUSED*/ static void
584 DamageResetProc(ExtensionEntry
* extEntry
)
586 DeleteCallback(&ClientStateCallback
, DamageClientCallback
, 0);
590 FreeDamageExt(pointer value
, XID did
)
592 DamageExtPtr pDamageExt
= (DamageExtPtr
) value
;
595 * Get rid of the resource table entry hanging from the window id
598 if (pDamageExt
->pDamage
) {
599 DamageDestroy(pDamageExt
->pDamage
);
606 SDamageNotifyEvent(xDamageNotifyEvent
* from
, xDamageNotifyEvent
* to
)
608 to
->type
= from
->type
;
609 cpswaps(from
->sequenceNumber
, to
->sequenceNumber
);
610 cpswapl(from
->drawable
, to
->drawable
);
611 cpswapl(from
->damage
, to
->damage
);
612 cpswaps(from
->area
.x
, to
->area
.x
);
613 cpswaps(from
->area
.y
, to
->area
.y
);
614 cpswaps(from
->area
.width
, to
->area
.width
);
615 cpswaps(from
->area
.height
, to
->area
.height
);
616 cpswaps(from
->geometry
.x
, to
->geometry
.x
);
617 cpswaps(from
->geometry
.y
, to
->geometry
.y
);
618 cpswaps(from
->geometry
.width
, to
->geometry
.width
);
619 cpswaps(from
->geometry
.height
, to
->geometry
.height
);
625 PanoramiXDamageReport(DamagePtr pDamage
, RegionPtr pRegion
, void *closure
)
627 PanoramiXDamageRes
*res
= closure
;
628 DamageExtPtr pDamageExt
= res
->ext
;
629 WindowPtr pWin
= (WindowPtr
)pDamage
->pDrawable
;
630 ScreenPtr pScreen
= pDamage
->pScreen
;
632 /* happens on unmap? sigh xinerama */
633 if (RegionNil(pRegion
))
636 /* translate root windows if necessary */
638 RegionTranslate(pRegion
, pScreen
->x
, pScreen
->y
);
640 /* add our damage to the protocol view */
641 DamageReportDamage(pDamageExt
->pDamage
, pRegion
);
644 DamageEmpty(pDamage
);
648 PanoramiXDamageExtDestroy(DamagePtr pDamage
, void *closure
)
650 PanoramiXDamageRes
*damage
= closure
;
651 damage
->damage
[pDamage
->pScreen
->myNum
] = NULL
;
655 PanoramiXDamageCreate(ClientPtr client
)
657 PanoramiXDamageRes
*damage
;
661 REQUEST(xDamageCreateReq
);
663 REQUEST_SIZE_MATCH(xDamageCreateReq
);
664 LEGAL_NEW_RESOURCE(stuff
->damage
, client
);
665 rc
= dixLookupResourceByClass((void **)&draw
, stuff
->drawable
, XRC_DRAWABLE
,
666 client
, DixGetAttrAccess
| DixReadAccess
);
670 if (!(damage
= calloc(1, sizeof(PanoramiXDamageRes
))))
673 if (!AddResource(stuff
->damage
, XRT_DAMAGE
, damage
))
676 damage
->ext
= doDamageCreate(client
, &rc
);
677 if (rc
== Success
&& draw
->type
== XRT_WINDOW
) {
678 FOR_NSCREENS_FORWARD(i
) {
679 DrawablePtr pDrawable
;
680 DamagePtr pDamage
= DamageCreate(PanoramiXDamageReport
,
681 PanoramiXDamageExtDestroy
,
682 DamageReportRawRegion
,
684 screenInfo
.screens
[i
],
689 damage
->damage
[i
] = pDamage
;
690 rc
= dixLookupDrawable(&pDrawable
, draw
->info
[i
].id
, client
,
692 DixGetAttrAccess
| DixReadAccess
);
697 DamageExtRegister(pDrawable
, pDamage
, i
!= 0);
702 FreeResource(stuff
->damage
, RT_NONE
);
708 PanoramiXDamageDelete(void *res
, XID id
)
711 PanoramiXDamageRes
*damage
= res
;
713 FOR_NSCREENS_BACKWARD(i
) {
714 if (damage
->damage
[i
]) {
715 DamageDestroy(damage
->damage
[i
]);
716 damage
->damage
[i
] = NULL
;
725 PanoramiXDamageInit(void)
727 XRT_DAMAGE
= CreateNewResourceType(PanoramiXDamageDelete
, "XineramaDamage");
729 FatalError("Couldn't Xineramify Damage extension\n");
731 PanoramiXSaveDamageCreate
= ProcDamageVector
[X_DamageCreate
];
732 ProcDamageVector
[X_DamageCreate
] = PanoramiXDamageCreate
;
736 PanoramiXDamageReset(void)
738 ProcDamageVector
[X_DamageCreate
] = PanoramiXSaveDamageCreate
;
741 #endif /* PANORAMIX */
744 DamageExtensionInit(void)
746 ExtensionEntry
*extEntry
;
749 for (s
= 0; s
< screenInfo
.numScreens
; s
++)
750 DamageSetup(screenInfo
.screens
[s
]);
752 DamageExtType
= CreateNewResourceType(FreeDamageExt
, "DamageExt");
756 if (!dixRegisterPrivateKey
757 (&DamageClientPrivateKeyRec
, PRIVATE_CLIENT
, sizeof(DamageClientRec
)))
760 if (!AddCallback(&ClientStateCallback
, DamageClientCallback
, 0))
763 if ((extEntry
= AddExtension(DAMAGE_NAME
, XDamageNumberEvents
,
765 ProcDamageDispatch
, SProcDamageDispatch
,
766 DamageResetProc
, StandardMinorOpcode
)) != 0) {
767 DamageReqCode
= (unsigned char) extEntry
->base
;
768 DamageEventBase
= extEntry
->eventBase
;
769 EventSwapVector
[DamageEventBase
+ XDamageNotify
] =
770 (EventSwapPtr
) SDamageNotifyEvent
;
771 SetResourceTypeErrorValue(DamageExtType
,
772 extEntry
->errorBase
+ BadDamage
);
775 SetResourceTypeErrorValue(XRT_DAMAGE
,
776 extEntry
->errorBase
+ BadDamage
);