2 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 * Copyright © 2003 Keith Packard
25 * Permission to use, copy, modify, distribute, and sell this software and its
26 * documentation for any purpose is hereby granted without fee, provided that
27 * the above copyright notice appear in all copies and that both that
28 * copyright notice and this permission notice appear in supporting
29 * documentation, and that the name of Keith Packard not be used in
30 * advertising or publicity pertaining to distribution of the software without
31 * specific, written prior permission. Keith Packard makes no
32 * representations about the suitability of this software for any purpose. It
33 * is provided "as is" without express or implied warranty.
35 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
36 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
37 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
39 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
40 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41 * PERFORMANCE OF THIS SOFTWARE.
44 #ifdef HAVE_DIX_CONFIG_H
45 #include <dix-config.h>
51 compScreenUpdate(ScreenPtr pScreen
)
53 compCheckTree(pScreen
);
54 compPaintChildrenToWindow(pScreen
->root
);
58 compBlockHandler(ScreenPtr pScreen
, pointer pTimeout
, pointer pReadmask
)
60 CompScreenPtr cs
= GetCompScreen(pScreen
);
62 pScreen
->BlockHandler
= cs
->BlockHandler
;
63 compScreenUpdate(pScreen
);
64 (*pScreen
->BlockHandler
) (pScreen
, pTimeout
, pReadmask
);
66 /* Next damage will restore the block handler */
67 cs
->BlockHandler
= NULL
;
71 compReportDamage(DamagePtr pDamage
, RegionPtr pRegion
, void *closure
)
73 WindowPtr pWin
= (WindowPtr
) closure
;
74 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
75 CompScreenPtr cs
= GetCompScreen(pScreen
);
76 CompWindowPtr cw
= GetCompWindow(pWin
);
78 if (!cs
->BlockHandler
) {
79 cs
->BlockHandler
= pScreen
->BlockHandler
;
80 pScreen
->BlockHandler
= compBlockHandler
;
84 /* Mark the ancestors */
87 if (pWin
->damagedDescendants
)
89 pWin
->damagedDescendants
= TRUE
;
95 compDestroyDamage(DamagePtr pDamage
, void *closure
)
97 WindowPtr pWin
= (WindowPtr
) closure
;
98 CompWindowPtr cw
= GetCompWindow(pWin
);
104 compMarkWindows(WindowPtr pWin
, WindowPtr
*ppLayerWin
)
106 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
107 WindowPtr pLayerWin
= pWin
;
112 (*pScreen
->MarkOverlappedWindows
) (pWin
, pWin
, &pLayerWin
);
113 (*pScreen
->MarkWindow
) (pLayerWin
->parent
);
115 *ppLayerWin
= pLayerWin
;
121 compHandleMarkedWindows(WindowPtr pWin
, WindowPtr pLayerWin
)
123 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
125 (*pScreen
->ValidateTree
) (pLayerWin
->parent
, pLayerWin
, VTOther
);
126 (*pScreen
->HandleExposures
) (pLayerWin
->parent
);
127 if (pScreen
->PostValidateTree
)
128 (*pScreen
->PostValidateTree
) (pLayerWin
->parent
, pLayerWin
, VTOther
);
132 * Redirect one window for one client
135 compRedirectWindow(ClientPtr pClient
, WindowPtr pWin
, int update
)
137 CompWindowPtr cw
= GetCompWindow(pWin
);
138 CompClientWindowPtr ccw
;
139 CompScreenPtr cs
= GetCompScreen(pWin
->drawable
.pScreen
);
141 Bool anyMarked
= FALSE
;
143 if (pWin
== cs
->pOverlayWin
) {
151 * Only one Manual update is allowed
153 if (cw
&& update
== CompositeRedirectManual
)
154 for (ccw
= cw
->clients
; ccw
; ccw
= ccw
->next
)
155 if (ccw
->update
== CompositeRedirectManual
)
159 * Allocate per-client per-window structure
160 * The client *could* allocate multiple, but while supported,
161 * it is not expected to be common
163 ccw
= malloc(sizeof(CompClientWindowRec
));
166 ccw
->id
= FakeClientID(pClient
->index
);
167 ccw
->update
= update
;
169 * Now make sure there's a per-window structure to hang this from
172 cw
= malloc(sizeof(CompWindowRec
));
177 cw
->damage
= DamageCreate(compReportDamage
,
179 DamageReportNonEmpty
,
180 FALSE
, pWin
->drawable
.pScreen
, pWin
);
187 anyMarked
= compMarkWindows(pWin
, &pLayerWin
);
189 RegionNull(&cw
->borderClip
);
190 cw
->update
= CompositeRedirectAutomatic
;
192 cw
->oldx
= COMP_ORIGIN_INVALID
;
193 cw
->oldy
= COMP_ORIGIN_INVALID
;
194 cw
->damageRegistered
= FALSE
;
196 cw
->pOldPixmap
= NullPixmap
;
197 dixSetPrivate(&pWin
->devPrivates
, CompWindowPrivateKey
, cw
);
199 ccw
->next
= cw
->clients
;
201 if (!AddResource(ccw
->id
, CompositeClientWindowType
, pWin
))
203 if (ccw
->update
== CompositeRedirectManual
) {
205 anyMarked
= compMarkWindows(pWin
, &pLayerWin
);
207 if (cw
->damageRegistered
) {
208 DamageUnregister(cw
->damage
);
209 cw
->damageRegistered
= FALSE
;
211 cw
->update
= CompositeRedirectManual
;
213 else if (cw
->update
== CompositeRedirectAutomatic
&& !cw
->damageRegistered
) {
215 anyMarked
= compMarkWindows(pWin
, &pLayerWin
);
218 if (!compCheckRedirect(pWin
)) {
219 FreeResource(ccw
->id
, RT_NONE
);
224 compHandleMarkedWindows(pWin
, pLayerWin
);
230 compRestoreWindow(WindowPtr pWin
, PixmapPtr pPixmap
)
232 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
233 WindowPtr pParent
= pWin
->parent
;
235 if (pParent
->drawable
.depth
== pWin
->drawable
.depth
) {
236 GCPtr pGC
= GetScratchGC(pWin
->drawable
.depth
, pScreen
);
237 int bw
= (int) pWin
->borderWidth
;
240 int w
= pWin
->drawable
.width
;
241 int h
= pWin
->drawable
.height
;
246 val
.val
= IncludeInferiors
;
247 ChangeGC(NullClient
, pGC
, GCSubwindowMode
, &val
);
248 ValidateGC(&pWin
->drawable
, pGC
);
249 (*pGC
->ops
->CopyArea
) (&pPixmap
->drawable
,
250 &pWin
->drawable
, pGC
, x
, y
, w
, h
, 0, 0);
257 * Free one of the per-client per-window resources, clearing
258 * redirect and the per-window pointer as appropriate
261 compFreeClientWindow(WindowPtr pWin
, XID id
)
263 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
264 CompWindowPtr cw
= GetCompWindow(pWin
);
265 CompClientWindowPtr ccw
, *prev
;
266 Bool anyMarked
= FALSE
;
268 PixmapPtr pPixmap
= NULL
;
272 for (prev
= &cw
->clients
; (ccw
= *prev
); prev
= &ccw
->next
) {
275 if (ccw
->update
== CompositeRedirectManual
)
276 cw
->update
= CompositeRedirectAutomatic
;
282 anyMarked
= compMarkWindows(pWin
, &pLayerWin
);
284 if (pWin
->redirectDraw
!= RedirectDrawNone
) {
285 pPixmap
= (*pScreen
->GetWindowPixmap
) (pWin
);
286 compSetParentPixmap(pWin
);
290 DamageDestroy(cw
->damage
);
292 RegionUninit(&cw
->borderClip
);
294 dixSetPrivate(&pWin
->devPrivates
, CompWindowPrivateKey
, NULL
);
297 else if (cw
->update
== CompositeRedirectAutomatic
&&
298 !cw
->damageRegistered
&& pWin
->redirectDraw
!= RedirectDrawNone
) {
299 anyMarked
= compMarkWindows(pWin
, &pLayerWin
);
301 DamageRegister(&pWin
->drawable
, cw
->damage
);
302 cw
->damageRegistered
= TRUE
;
303 pWin
->redirectDraw
= RedirectDrawAutomatic
;
304 DamageDamageRegion(&pWin
->drawable
, &pWin
->borderSize
);
308 compHandleMarkedWindows(pWin
, pLayerWin
);
311 compRestoreWindow(pWin
, pPixmap
);
312 (*pScreen
->DestroyPixmap
) (pPixmap
);
317 * This is easy, just free the appropriate resource.
321 compUnredirectWindow(ClientPtr pClient
, WindowPtr pWin
, int update
)
323 CompWindowPtr cw
= GetCompWindow(pWin
);
324 CompClientWindowPtr ccw
;
329 for (ccw
= cw
->clients
; ccw
; ccw
= ccw
->next
)
330 if (ccw
->update
== update
&& CLIENT_ID(ccw
->id
) == pClient
->index
) {
331 FreeResource(ccw
->id
, RT_NONE
);
338 * Redirect all subwindows for one client
342 compRedirectSubwindows(ClientPtr pClient
, WindowPtr pWin
, int update
)
344 CompSubwindowsPtr csw
= GetCompSubwindows(pWin
);
345 CompClientWindowPtr ccw
;
349 * Only one Manual update is allowed
351 if (csw
&& update
== CompositeRedirectManual
)
352 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
)
353 if (ccw
->update
== CompositeRedirectManual
)
356 * Allocate per-client per-window structure
357 * The client *could* allocate multiple, but while supported,
358 * it is not expected to be common
360 ccw
= malloc(sizeof(CompClientWindowRec
));
363 ccw
->id
= FakeClientID(pClient
->index
);
364 ccw
->update
= update
;
366 * Now make sure there's a per-window structure to hang this from
369 csw
= malloc(sizeof(CompSubwindowsRec
));
374 csw
->update
= CompositeRedirectAutomatic
;
376 dixSetPrivate(&pWin
->devPrivates
, CompSubwindowsPrivateKey
, csw
);
379 * Redirect all existing windows
381 for (pChild
= pWin
->lastChild
; pChild
; pChild
= pChild
->prevSib
) {
382 int ret
= compRedirectWindow(pClient
, pChild
, update
);
384 if (ret
!= Success
) {
385 for (pChild
= pChild
->nextSib
; pChild
; pChild
= pChild
->nextSib
)
386 (void) compUnredirectWindow(pClient
, pChild
, update
);
389 dixSetPrivate(&pWin
->devPrivates
, CompSubwindowsPrivateKey
, 0);
396 * Hook into subwindows list
398 ccw
->next
= csw
->clients
;
400 if (!AddResource(ccw
->id
, CompositeClientSubwindowsType
, pWin
))
402 if (ccw
->update
== CompositeRedirectManual
) {
403 csw
->update
= CompositeRedirectManual
;
405 * tell damage extension that damage events for this client are
408 DamageExtSetCritical(pClient
, TRUE
);
409 pWin
->inhibitBGPaint
= TRUE
;
415 * Free one of the per-client per-subwindows resources,
416 * which frees one redirect per subwindow
419 compFreeClientSubwindows(WindowPtr pWin
, XID id
)
421 CompSubwindowsPtr csw
= GetCompSubwindows(pWin
);
422 CompClientWindowPtr ccw
, *prev
;
427 for (prev
= &csw
->clients
; (ccw
= *prev
); prev
= &ccw
->next
) {
429 ClientPtr pClient
= clients
[CLIENT_ID(id
)];
432 if (ccw
->update
== CompositeRedirectManual
) {
434 * tell damage extension that damage events for this client are
437 DamageExtSetCritical(pClient
, FALSE
);
438 csw
->update
= CompositeRedirectAutomatic
;
439 pWin
->inhibitBGPaint
= FALSE
;
441 (*pWin
->drawable
.pScreen
->ClearToBackground
) (pWin
, 0, 0, 0,
446 * Unredirect all existing subwindows
448 for (pChild
= pWin
->lastChild
; pChild
; pChild
= pChild
->prevSib
)
449 (void) compUnredirectWindow(pClient
, pChild
, ccw
->update
);
457 * Check if all of the per-client records are gone
460 dixSetPrivate(&pWin
->devPrivates
, CompSubwindowsPrivateKey
, NULL
);
466 * This is easy, just free the appropriate resource.
470 compUnredirectSubwindows(ClientPtr pClient
, WindowPtr pWin
, int update
)
472 CompSubwindowsPtr csw
= GetCompSubwindows(pWin
);
473 CompClientWindowPtr ccw
;
477 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
)
478 if (ccw
->update
== update
&& CLIENT_ID(ccw
->id
) == pClient
->index
) {
479 FreeResource(ccw
->id
, RT_NONE
);
486 * Add redirection information for one subwindow (during reparent)
490 compRedirectOneSubwindow(WindowPtr pParent
, WindowPtr pWin
)
492 CompSubwindowsPtr csw
= GetCompSubwindows(pParent
);
493 CompClientWindowPtr ccw
;
497 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
) {
498 int ret
= compRedirectWindow(clients
[CLIENT_ID(ccw
->id
)],
508 * Remove redirection information for one subwindow (during reparent)
512 compUnredirectOneSubwindow(WindowPtr pParent
, WindowPtr pWin
)
514 CompSubwindowsPtr csw
= GetCompSubwindows(pParent
);
515 CompClientWindowPtr ccw
;
519 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
) {
520 int ret
= compUnredirectWindow(clients
[CLIENT_ID(ccw
->id
)],
530 compNewPixmap(WindowPtr pWin
, int x
, int y
, int w
, int h
)
532 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
533 WindowPtr pParent
= pWin
->parent
;
536 pPixmap
= (*pScreen
->CreatePixmap
) (pScreen
, w
, h
, pWin
->drawable
.depth
,
537 CREATE_PIXMAP_USAGE_BACKING_PIXMAP
);
542 pPixmap
->screen_x
= x
;
543 pPixmap
->screen_y
= y
;
545 if (pParent
->drawable
.depth
== pWin
->drawable
.depth
) {
546 GCPtr pGC
= GetScratchGC(pWin
->drawable
.depth
, pScreen
);
551 val
.val
= IncludeInferiors
;
552 ChangeGC(NullClient
, pGC
, GCSubwindowMode
, &val
);
553 ValidateGC(&pPixmap
->drawable
, pGC
);
554 (*pGC
->ops
->CopyArea
) (&pParent
->drawable
,
557 x
- pParent
->drawable
.x
,
558 y
- pParent
->drawable
.y
, w
, h
, 0, 0);
563 PictFormatPtr pSrcFormat
= PictureWindowFormat(pParent
);
564 PictFormatPtr pDstFormat
= PictureWindowFormat(pWin
);
565 XID inferiors
= IncludeInferiors
;
568 PicturePtr pSrcPicture
= CreatePicture(None
,
573 serverClient
, &error
);
575 PicturePtr pDstPicture
= CreatePicture(None
,
579 serverClient
, &error
);
581 if (pSrcPicture
&& pDstPicture
) {
582 CompositePicture(PictOpSrc
,
586 x
- pParent
->drawable
.x
,
587 y
- pParent
->drawable
.y
, 0, 0, 0, 0, w
, h
);
590 FreePicture(pSrcPicture
, 0);
592 FreePicture(pDstPicture
, 0);
598 compAllocPixmap(WindowPtr pWin
)
600 int bw
= (int) pWin
->borderWidth
;
601 int x
= pWin
->drawable
.x
- bw
;
602 int y
= pWin
->drawable
.y
- bw
;
603 int w
= pWin
->drawable
.width
+ (bw
<< 1);
604 int h
= pWin
->drawable
.height
+ (bw
<< 1);
605 PixmapPtr pPixmap
= compNewPixmap(pWin
, x
, y
, w
, h
);
606 CompWindowPtr cw
= GetCompWindow(pWin
);
610 if (cw
->update
== CompositeRedirectAutomatic
)
611 pWin
->redirectDraw
= RedirectDrawAutomatic
;
613 pWin
->redirectDraw
= RedirectDrawManual
;
615 compSetPixmap(pWin
, pPixmap
);
616 cw
->oldx
= COMP_ORIGIN_INVALID
;
617 cw
->oldy
= COMP_ORIGIN_INVALID
;
618 cw
->damageRegistered
= FALSE
;
619 if (cw
->update
== CompositeRedirectAutomatic
) {
620 DamageRegister(&pWin
->drawable
, cw
->damage
);
621 cw
->damageRegistered
= TRUE
;
624 /* Make sure our borderClip is up to date */
625 RegionUninit(&cw
->borderClip
);
626 RegionCopy(&cw
->borderClip
, &pWin
->borderClip
);
627 cw
->borderClipX
= pWin
->drawable
.x
;
628 cw
->borderClipY
= pWin
->drawable
.y
;
634 compSetParentPixmap(WindowPtr pWin
)
636 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
637 PixmapPtr pParentPixmap
;
638 CompWindowPtr cw
= GetCompWindow(pWin
);
640 if (cw
->damageRegistered
) {
641 DamageUnregister(cw
->damage
);
642 cw
->damageRegistered
= FALSE
;
643 DamageEmpty(cw
->damage
);
646 * Move the parent-constrained border clip region back into
647 * the window so that ValidateTree will handle the unmap
648 * case correctly. Unmap adds the window borderClip to the
649 * parent exposed area; regions beyond the parent cause crashes
651 RegionCopy(&pWin
->borderClip
, &cw
->borderClip
);
652 pParentPixmap
= (*pScreen
->GetWindowPixmap
) (pWin
->parent
);
653 pWin
->redirectDraw
= RedirectDrawNone
;
654 compSetPixmap(pWin
, pParentPixmap
);
658 * Make sure the pixmap is the right size and offset. Allocate a new
659 * pixmap to change size, adjust origin to change offset, leaving the
660 * old pixmap in cw->pOldPixmap so bits can be recovered
663 compReallocPixmap(WindowPtr pWin
, int draw_x
, int draw_y
,
664 unsigned int w
, unsigned int h
, int bw
)
666 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
667 PixmapPtr pOld
= (*pScreen
->GetWindowPixmap
) (pWin
);
669 CompWindowPtr cw
= GetCompWindow(pWin
);
673 assert(cw
&& pWin
->redirectDraw
!= RedirectDrawNone
);
674 cw
->oldx
= pOld
->screen_x
;
675 cw
->oldy
= pOld
->screen_y
;
678 pix_w
= w
+ (bw
<< 1);
679 pix_h
= h
+ (bw
<< 1);
680 if (pix_w
!= pOld
->drawable
.width
|| pix_h
!= pOld
->drawable
.height
) {
681 pNew
= compNewPixmap(pWin
, pix_x
, pix_y
, pix_w
, pix_h
);
684 cw
->pOldPixmap
= pOld
;
685 compSetPixmap(pWin
, pNew
);
691 pNew
->screen_x
= pix_x
;
692 pNew
->screen_y
= pix_y
;