2 * Copyright © 2006 Sun Microsystems
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 Sun Microsystems not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Sun Microsystems 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 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL SUN MICROSYSTEMS 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.
22 * Copyright © 2003 Keith Packard
24 * Permission to use, copy, modify, distribute, and sell this software and its
25 * documentation for any purpose is hereby granted without fee, provided that
26 * the above copyright notice appear in all copies and that both that
27 * copyright notice and this permission notice appear in supporting
28 * documentation, and that the name of Keith Packard not be used in
29 * advertising or publicity pertaining to distribution of the software without
30 * specific, written prior permission. Keith Packard makes no
31 * representations about the suitability of this software for any purpose. It
32 * is provided "as is" without express or implied warranty.
34 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
35 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
36 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
37 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
38 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
39 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
40 * PERFORMANCE OF THIS SOFTWARE.
43 #ifdef HAVE_DIX_CONFIG_H
44 #include <dix-config.h>
50 compReportDamage (DamagePtr pDamage
, RegionPtr pRegion
, void *closure
)
52 WindowPtr pWin
= (WindowPtr
) closure
;
53 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
54 CompScreenPtr cs
= GetCompScreen (pScreen
);
55 CompWindowPtr cw
= GetCompWindow (pWin
);
62 compDestroyDamage (DamagePtr pDamage
, void *closure
)
64 WindowPtr pWin
= (WindowPtr
) closure
;
65 CompWindowPtr cw
= GetCompWindow (pWin
);
71 * Redirect one window for one client
74 compRedirectWindow (ClientPtr pClient
, WindowPtr pWin
, int update
)
76 CompWindowPtr cw
= GetCompWindow (pWin
);
77 CompClientWindowPtr ccw
;
78 Bool wasMapped
= pWin
->mapped
;
79 CompScreenPtr cs
= GetCompScreen(pWin
->drawable
.pScreen
);
81 if (pWin
== cs
->pOverlayWin
) {
86 * Only one Manual update is allowed
88 if (cw
&& update
== CompositeRedirectManual
)
89 for (ccw
= cw
->clients
; ccw
; ccw
= ccw
->next
)
90 if (ccw
->update
== CompositeRedirectManual
)
94 * Allocate per-client per-window structure
95 * The client *could* allocate multiple, but while supported,
96 * it is not expected to be common
98 ccw
= xalloc (sizeof (CompClientWindowRec
));
101 ccw
->id
= FakeClientID (pClient
->index
);
102 ccw
->update
= update
;
104 * Now make sure there's a per-window structure to hang this from
108 cw
= xalloc (sizeof (CompWindowRec
));
114 cw
->damage
= DamageCreate (compReportDamage
,
116 DamageReportNonEmpty
,
118 pWin
->drawable
.pScreen
,
128 DisableMapUnmapEvents (pWin
);
129 UnmapWindow (pWin
, FALSE
);
130 EnableMapUnmapEvents (pWin
);
133 REGION_NULL (pScreen
, &cw
->borderClip
);
134 cw
->update
= CompositeRedirectAutomatic
;
136 cw
->oldx
= COMP_ORIGIN_INVALID
;
137 cw
->oldy
= COMP_ORIGIN_INVALID
;
138 cw
->damageRegistered
= FALSE
;
140 pWin
->devPrivates
[CompWindowPrivateIndex
].ptr
= cw
;
142 ccw
->next
= cw
->clients
;
144 if (!AddResource (ccw
->id
, CompositeClientWindowType
, pWin
))
146 if (ccw
->update
== CompositeRedirectManual
)
148 if (cw
->damageRegistered
)
150 DamageUnregister (&pWin
->drawable
, cw
->damage
);
151 cw
->damageRegistered
= FALSE
;
153 cw
->update
= CompositeRedirectManual
;
156 if (!compCheckRedirect (pWin
))
158 FreeResource (ccw
->id
, RT_NONE
);
161 if (wasMapped
&& !pWin
->mapped
)
163 Bool overrideRedirect
= pWin
->overrideRedirect
;
164 pWin
->overrideRedirect
= TRUE
;
165 DisableMapUnmapEvents (pWin
);
166 MapWindow (pWin
, pClient
);
167 EnableMapUnmapEvents (pWin
);
168 pWin
->overrideRedirect
= overrideRedirect
;
175 * Free one of the per-client per-window resources, clearing
176 * redirect and the per-window pointer as appropriate
179 compFreeClientWindow (WindowPtr pWin
, XID id
)
181 CompWindowPtr cw
= GetCompWindow (pWin
);
182 CompClientWindowPtr ccw
, *prev
;
183 Bool wasMapped
= pWin
->mapped
;
187 for (prev
= &cw
->clients
; (ccw
= *prev
); prev
= &ccw
->next
)
192 if (ccw
->update
== CompositeRedirectManual
)
193 cw
->update
= CompositeRedirectAutomatic
;
202 DisableMapUnmapEvents (pWin
);
203 UnmapWindow (pWin
, FALSE
);
204 EnableMapUnmapEvents (pWin
);
207 if (pWin
->redirectDraw
!= RedirectDrawNone
)
208 compFreePixmap (pWin
);
211 DamageDestroy (cw
->damage
);
213 REGION_UNINIT (pScreen
, &cw
->borderClip
);
215 pWin
->devPrivates
[CompWindowPrivateIndex
].ptr
= 0;
218 else if (cw
->update
== CompositeRedirectAutomatic
&&
219 !cw
->damageRegistered
&& pWin
->redirectDraw
!= RedirectDrawNone
)
221 DamageRegister (&pWin
->drawable
, cw
->damage
);
222 cw
->damageRegistered
= TRUE
;
223 pWin
->redirectDraw
= RedirectDrawAutomatic
;
224 DamageDamageRegion (&pWin
->drawable
, &pWin
->borderSize
);
226 if (wasMapped
&& !pWin
->mapped
)
228 Bool overrideRedirect
= pWin
->overrideRedirect
;
229 pWin
->overrideRedirect
= TRUE
;
230 DisableMapUnmapEvents (pWin
);
231 MapWindow (pWin
, clients
[CLIENT_ID(id
)]);
232 EnableMapUnmapEvents (pWin
);
233 pWin
->overrideRedirect
= overrideRedirect
;
238 * This is easy, just free the appropriate resource.
242 compUnredirectWindow (ClientPtr pClient
, WindowPtr pWin
, int update
)
244 CompWindowPtr cw
= GetCompWindow (pWin
);
245 CompClientWindowPtr ccw
;
250 for (ccw
= cw
->clients
; ccw
; ccw
= ccw
->next
)
251 if (ccw
->update
== update
&& CLIENT_ID(ccw
->id
) == pClient
->index
)
253 FreeResource (ccw
->id
, RT_NONE
);
260 * Redirect all subwindows for one client
264 compRedirectSubwindows (ClientPtr pClient
, WindowPtr pWin
, int update
)
266 CompSubwindowsPtr csw
= GetCompSubwindows (pWin
);
267 CompClientWindowPtr ccw
;
271 * Only one Manual update is allowed
273 if (csw
&& update
== CompositeRedirectManual
)
274 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
)
275 if (ccw
->update
== CompositeRedirectManual
)
278 * Allocate per-client per-window structure
279 * The client *could* allocate multiple, but while supported,
280 * it is not expected to be common
282 ccw
= xalloc (sizeof (CompClientWindowRec
));
285 ccw
->id
= FakeClientID (pClient
->index
);
286 ccw
->update
= update
;
288 * Now make sure there's a per-window structure to hang this from
292 csw
= xalloc (sizeof (CompSubwindowsRec
));
298 csw
->update
= CompositeRedirectAutomatic
;
300 pWin
->devPrivates
[CompSubwindowsPrivateIndex
].ptr
= csw
;
303 * Redirect all existing windows
305 for (pChild
= pWin
->lastChild
; pChild
; pChild
= pChild
->prevSib
)
307 int ret
= compRedirectWindow (pClient
, pChild
, update
);
310 for (pChild
= pChild
->nextSib
; pChild
; pChild
= pChild
->nextSib
)
311 (void) compUnredirectWindow (pClient
, pChild
, update
);
315 pWin
->devPrivates
[CompSubwindowsPrivateIndex
].ptr
= 0;
322 * Hook into subwindows list
324 ccw
->next
= csw
->clients
;
326 if (!AddResource (ccw
->id
, CompositeClientSubwindowsType
, pWin
))
328 if (ccw
->update
== CompositeRedirectManual
)
330 csw
->update
= CompositeRedirectManual
;
332 * tell damage extension that damage events for this client are
335 DamageExtSetCritical (pClient
, TRUE
);
341 * Free one of the per-client per-subwindows resources,
342 * which frees one redirect per subwindow
345 compFreeClientSubwindows (WindowPtr pWin
, XID id
)
347 CompSubwindowsPtr csw
= GetCompSubwindows (pWin
);
348 CompClientWindowPtr ccw
, *prev
;
353 for (prev
= &csw
->clients
; (ccw
= *prev
); prev
= &ccw
->next
)
357 ClientPtr pClient
= clients
[CLIENT_ID(id
)];
360 if (ccw
->update
== CompositeRedirectManual
)
363 * tell damage extension that damage events for this client are
366 DamageExtSetCritical (pClient
, FALSE
);
367 csw
->update
= CompositeRedirectAutomatic
;
369 (*pWin
->drawable
.pScreen
->ClearToBackground
)(pWin
, 0, 0, 0, 0, TRUE
);
373 * Unredirect all existing subwindows
375 for (pChild
= pWin
->lastChild
; pChild
; pChild
= pChild
->prevSib
)
376 (void) compUnredirectWindow (pClient
, pChild
, ccw
->update
);
384 * Check if all of the per-client records are gone
388 pWin
->devPrivates
[CompSubwindowsPrivateIndex
].ptr
= 0;
394 * This is easy, just free the appropriate resource.
398 compUnredirectSubwindows (ClientPtr pClient
, WindowPtr pWin
, int update
)
400 CompSubwindowsPtr csw
= GetCompSubwindows (pWin
);
401 CompClientWindowPtr ccw
;
405 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
)
406 if (ccw
->update
== update
&& CLIENT_ID(ccw
->id
) == pClient
->index
)
408 FreeResource (ccw
->id
, RT_NONE
);
415 * Add redirection information for one subwindow (during reparent)
419 compRedirectOneSubwindow (WindowPtr pParent
, WindowPtr pWin
)
421 CompSubwindowsPtr csw
= GetCompSubwindows (pParent
);
422 CompClientWindowPtr ccw
;
426 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
)
428 int ret
= compRedirectWindow (clients
[CLIENT_ID(ccw
->id
)],
437 * Remove redirection information for one subwindow (during reparent)
441 compUnredirectOneSubwindow (WindowPtr pParent
, WindowPtr pWin
)
443 CompSubwindowsPtr csw
= GetCompSubwindows (pParent
);
444 CompClientWindowPtr ccw
;
448 for (ccw
= csw
->clients
; ccw
; ccw
= ccw
->next
)
450 int ret
= compUnredirectWindow (clients
[CLIENT_ID(ccw
->id
)],
459 compNewPixmap (WindowPtr pWin
, int x
, int y
, int w
, int h
)
461 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
462 WindowPtr pParent
= pWin
->parent
;
465 pPixmap
= (*pScreen
->CreatePixmap
) (pScreen
, w
, h
, pWin
->drawable
.depth
);
470 pPixmap
->screen_x
= x
;
471 pPixmap
->screen_y
= y
;
473 if (pParent
->drawable
.depth
== pWin
->drawable
.depth
)
475 GCPtr pGC
= GetScratchGC (pWin
->drawable
.depth
, pScreen
);
478 * Copy bits from the parent into the new pixmap so that it will
479 * have "reasonable" contents in case for background None areas.
483 XID val
= IncludeInferiors
;
485 ValidateGC(&pPixmap
->drawable
, pGC
);
486 dixChangeGC (serverClient
, pGC
, GCSubwindowMode
, &val
, NULL
);
487 (*pGC
->ops
->CopyArea
) (&pParent
->drawable
,
490 x
- pParent
->drawable
.x
,
491 y
- pParent
->drawable
.y
,
498 PictFormatPtr pSrcFormat
= compWindowFormat (pParent
);
499 PictFormatPtr pDstFormat
= compWindowFormat (pWin
);
500 XID inferiors
= IncludeInferiors
;
503 PicturePtr pSrcPicture
= CreatePicture (None
,
508 serverClient
, &error
);
510 PicturePtr pDstPicture
= CreatePicture (None
,
514 serverClient
, &error
);
516 if (pSrcPicture
&& pDstPicture
)
518 CompositePicture (PictOpSrc
,
522 x
- pParent
->drawable
.x
,
523 y
- pParent
->drawable
.y
,
527 FreePicture (pSrcPicture
, 0);
529 FreePicture (pDstPicture
, 0);
535 compAllocPixmap (WindowPtr pWin
)
537 int bw
= (int) pWin
->borderWidth
;
538 int x
= pWin
->drawable
.x
- bw
;
539 int y
= pWin
->drawable
.y
- bw
;
540 int w
= pWin
->drawable
.width
+ (bw
<< 1);
541 int h
= pWin
->drawable
.height
+ (bw
<< 1);
542 PixmapPtr pPixmap
= compNewPixmap (pWin
, x
, y
, w
, h
);
543 CompWindowPtr cw
= GetCompWindow (pWin
);
547 if (cw
->update
== CompositeRedirectAutomatic
)
548 pWin
->redirectDraw
= RedirectDrawAutomatic
;
550 pWin
->redirectDraw
= RedirectDrawManual
;
552 compSetPixmap (pWin
, pPixmap
);
553 cw
->oldx
= COMP_ORIGIN_INVALID
;
554 cw
->oldy
= COMP_ORIGIN_INVALID
;
555 cw
->damageRegistered
= FALSE
;
556 if (cw
->update
== CompositeRedirectAutomatic
)
558 DamageRegister (&pWin
->drawable
, cw
->damage
);
559 cw
->damageRegistered
= TRUE
;
565 compFreePixmap (WindowPtr pWin
)
567 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
568 PixmapPtr pRedirectPixmap
, pParentPixmap
;
569 CompWindowPtr cw
= GetCompWindow (pWin
);
571 if (cw
->damageRegistered
)
573 DamageUnregister (&pWin
->drawable
, cw
->damage
);
574 cw
->damageRegistered
= FALSE
;
575 DamageEmpty (cw
->damage
);
578 * Move the parent-constrained border clip region back into
579 * the window so that ValidateTree will handle the unmap
580 * case correctly. Unmap adds the window borderClip to the
581 * parent exposed area; regions beyond the parent cause crashes
583 REGION_COPY (pScreen
, &pWin
->borderClip
, &cw
->borderClip
);
584 pRedirectPixmap
= (*pScreen
->GetWindowPixmap
) (pWin
);
585 pParentPixmap
= (*pScreen
->GetWindowPixmap
) (pWin
->parent
);
586 pWin
->redirectDraw
= RedirectDrawNone
;
587 compSetPixmap (pWin
, pParentPixmap
);
588 (*pScreen
->DestroyPixmap
) (pRedirectPixmap
);
592 * Make sure the pixmap is the right size and offset. Allocate a new
593 * pixmap to change size, adjust origin to change offset, leaving the
594 * old pixmap in cw->pOldPixmap so bits can be recovered
597 compReallocPixmap (WindowPtr pWin
, int draw_x
, int draw_y
,
598 unsigned int w
, unsigned int h
, int bw
)
600 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
601 PixmapPtr pOld
= (*pScreen
->GetWindowPixmap
) (pWin
);
603 CompWindowPtr cw
= GetCompWindow (pWin
);
607 assert (cw
&& pWin
->redirectDraw
!= RedirectDrawNone
);
608 cw
->oldx
= pOld
->screen_x
;
609 cw
->oldy
= pOld
->screen_y
;
612 pix_w
= w
+ (bw
<< 1);
613 pix_h
= h
+ (bw
<< 1);
614 if (pix_w
!= pOld
->drawable
.width
|| pix_h
!= pOld
->drawable
.height
)
616 pNew
= compNewPixmap (pWin
, pix_x
, pix_y
, pix_w
, pix_h
);
619 cw
->pOldPixmap
= pOld
;
620 compSetPixmap (pWin
, pNew
);
627 pNew
->screen_x
= pix_x
;
628 pNew
->screen_y
= pix_y
;