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