compwindow.c revision 05b261ec
1/*
2 * Copyright © 2006 Sun Microsystems
3 *
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.
13 *
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.
21 *
22 * Copyright © 2003 Keith Packard
23 *
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.
33 *
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.
41 */
42
43#ifdef HAVE_DIX_CONFIG_H
44#include <dix-config.h>
45#endif
46
47#include "compint.h"
48
49#ifdef COMPOSITE_DEBUG
50static int
51compCheckWindow (WindowPtr pWin, pointer data)
52{
53    ScreenPtr	pScreen = pWin->drawable.pScreen;
54    PixmapPtr	pWinPixmap = (*pScreen->GetWindowPixmap) (pWin);
55    PixmapPtr	pParentPixmap = pWin->parent ? (*pScreen->GetWindowPixmap) (pWin->parent) : 0;
56    PixmapPtr	pScreenPixmap = (*pScreen->GetScreenPixmap) (pScreen);
57
58    if (!pWin->parent)
59    {
60	assert (pWin->redirectDraw == RedirectDrawNone);
61	assert (pWinPixmap == pScreenPixmap);
62    }
63    else if (pWin->redirectDraw != RedirectDrawNone)
64    {
65	assert (pWinPixmap != pParentPixmap);
66	assert (pWinPixmap != pScreenPixmap);
67    }
68    else
69    {
70	assert (pWinPixmap == pParentPixmap);
71    }
72    assert (0 < pWinPixmap->refcnt && pWinPixmap->refcnt < 3);
73    assert (0 < pScreenPixmap->refcnt && pScreenPixmap->refcnt < 3);
74    if (pParentPixmap)
75	assert (0 <= pParentPixmap->refcnt && pParentPixmap->refcnt < 3);
76    return WT_WALKCHILDREN;
77}
78
79void
80compCheckTree (ScreenPtr pScreen)
81{
82    WalkTree (pScreen, compCheckWindow, 0);
83}
84#endif
85
86typedef struct _compPixmapVisit {
87    WindowPtr	pWindow;
88    PixmapPtr	pPixmap;
89} CompPixmapVisitRec, *CompPixmapVisitPtr;
90
91static Bool
92compRepaintBorder (ClientPtr pClient, pointer closure)
93{
94    WindowPtr pWindow;
95    int rc = dixLookupWindow(&pWindow, (XID)closure, pClient,DixUnknownAccess);
96
97    if (rc == Success) {
98	RegionRec exposed;
99
100	REGION_NULL(pScreen, &exposed);
101	REGION_SUBTRACT(pScreen, &exposed, &pWindow->borderClip, &pWindow->winSize);
102	(*pWindow->drawable.pScreen->PaintWindowBorder)(pWindow, &exposed, PW_BORDER);
103	REGION_UNINIT(pScreen, &exposed);
104    }
105    return TRUE;
106}
107
108static int
109compSetPixmapVisitWindow (WindowPtr pWindow, pointer data)
110{
111    CompPixmapVisitPtr	pVisit = (CompPixmapVisitPtr) data;
112    ScreenPtr		pScreen = pWindow->drawable.pScreen;
113
114    if (pWindow != pVisit->pWindow && pWindow->redirectDraw != RedirectDrawNone)
115	return WT_DONTWALKCHILDREN;
116    (*pScreen->SetWindowPixmap) (pWindow, pVisit->pPixmap);
117    /*
118     * Recompute winSize and borderSize.  This is duplicate effort
119     * when resizing pixmaps, but necessary when changing redirection.
120     * Might be nice to fix this.
121     */
122    SetWinSize (pWindow);
123    SetBorderSize (pWindow);
124    if (HasBorder (pWindow))
125	QueueWorkProc (compRepaintBorder, serverClient,
126		       (pointer) pWindow->drawable.id);
127    return WT_WALKCHILDREN;
128}
129
130void
131compSetPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
132{
133    CompPixmapVisitRec	visitRec;
134
135    visitRec.pWindow = pWindow;
136    visitRec.pPixmap = pPixmap;
137    TraverseTree (pWindow, compSetPixmapVisitWindow, (pointer) &visitRec);
138    compCheckTree (pWindow->drawable.pScreen);
139}
140
141Bool
142compCheckRedirect (WindowPtr pWin)
143{
144    CompWindowPtr   cw = GetCompWindow (pWin);
145    CompScreenPtr   cs = GetCompScreen(pWin->drawable.pScreen);
146    Bool	    should;
147
148    should = pWin->realized && (pWin->drawable.class != InputOnly) &&
149	     (cw != NULL) && (pWin->parent != NULL);
150
151    /* Never redirect the overlay window */
152    if (cs->pOverlayWin != NULL) {
153	if (pWin == cs->pOverlayWin) {
154	    should = FALSE;
155	}
156    }
157
158    if (should != (pWin->redirectDraw != RedirectDrawNone))
159    {
160	if (should)
161	    return compAllocPixmap (pWin);
162	else
163	    compFreePixmap (pWin);
164    }
165    return TRUE;
166}
167
168static int
169updateOverlayWindow(ScreenPtr pScreen)
170{
171	CompScreenPtr cs;
172	WindowPtr pWin; /* overlay window */
173	XID vlist[2];
174
175	cs = GetCompScreen(pScreen);
176	if ((pWin = cs->pOverlayWin) != NULL) {
177		if ((pWin->drawable.width == pScreen->width) &&
178			(pWin->drawable.height == pScreen->height))
179			return Success;
180
181		/* Let's resize the overlay window. */
182		vlist[0] = pScreen->width;
183		vlist[1] = pScreen->height;
184		return ConfigureWindow(pWin, CWWidth | CWHeight, vlist, wClient(pWin));
185	}
186
187	/* Let's be on the safe side and not assume an overlay window is always allocated. */
188	return Success;
189}
190
191Bool
192compPositionWindow (WindowPtr pWin, int x, int y)
193{
194    ScreenPtr	    pScreen = pWin->drawable.pScreen;
195    CompScreenPtr   cs = GetCompScreen (pScreen);
196    Bool	    ret = TRUE;
197
198    pScreen->PositionWindow = cs->PositionWindow;
199    /*
200     * "Shouldn't need this as all possible places should be wrapped
201     *
202    compCheckRedirect (pWin);
203     */
204#ifdef COMPOSITE_DEBUG
205    if ((pWin->redirectDraw != RedirectDrawNone) !=
206	(pWin->viewable && (GetCompWindow(pWin) != NULL)))
207	abort ();
208#endif
209    if (pWin->redirectDraw != RedirectDrawNone)
210    {
211	PixmapPtr   pPixmap = (*pScreen->GetWindowPixmap) (pWin);
212	int	    bw = wBorderWidth (pWin);
213	int	    nx = pWin->drawable.x - bw;
214	int	    ny = pWin->drawable.y - bw;
215
216	if (pPixmap->screen_x != nx || pPixmap->screen_y != ny)
217	{
218	    pPixmap->screen_x = nx;
219	    pPixmap->screen_y = ny;
220	    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
221	}
222    }
223
224    if (!(*pScreen->PositionWindow) (pWin, x, y))
225	ret = FALSE;
226    cs->PositionWindow = pScreen->PositionWindow;
227    pScreen->PositionWindow = compPositionWindow;
228    compCheckTree (pWin->drawable.pScreen);
229    if (updateOverlayWindow(pScreen) != Success)
230	ret = FALSE;
231    return ret;
232}
233
234Bool
235compRealizeWindow (WindowPtr pWin)
236{
237    ScreenPtr	    pScreen = pWin->drawable.pScreen;
238    CompScreenPtr   cs = GetCompScreen (pScreen);
239    Bool	    ret = TRUE;
240
241    pScreen->RealizeWindow = cs->RealizeWindow;
242    compCheckRedirect (pWin);
243    if (!(*pScreen->RealizeWindow) (pWin))
244	ret = FALSE;
245    cs->RealizeWindow = pScreen->RealizeWindow;
246    pScreen->RealizeWindow = compRealizeWindow;
247    compCheckTree (pWin->drawable.pScreen);
248    return ret;
249}
250
251Bool
252compUnrealizeWindow (WindowPtr pWin)
253{
254    ScreenPtr	    pScreen = pWin->drawable.pScreen;
255    CompScreenPtr   cs = GetCompScreen (pScreen);
256    Bool	    ret = TRUE;
257
258    pScreen->UnrealizeWindow = cs->UnrealizeWindow;
259    compCheckRedirect (pWin);
260    if (!(*pScreen->UnrealizeWindow) (pWin))
261	ret = FALSE;
262    cs->UnrealizeWindow = pScreen->UnrealizeWindow;
263    pScreen->UnrealizeWindow = compUnrealizeWindow;
264    compCheckTree (pWin->drawable.pScreen);
265    return ret;
266}
267
268void
269compPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
270{
271    ScreenPtr		pScreen = pWin->drawable.pScreen;
272    CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
273    CompScreenPtr	cs = GetCompScreen (pScreen);
274
275    if (csw && csw->update == CompositeRedirectManual)
276	return;
277    pScreen->PaintWindowBackground = cs->PaintWindowBackground;
278    (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
279    cs->PaintWindowBackground = pScreen->PaintWindowBackground;
280    pScreen->PaintWindowBackground = compPaintWindowBackground;
281}
282
283/*
284 * Called after the borderClip for the window has settled down
285 * We use this to make sure our extra borderClip has the right origin
286 */
287
288void
289compClipNotify (WindowPtr pWin, int dx, int dy)
290{
291    ScreenPtr		pScreen = pWin->drawable.pScreen;
292    CompScreenPtr	cs = GetCompScreen (pScreen);
293    CompWindowPtr	cw = GetCompWindow (pWin);
294
295    if (cw)
296    {
297	if (cw->borderClipX != pWin->drawable.x ||
298	    cw->borderClipY != pWin->drawable.y)
299	{
300	    REGION_TRANSLATE (pScreen, &cw->borderClip,
301			      pWin->drawable.x - cw->borderClipX,
302			      pWin->drawable.y - cw->borderClipY);
303	    cw->borderClipX = pWin->drawable.x;
304	    cw->borderClipY = pWin->drawable.y;
305	}
306    }
307    if (cs->ClipNotify)
308    {
309	pScreen->ClipNotify = cs->ClipNotify;
310	(*pScreen->ClipNotify) (pWin, dx, dy);
311	cs->ClipNotify = pScreen->ClipNotify;
312	pScreen->ClipNotify = compClipNotify;
313    }
314}
315
316/*
317 * Returns TRUE if the window needs server-provided automatic redirect,
318 * which is true if the child and parent aren't both regular or ARGB visuals
319 */
320
321static Bool
322compIsAlternateVisual (ScreenPtr    pScreen,
323		       XID	    visual)
324{
325    CompScreenPtr	cs = GetCompScreen (pScreen);
326    int			i;
327
328    for (i = 0; i < cs->numAlternateVisuals; i++)
329	if (cs->alternateVisuals[i] == visual)
330	    return TRUE;
331    return FALSE;
332}
333
334static Bool
335compImplicitRedirect (WindowPtr pWin, WindowPtr pParent)
336{
337    if (pParent)
338    {
339	ScreenPtr	pScreen = pWin->drawable.pScreen;
340	XID		winVisual = wVisual (pWin);
341	XID		parentVisual = wVisual (pParent);
342
343	if (winVisual != parentVisual &&
344	    (compIsAlternateVisual (pScreen, winVisual) ||
345	     compIsAlternateVisual (pScreen, parentVisual)))
346	    return TRUE;
347    }
348    return FALSE;
349}
350
351void
352compMoveWindow (WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
353{
354    ScreenPtr		pScreen = pWin->drawable.pScreen;
355    CompScreenPtr	cs = GetCompScreen (pScreen);
356
357    compCheckTree (pScreen);
358    if (pWin->redirectDraw != RedirectDrawNone)
359    {
360	WindowPtr		pParent;
361	int			draw_x, draw_y;
362	unsigned int		w, h, bw;
363
364	/* if this is a root window, can't be moved */
365	if (!(pParent = pWin->parent))
366	   return;
367
368	bw = wBorderWidth (pWin);
369	draw_x = pParent->drawable.x + x + (int)bw;
370	draw_y = pParent->drawable.y + y + (int)bw;
371	w = pWin->drawable.width;
372	h = pWin->drawable.height;
373	compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
374    }
375    compCheckTree (pScreen);
376
377    pScreen->MoveWindow = cs->MoveWindow;
378    (*pScreen->MoveWindow) (pWin, x, y, pSib, kind);
379    cs->MoveWindow = pScreen->MoveWindow;
380    pScreen->MoveWindow = compMoveWindow;
381
382    if (pWin->redirectDraw != RedirectDrawNone)
383    {
384	CompWindowPtr	cw = GetCompWindow (pWin);
385	if (cw->pOldPixmap)
386	{
387	    (*pScreen->DestroyPixmap) (cw->pOldPixmap);
388	    cw->pOldPixmap = NullPixmap;
389	}
390    }
391
392    compCheckTree (pScreen);
393}
394
395void
396compResizeWindow (WindowPtr pWin, int x, int y,
397		  unsigned int w, unsigned int h, WindowPtr pSib)
398{
399    ScreenPtr		pScreen = pWin->drawable.pScreen;
400    CompScreenPtr	cs = GetCompScreen (pScreen);
401
402    compCheckTree (pScreen);
403    if (pWin->redirectDraw != RedirectDrawNone)
404    {
405	WindowPtr		pParent;
406	int			draw_x, draw_y;
407	unsigned int		bw;
408
409	/* if this is a root window, can't be moved */
410	if (!(pParent = pWin->parent))
411	   return;
412
413	bw = wBorderWidth (pWin);
414	draw_x = pParent->drawable.x + x + (int)bw;
415	draw_y = pParent->drawable.y + y + (int)bw;
416	compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
417    }
418    compCheckTree (pScreen);
419
420    pScreen->ResizeWindow = cs->ResizeWindow;
421    (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib);
422    cs->ResizeWindow = pScreen->ResizeWindow;
423    pScreen->ResizeWindow = compResizeWindow;
424    if (pWin->redirectDraw != RedirectDrawNone)
425    {
426	CompWindowPtr	cw = GetCompWindow (pWin);
427	if (cw->pOldPixmap)
428	{
429	    (*pScreen->DestroyPixmap) (cw->pOldPixmap);
430	    cw->pOldPixmap = NullPixmap;
431	}
432    }
433    compCheckTree (pWin->drawable.pScreen);
434}
435
436void
437compChangeBorderWidth (WindowPtr pWin, unsigned int bw)
438{
439    ScreenPtr		pScreen = pWin->drawable.pScreen;
440    CompScreenPtr	cs = GetCompScreen (pScreen);
441
442    compCheckTree (pScreen);
443    if (pWin->redirectDraw != RedirectDrawNone)
444    {
445	WindowPtr		pParent;
446	int			draw_x, draw_y;
447	unsigned int		w, h;
448
449	/* if this is a root window, can't be moved */
450	if (!(pParent = pWin->parent))
451	   return;
452
453	draw_x = pWin->drawable.x;
454	draw_y = pWin->drawable.y;
455	w = pWin->drawable.width;
456	h = pWin->drawable.height;
457	compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
458    }
459    compCheckTree (pScreen);
460
461    pScreen->ChangeBorderWidth = cs->ChangeBorderWidth;
462    (*pScreen->ChangeBorderWidth) (pWin, bw);
463    cs->ChangeBorderWidth = pScreen->ChangeBorderWidth;
464    pScreen->ChangeBorderWidth = compChangeBorderWidth;
465    if (pWin->redirectDraw != RedirectDrawNone)
466    {
467	CompWindowPtr	cw = GetCompWindow (pWin);
468	if (cw->pOldPixmap)
469	{
470	    (*pScreen->DestroyPixmap) (cw->pOldPixmap);
471	    cw->pOldPixmap = NullPixmap;
472	}
473    }
474    compCheckTree (pWin->drawable.pScreen);
475}
476
477void
478compReparentWindow (WindowPtr pWin, WindowPtr pPriorParent)
479{
480    ScreenPtr		pScreen = pWin->drawable.pScreen;
481    CompScreenPtr	cs = GetCompScreen (pScreen);
482
483    pScreen->ReparentWindow = cs->ReparentWindow;
484    /*
485     * Remove any implicit redirect due to synthesized visual
486     */
487    if (compImplicitRedirect (pWin, pPriorParent))
488	compUnredirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
489    /*
490     * Handle subwindows redirection
491     */
492    compUnredirectOneSubwindow (pPriorParent, pWin);
493    compRedirectOneSubwindow (pWin->parent, pWin);
494    /*
495     * Add any implict redirect due to synthesized visual
496     */
497    if (compImplicitRedirect (pWin, pWin->parent))
498	compRedirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
499
500    /*
501     * Allocate any necessary redirect pixmap
502     * (this actually should never be true; pWin is always unmapped)
503     */
504    compCheckRedirect (pWin);
505
506    /*
507     * Reset pixmap pointers as appropriate
508     */
509    if (pWin->parent && pWin->redirectDraw == RedirectDrawNone)
510	compSetPixmap (pWin, (*pScreen->GetWindowPixmap) (pWin->parent));
511    /*
512     * Call down to next function
513     */
514    if (pScreen->ReparentWindow)
515	(*pScreen->ReparentWindow) (pWin, pPriorParent);
516    cs->ReparentWindow = pScreen->ReparentWindow;
517    pScreen->ReparentWindow = compReparentWindow;
518    compCheckTree (pWin->drawable.pScreen);
519}
520
521void
522compCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
523{
524    ScreenPtr	    pScreen = pWin->drawable.pScreen;
525    CompScreenPtr   cs = GetCompScreen (pScreen);
526    int		    dx = 0, dy = 0;
527
528    if (pWin->redirectDraw != RedirectDrawNone)
529    {
530	PixmapPtr	pPixmap = (*pScreen->GetWindowPixmap) (pWin);
531	CompWindowPtr	cw = GetCompWindow (pWin);
532
533	assert (cw->oldx != COMP_ORIGIN_INVALID);
534	assert (cw->oldy != COMP_ORIGIN_INVALID);
535	if (cw->pOldPixmap)
536	{
537	    /*
538	     * Ok, the old bits are available in pOldPixmap and
539	     * need to be copied to pNewPixmap.
540	     */
541	    RegionRec	rgnDst;
542	    PixmapPtr	pPixmap = (*pScreen->GetWindowPixmap) (pWin);
543	    GCPtr	pGC;
544
545	    dx = ptOldOrg.x - pWin->drawable.x;
546	    dy = ptOldOrg.y - pWin->drawable.y;
547	    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
548
549	    REGION_NULL (pWin->drawable.pScreen, &rgnDst);
550
551	    REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst,
552			     &pWin->borderClip, prgnSrc);
553
554	    REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
555			      -pPixmap->screen_x, -pPixmap->screen_y);
556
557	    dx = dx + pPixmap->screen_x - cw->oldx;
558	    dy = dy + pPixmap->screen_y - cw->oldy;
559	    pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
560	    if (pGC)
561	    {
562		BoxPtr	pBox = REGION_RECTS (&rgnDst);
563		int	nBox = REGION_NUM_RECTS (&rgnDst);
564
565		ValidateGC(&pPixmap->drawable, pGC);
566		while (nBox--)
567		{
568		    (void) (*pGC->ops->CopyArea) (&cw->pOldPixmap->drawable,
569						  &pPixmap->drawable,
570						  pGC,
571						  pBox->x1 + dx, pBox->y1 + dy,
572						  pBox->x2 - pBox->x1,
573						  pBox->y2 - pBox->y1,
574						  pBox->x1, pBox->y1);
575		    pBox++;
576		}
577		FreeScratchGC (pGC);
578	    }
579	    return;
580	}
581	dx = pPixmap->screen_x - cw->oldx;
582	dy = pPixmap->screen_y - cw->oldy;
583	ptOldOrg.x += dx;
584	ptOldOrg.y += dy;
585    }
586
587    pScreen->CopyWindow = cs->CopyWindow;
588    if (ptOldOrg.x != pWin->drawable.x || ptOldOrg.y != pWin->drawable.y)
589    {
590	if (dx || dy)
591	    REGION_TRANSLATE (pScreen, prgnSrc, dx, dy);
592	(*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc);
593	if (dx || dy)
594	    REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
595    }
596    else
597    {
598	ptOldOrg.x -= dx;
599	ptOldOrg.y -= dy;
600	REGION_TRANSLATE (prgnSrc, prgnSrc,
601			  pWin->drawable.x - ptOldOrg.x,
602			  pWin->drawable.y - ptOldOrg.y);
603	DamageDamageRegion (&pWin->drawable, prgnSrc);
604    }
605    cs->CopyWindow = pScreen->CopyWindow;
606    pScreen->CopyWindow = compCopyWindow;
607    compCheckTree (pWin->drawable.pScreen);
608}
609
610Bool
611compCreateWindow (WindowPtr pWin)
612{
613    ScreenPtr		pScreen = pWin->drawable.pScreen;
614    CompScreenPtr	cs = GetCompScreen (pScreen);
615    Bool		ret;
616
617    pScreen->CreateWindow = cs->CreateWindow;
618    ret = (*pScreen->CreateWindow) (pWin);
619    if (pWin->parent && ret)
620    {
621	CompSubwindowsPtr	csw = GetCompSubwindows (pWin->parent);
622        CompClientWindowPtr	ccw;
623
624	(*pScreen->SetWindowPixmap) (pWin, (*pScreen->GetWindowPixmap) (pWin->parent));
625	if (csw)
626	    for (ccw = csw->clients; ccw; ccw = ccw->next)
627		compRedirectWindow (clients[CLIENT_ID(ccw->id)],
628				    pWin, ccw->update);
629	if (compImplicitRedirect (pWin, pWin->parent))
630	    compRedirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
631    }
632    cs->CreateWindow = pScreen->CreateWindow;
633    pScreen->CreateWindow = compCreateWindow;
634    compCheckTree (pWin->drawable.pScreen);
635    return ret;
636}
637
638Bool
639compDestroyWindow (WindowPtr pWin)
640{
641    ScreenPtr		pScreen = pWin->drawable.pScreen;
642    CompScreenPtr	cs = GetCompScreen (pScreen);
643    CompWindowPtr	cw;
644    CompSubwindowsPtr	csw;
645    Bool		ret;
646
647    pScreen->DestroyWindow = cs->DestroyWindow;
648    while ((cw = GetCompWindow (pWin)))
649	FreeResource (cw->clients->id, RT_NONE);
650    while ((csw = GetCompSubwindows (pWin)))
651	FreeResource (csw->clients->id, RT_NONE);
652
653    if (pWin->redirectDraw != RedirectDrawNone)
654	compFreePixmap (pWin);
655    ret = (*pScreen->DestroyWindow) (pWin);
656    cs->DestroyWindow = pScreen->DestroyWindow;
657    pScreen->DestroyWindow = compDestroyWindow;
658/*    compCheckTree (pWin->drawable.pScreen); can't check -- tree isn't good*/
659    return ret;
660}
661
662void
663compSetRedirectBorderClip (WindowPtr pWin, RegionPtr pRegion)
664{
665    CompWindowPtr   cw = GetCompWindow (pWin);
666    RegionRec	    damage;
667
668    REGION_NULL (pScreen, &damage);
669    /*
670     * Align old border clip with new border clip
671     */
672    REGION_TRANSLATE (pScreen, &cw->borderClip,
673		      pWin->drawable.x - cw->borderClipX,
674		      pWin->drawable.y - cw->borderClipY);
675    /*
676     * Compute newly visible portion of window for repaint
677     */
678    REGION_SUBTRACT (pScreen, &damage, pRegion, &cw->borderClip);
679    /*
680     * Report that as damaged so it will be redrawn
681     */
682    DamageDamageRegion (&pWin->drawable, &damage);
683    REGION_UNINIT (pScreen, &damage);
684    /*
685     * Save the new border clip region
686     */
687    REGION_COPY (pScreen, &cw->borderClip, pRegion);
688    cw->borderClipX = pWin->drawable.x;
689    cw->borderClipY = pWin->drawable.y;
690}
691
692RegionPtr
693compGetRedirectBorderClip (WindowPtr pWin)
694{
695    CompWindowPtr   cw = GetCompWindow (pWin);
696
697    return &cw->borderClip;
698}
699
700static VisualPtr
701compGetWindowVisual (WindowPtr pWin)
702{
703    ScreenPtr	    pScreen = pWin->drawable.pScreen;
704    VisualID	    vid = wVisual (pWin);
705    int		    i;
706
707    for (i = 0; i < pScreen->numVisuals; i++)
708	if (pScreen->visuals[i].vid == vid)
709	    return &pScreen->visuals[i];
710    return 0;
711}
712
713PictFormatPtr
714compWindowFormat (WindowPtr pWin)
715{
716    ScreenPtr	pScreen = pWin->drawable.pScreen;
717
718    return PictureMatchVisual (pScreen, pWin->drawable.depth,
719			       compGetWindowVisual (pWin));
720}
721
722static void
723compWindowUpdateAutomatic (WindowPtr pWin)
724{
725    CompWindowPtr   cw = GetCompWindow (pWin);
726    ScreenPtr	    pScreen = pWin->drawable.pScreen;
727    WindowPtr	    pParent = pWin->parent;
728    PixmapPtr	    pSrcPixmap = (*pScreen->GetWindowPixmap) (pWin);
729    PictFormatPtr   pSrcFormat = compWindowFormat (pWin);
730    PictFormatPtr   pDstFormat = compWindowFormat (pWin->parent);
731    int		    error;
732    RegionPtr	    pRegion = DamageRegion (cw->damage);
733    PicturePtr	    pSrcPicture = CreatePicture (0, &pSrcPixmap->drawable,
734						 pSrcFormat,
735						 0, 0,
736						 serverClient,
737						 &error);
738    XID		    subwindowMode = IncludeInferiors;
739    PicturePtr	    pDstPicture = CreatePicture (0, &pParent->drawable,
740						 pDstFormat,
741						 CPSubwindowMode,
742						 &subwindowMode,
743						 serverClient,
744						 &error);
745
746    /*
747     * First move the region from window to screen coordinates
748     */
749    REGION_TRANSLATE (pScreen, pRegion,
750		      pWin->drawable.x, pWin->drawable.y);
751
752    /*
753     * Clip against the "real" border clip
754     */
755    REGION_INTERSECT (pScreen, pRegion, pRegion, &cw->borderClip);
756
757    /*
758     * Now translate from screen to dest coordinates
759     */
760    REGION_TRANSLATE (pScreen, pRegion,
761		      -pParent->drawable.x, -pParent->drawable.y);
762
763    /*
764     * Clip the picture
765     */
766    SetPictureClipRegion (pDstPicture, 0, 0, pRegion);
767
768    /*
769     * And paint
770     */
771    CompositePicture (PictOpSrc,
772		      pSrcPicture,
773		      0,
774		      pDstPicture,
775		      0, 0, /* src_x, src_y */
776		      0, 0, /* msk_x, msk_y */
777		      pSrcPixmap->screen_x - pParent->drawable.x,
778		      pSrcPixmap->screen_y - pParent->drawable.y,
779		      pSrcPixmap->drawable.width,
780		      pSrcPixmap->drawable.height);
781    FreePicture (pSrcPicture, 0);
782    FreePicture (pDstPicture, 0);
783    /*
784     * Empty the damage region.  This has the nice effect of
785     * rendering the translations above harmless
786     */
787    DamageEmpty (cw->damage);
788}
789
790void
791compWindowUpdate (WindowPtr pWin)
792{
793    WindowPtr	pChild;
794
795    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
796	compWindowUpdate (pChild);
797    if (pWin->redirectDraw != RedirectDrawNone)
798    {
799	CompWindowPtr	cw = GetCompWindow(pWin);
800
801	if (cw->damaged)
802	{
803	    compWindowUpdateAutomatic (pWin);
804	    cw->damaged = FALSE;
805	}
806    }
807}
808
809WindowPtr
810CompositeRealChildHead (WindowPtr pWin)
811{
812    WindowPtr pChild, pChildBefore;
813    CompScreenPtr cs;
814
815    if (!pWin->parent &&
816	(screenIsSaved == SCREEN_SAVER_ON) &&
817	(HasSaverWindow (pWin->drawable.pScreen->myNum))) {
818
819	/* First child is the screen saver; see if next child is the overlay */
820	pChildBefore = pWin->firstChild;
821	pChild = pChildBefore->nextSib;
822
823    } else {
824	pChildBefore = NullWindow;
825	pChild = pWin->firstChild;
826    }
827
828    if (!pChild) {
829	return NullWindow;
830    }
831
832    cs = GetCompScreen(pWin->drawable.pScreen);
833    if (pChild == cs->pOverlayWin) {
834	return pChild;
835    } else {
836	return pChildBefore;
837    }
838}
839