1706f2543Smrg/*
2706f2543Smrg * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Software"),
6706f2543Smrg * to deal in the Software without restriction, including without limitation
7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, subject to the following conditions:
10706f2543Smrg *
11706f2543Smrg * The above copyright notice and this permission notice (including the next
12706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the
13706f2543Smrg * Software.
14706f2543Smrg *
15706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21706f2543Smrg * DEALINGS IN THE SOFTWARE.
22706f2543Smrg *
23706f2543Smrg * Copyright © 2003 Keith Packard
24706f2543Smrg *
25706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
26706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
27706f2543Smrg * the above copyright notice appear in all copies and that both that
28706f2543Smrg * copyright notice and this permission notice appear in supporting
29706f2543Smrg * documentation, and that the name of Keith Packard not be used in
30706f2543Smrg * advertising or publicity pertaining to distribution of the software without
31706f2543Smrg * specific, written prior permission.  Keith Packard makes no
32706f2543Smrg * representations about the suitability of this software for any purpose.  It
33706f2543Smrg * is provided "as is" without express or implied warranty.
34706f2543Smrg *
35706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
36706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
37706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
38706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
39706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
40706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
42706f2543Smrg */
43706f2543Smrg
44706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
45706f2543Smrg#include <dix-config.h>
46706f2543Smrg#endif
47706f2543Smrg
48706f2543Smrg#include "compint.h"
49706f2543Smrg
50706f2543Smrgstatic void
51706f2543SmrgcompScreenUpdate (ScreenPtr pScreen)
52706f2543Smrg{
53706f2543Smrg    compCheckTree (pScreen);
54706f2543Smrg    compPaintChildrenToWindow (pScreen->root);
55706f2543Smrg}
56706f2543Smrg
57706f2543Smrgstatic void
58706f2543SmrgcompBlockHandler (int	    i,
59706f2543Smrg		  pointer   blockData,
60706f2543Smrg		  pointer   pTimeout,
61706f2543Smrg		  pointer   pReadmask)
62706f2543Smrg{
63706f2543Smrg    ScreenPtr	    pScreen = screenInfo.screens[i];
64706f2543Smrg    CompScreenPtr   cs = GetCompScreen (pScreen);
65706f2543Smrg
66706f2543Smrg    pScreen->BlockHandler = cs->BlockHandler;
67706f2543Smrg    compScreenUpdate (pScreen);
68706f2543Smrg    (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
69706f2543Smrg
70706f2543Smrg    /* Next damage will restore the block handler */
71706f2543Smrg    cs->BlockHandler = NULL;
72706f2543Smrg}
73706f2543Smrg
74706f2543Smrgstatic void
75706f2543SmrgcompReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
76706f2543Smrg{
77706f2543Smrg    WindowPtr	    pWin = (WindowPtr) closure;
78706f2543Smrg    ScreenPtr	    pScreen = pWin->drawable.pScreen;
79706f2543Smrg    CompScreenPtr   cs = GetCompScreen (pScreen);
80706f2543Smrg    CompWindowPtr   cw = GetCompWindow (pWin);
81706f2543Smrg
82706f2543Smrg    if (!cs->BlockHandler) {
83706f2543Smrg        cs->BlockHandler = pScreen->BlockHandler;
84706f2543Smrg        pScreen->BlockHandler = compBlockHandler;
85706f2543Smrg    }
86706f2543Smrg    cw->damaged = TRUE;
87706f2543Smrg
88706f2543Smrg    /* Mark the ancestors */
89706f2543Smrg    pWin = pWin->parent;
90706f2543Smrg    while (pWin) {
91706f2543Smrg	if (pWin->damagedDescendants)
92706f2543Smrg	    break;
93706f2543Smrg	pWin->damagedDescendants = TRUE;
94706f2543Smrg	pWin = pWin->parent;
95706f2543Smrg    }
96706f2543Smrg}
97706f2543Smrg
98706f2543Smrgstatic void
99706f2543SmrgcompDestroyDamage (DamagePtr pDamage, void *closure)
100706f2543Smrg{
101706f2543Smrg    WindowPtr	    pWin = (WindowPtr) closure;
102706f2543Smrg    CompWindowPtr   cw = GetCompWindow (pWin);
103706f2543Smrg
104706f2543Smrg    cw->damage = 0;
105706f2543Smrg}
106706f2543Smrg
107706f2543Smrg/*
108706f2543Smrg * Redirect one window for one client
109706f2543Smrg */
110706f2543Smrgint
111706f2543SmrgcompRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
112706f2543Smrg{
113706f2543Smrg    CompWindowPtr	cw = GetCompWindow (pWin);
114706f2543Smrg    CompClientWindowPtr	ccw;
115706f2543Smrg    Bool		wasMapped = pWin->mapped;
116706f2543Smrg    CompScreenPtr       cs = GetCompScreen(pWin->drawable.pScreen);
117706f2543Smrg
118706f2543Smrg    if (pWin == cs->pOverlayWin) {
119706f2543Smrg	return Success;
120706f2543Smrg    }
121706f2543Smrg
122706f2543Smrg    if (!pWin->parent)
123706f2543Smrg	return BadMatch;
124706f2543Smrg
125706f2543Smrg    /*
126706f2543Smrg     * Only one Manual update is allowed
127706f2543Smrg     */
128706f2543Smrg    if (cw && update == CompositeRedirectManual)
129706f2543Smrg	for (ccw = cw->clients; ccw; ccw = ccw->next)
130706f2543Smrg	    if (ccw->update == CompositeRedirectManual)
131706f2543Smrg		return BadAccess;
132706f2543Smrg
133706f2543Smrg    /*
134706f2543Smrg     * Allocate per-client per-window structure
135706f2543Smrg     * The client *could* allocate multiple, but while supported,
136706f2543Smrg     * it is not expected to be common
137706f2543Smrg     */
138706f2543Smrg    ccw = malloc(sizeof (CompClientWindowRec));
139706f2543Smrg    if (!ccw)
140706f2543Smrg	return BadAlloc;
141706f2543Smrg    ccw->id = FakeClientID (pClient->index);
142706f2543Smrg    ccw->update = update;
143706f2543Smrg    /*
144706f2543Smrg     * Now make sure there's a per-window structure to hang this from
145706f2543Smrg     */
146706f2543Smrg    if (!cw)
147706f2543Smrg    {
148706f2543Smrg	cw = malloc(sizeof (CompWindowRec));
149706f2543Smrg	if (!cw)
150706f2543Smrg	{
151706f2543Smrg	    free(ccw);
152706f2543Smrg	    return BadAlloc;
153706f2543Smrg	}
154706f2543Smrg	cw->damage = DamageCreate (compReportDamage,
155706f2543Smrg				   compDestroyDamage,
156706f2543Smrg				   DamageReportNonEmpty,
157706f2543Smrg				   FALSE,
158706f2543Smrg				   pWin->drawable.pScreen,
159706f2543Smrg				   pWin);
160706f2543Smrg	if (!cw->damage)
161706f2543Smrg	{
162706f2543Smrg	    free(ccw);
163706f2543Smrg	    free(cw);
164706f2543Smrg	    return BadAlloc;
165706f2543Smrg	}
166706f2543Smrg	if (wasMapped)
167706f2543Smrg	{
168706f2543Smrg	    DisableMapUnmapEvents (pWin);
169706f2543Smrg	    UnmapWindow (pWin, FALSE);
170706f2543Smrg	    EnableMapUnmapEvents (pWin);
171706f2543Smrg	}
172706f2543Smrg
173706f2543Smrg	RegionNull(&cw->borderClip);
174706f2543Smrg	cw->borderClipX = 0;
175706f2543Smrg	cw->borderClipY = 0;
176706f2543Smrg	cw->update = CompositeRedirectAutomatic;
177706f2543Smrg	cw->clients = 0;
178706f2543Smrg	cw->oldx = COMP_ORIGIN_INVALID;
179706f2543Smrg	cw->oldy = COMP_ORIGIN_INVALID;
180706f2543Smrg	cw->damageRegistered = FALSE;
181706f2543Smrg	cw->damaged = FALSE;
182706f2543Smrg	cw->pOldPixmap = NullPixmap;
183706f2543Smrg	dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw);
184706f2543Smrg    }
185706f2543Smrg    ccw->next = cw->clients;
186706f2543Smrg    cw->clients = ccw;
187706f2543Smrg    if (!AddResource (ccw->id, CompositeClientWindowType, pWin))
188706f2543Smrg	return BadAlloc;
189706f2543Smrg    if (ccw->update == CompositeRedirectManual)
190706f2543Smrg    {
191706f2543Smrg	/* If the window was CompositeRedirectAutomatic, then
192706f2543Smrg	 * unmap the window so that the parent clip list will
193706f2543Smrg	 * be correctly recomputed.
194706f2543Smrg	 */
195706f2543Smrg	if (pWin->mapped)
196706f2543Smrg	{
197706f2543Smrg	    DisableMapUnmapEvents (pWin);
198706f2543Smrg	    UnmapWindow (pWin, FALSE);
199706f2543Smrg	    EnableMapUnmapEvents (pWin);
200706f2543Smrg	}
201706f2543Smrg	if (cw->damageRegistered)
202706f2543Smrg	{
203706f2543Smrg	    DamageUnregister (&pWin->drawable, cw->damage);
204706f2543Smrg	    cw->damageRegistered = FALSE;
205706f2543Smrg	}
206706f2543Smrg	cw->update = CompositeRedirectManual;
207706f2543Smrg    }
208706f2543Smrg
209706f2543Smrg    if (!compCheckRedirect (pWin))
210706f2543Smrg    {
211706f2543Smrg	FreeResource (ccw->id, RT_NONE);
212706f2543Smrg	return BadAlloc;
213706f2543Smrg    }
214706f2543Smrg    if (wasMapped && !pWin->mapped)
215706f2543Smrg    {
216706f2543Smrg	Bool	overrideRedirect = pWin->overrideRedirect;
217706f2543Smrg	pWin->overrideRedirect = TRUE;
218706f2543Smrg	DisableMapUnmapEvents (pWin);
219706f2543Smrg	MapWindow (pWin, pClient);
220706f2543Smrg	EnableMapUnmapEvents (pWin);
221706f2543Smrg	pWin->overrideRedirect = overrideRedirect;
222706f2543Smrg    }
223706f2543Smrg
224706f2543Smrg    return Success;
225706f2543Smrg}
226706f2543Smrg
227706f2543Smrg/*
228706f2543Smrg * Free one of the per-client per-window resources, clearing
229706f2543Smrg * redirect and the per-window pointer as appropriate
230706f2543Smrg */
231706f2543Smrgvoid
232706f2543SmrgcompFreeClientWindow (WindowPtr pWin, XID id)
233706f2543Smrg{
234706f2543Smrg    CompWindowPtr	cw = GetCompWindow (pWin);
235706f2543Smrg    CompClientWindowPtr	ccw, *prev;
236706f2543Smrg    Bool		wasMapped = pWin->mapped;
237706f2543Smrg
238706f2543Smrg    if (!cw)
239706f2543Smrg	return;
240706f2543Smrg    for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next)
241706f2543Smrg    {
242706f2543Smrg	if (ccw->id == id)
243706f2543Smrg	{
244706f2543Smrg	    *prev = ccw->next;
245706f2543Smrg	    if (ccw->update == CompositeRedirectManual)
246706f2543Smrg		cw->update = CompositeRedirectAutomatic;
247706f2543Smrg	    free(ccw);
248706f2543Smrg	    break;
249706f2543Smrg	}
250706f2543Smrg    }
251706f2543Smrg    if (!cw->clients)
252706f2543Smrg    {
253706f2543Smrg	if (wasMapped)
254706f2543Smrg	{
255706f2543Smrg	    DisableMapUnmapEvents (pWin);
256706f2543Smrg	    UnmapWindow (pWin, FALSE);
257706f2543Smrg	    EnableMapUnmapEvents (pWin);
258706f2543Smrg	}
259706f2543Smrg
260706f2543Smrg	if (pWin->redirectDraw != RedirectDrawNone)
261706f2543Smrg	    compFreePixmap (pWin);
262706f2543Smrg
263706f2543Smrg	if (cw->damage)
264706f2543Smrg	    DamageDestroy (cw->damage);
265706f2543Smrg
266706f2543Smrg	RegionUninit(&cw->borderClip);
267706f2543Smrg
268706f2543Smrg	dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL);
269706f2543Smrg	free(cw);
270706f2543Smrg    }
271706f2543Smrg    else if (cw->update == CompositeRedirectAutomatic &&
272706f2543Smrg	     !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone)
273706f2543Smrg    {
274706f2543Smrg	DamageRegister (&pWin->drawable, cw->damage);
275706f2543Smrg	cw->damageRegistered = TRUE;
276706f2543Smrg	pWin->redirectDraw = RedirectDrawAutomatic;
277706f2543Smrg	DamageDamageRegion(&pWin->drawable, &pWin->borderSize);
278706f2543Smrg    }
279706f2543Smrg    if (wasMapped && !pWin->mapped)
280706f2543Smrg    {
281706f2543Smrg	Bool	overrideRedirect = pWin->overrideRedirect;
282706f2543Smrg	pWin->overrideRedirect = TRUE;
283706f2543Smrg	DisableMapUnmapEvents (pWin);
284706f2543Smrg	MapWindow (pWin, clients[CLIENT_ID(id)]);
285706f2543Smrg	EnableMapUnmapEvents (pWin);
286706f2543Smrg	pWin->overrideRedirect = overrideRedirect;
287706f2543Smrg    }
288706f2543Smrg}
289706f2543Smrg
290706f2543Smrg/*
291706f2543Smrg * This is easy, just free the appropriate resource.
292706f2543Smrg */
293706f2543Smrg
294706f2543Smrgint
295706f2543SmrgcompUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
296706f2543Smrg{
297706f2543Smrg    CompWindowPtr	cw = GetCompWindow (pWin);
298706f2543Smrg    CompClientWindowPtr	ccw;
299706f2543Smrg
300706f2543Smrg    if (!cw)
301706f2543Smrg	return BadValue;
302706f2543Smrg
303706f2543Smrg    for (ccw = cw->clients; ccw; ccw = ccw->next)
304706f2543Smrg	if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
305706f2543Smrg	{
306706f2543Smrg	    FreeResource (ccw->id, RT_NONE);
307706f2543Smrg	    return Success;
308706f2543Smrg	}
309706f2543Smrg    return BadValue;
310706f2543Smrg}
311706f2543Smrg
312706f2543Smrg/*
313706f2543Smrg * Redirect all subwindows for one client
314706f2543Smrg */
315706f2543Smrg
316706f2543Smrgint
317706f2543SmrgcompRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
318706f2543Smrg{
319706f2543Smrg    CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
320706f2543Smrg    CompClientWindowPtr	ccw;
321706f2543Smrg    WindowPtr		pChild;
322706f2543Smrg
323706f2543Smrg    /*
324706f2543Smrg     * Only one Manual update is allowed
325706f2543Smrg     */
326706f2543Smrg    if (csw && update == CompositeRedirectManual)
327706f2543Smrg	for (ccw = csw->clients; ccw; ccw = ccw->next)
328706f2543Smrg	    if (ccw->update == CompositeRedirectManual)
329706f2543Smrg		return BadAccess;
330706f2543Smrg    /*
331706f2543Smrg     * Allocate per-client per-window structure
332706f2543Smrg     * The client *could* allocate multiple, but while supported,
333706f2543Smrg     * it is not expected to be common
334706f2543Smrg     */
335706f2543Smrg    ccw = malloc(sizeof (CompClientWindowRec));
336706f2543Smrg    if (!ccw)
337706f2543Smrg	return BadAlloc;
338706f2543Smrg    ccw->id = FakeClientID (pClient->index);
339706f2543Smrg    ccw->update = update;
340706f2543Smrg    /*
341706f2543Smrg     * Now make sure there's a per-window structure to hang this from
342706f2543Smrg     */
343706f2543Smrg    if (!csw)
344706f2543Smrg    {
345706f2543Smrg	csw = malloc(sizeof (CompSubwindowsRec));
346706f2543Smrg	if (!csw)
347706f2543Smrg	{
348706f2543Smrg	    free(ccw);
349706f2543Smrg	    return BadAlloc;
350706f2543Smrg	}
351706f2543Smrg	csw->update = CompositeRedirectAutomatic;
352706f2543Smrg	csw->clients = 0;
353706f2543Smrg	dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw);
354706f2543Smrg    }
355706f2543Smrg    /*
356706f2543Smrg     * Redirect all existing windows
357706f2543Smrg     */
358706f2543Smrg    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
359706f2543Smrg    {
360706f2543Smrg	int ret = compRedirectWindow (pClient, pChild, update);
361706f2543Smrg	if (ret != Success)
362706f2543Smrg	{
363706f2543Smrg	    for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
364706f2543Smrg		(void) compUnredirectWindow (pClient, pChild, update);
365706f2543Smrg	    if (!csw->clients)
366706f2543Smrg	    {
367706f2543Smrg		free(csw);
368706f2543Smrg		dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0);
369706f2543Smrg	    }
370706f2543Smrg	    free(ccw);
371706f2543Smrg	    return ret;
372706f2543Smrg	}
373706f2543Smrg    }
374706f2543Smrg    /*
375706f2543Smrg     * Hook into subwindows list
376706f2543Smrg     */
377706f2543Smrg    ccw->next = csw->clients;
378706f2543Smrg    csw->clients = ccw;
379706f2543Smrg    if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin))
380706f2543Smrg	return BadAlloc;
381706f2543Smrg    if (ccw->update == CompositeRedirectManual)
382706f2543Smrg    {
383706f2543Smrg	csw->update = CompositeRedirectManual;
384706f2543Smrg	/*
385706f2543Smrg	 * tell damage extension that damage events for this client are
386706f2543Smrg	 * critical output
387706f2543Smrg	 */
388706f2543Smrg	DamageExtSetCritical (pClient, TRUE);
389706f2543Smrg    }
390706f2543Smrg    return Success;
391706f2543Smrg}
392706f2543Smrg
393706f2543Smrg/*
394706f2543Smrg * Free one of the per-client per-subwindows resources,
395706f2543Smrg * which frees one redirect per subwindow
396706f2543Smrg */
397706f2543Smrgvoid
398706f2543SmrgcompFreeClientSubwindows (WindowPtr pWin, XID id)
399706f2543Smrg{
400706f2543Smrg    CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
401706f2543Smrg    CompClientWindowPtr	ccw, *prev;
402706f2543Smrg    WindowPtr		pChild;
403706f2543Smrg
404706f2543Smrg    if (!csw)
405706f2543Smrg	return;
406706f2543Smrg    for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next)
407706f2543Smrg    {
408706f2543Smrg	if (ccw->id == id)
409706f2543Smrg	{
410706f2543Smrg	    ClientPtr	pClient = clients[CLIENT_ID(id)];
411706f2543Smrg
412706f2543Smrg	    *prev = ccw->next;
413706f2543Smrg	    if (ccw->update == CompositeRedirectManual)
414706f2543Smrg	    {
415706f2543Smrg		/*
416706f2543Smrg		 * tell damage extension that damage events for this client are
417706f2543Smrg		 * critical output
418706f2543Smrg		 */
419706f2543Smrg		DamageExtSetCritical (pClient, FALSE);
420706f2543Smrg		csw->update = CompositeRedirectAutomatic;
421706f2543Smrg		if (pWin->mapped)
422706f2543Smrg		    (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE);
423706f2543Smrg	    }
424706f2543Smrg
425706f2543Smrg	    /*
426706f2543Smrg	     * Unredirect all existing subwindows
427706f2543Smrg	     */
428706f2543Smrg	    for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
429706f2543Smrg		(void) compUnredirectWindow (pClient, pChild, ccw->update);
430706f2543Smrg
431706f2543Smrg	    free(ccw);
432706f2543Smrg	    break;
433706f2543Smrg	}
434706f2543Smrg    }
435706f2543Smrg
436706f2543Smrg    /*
437706f2543Smrg     * Check if all of the per-client records are gone
438706f2543Smrg     */
439706f2543Smrg    if (!csw->clients)
440706f2543Smrg    {
441706f2543Smrg	dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL);
442706f2543Smrg	free(csw);
443706f2543Smrg    }
444706f2543Smrg}
445706f2543Smrg
446706f2543Smrg/*
447706f2543Smrg * This is easy, just free the appropriate resource.
448706f2543Smrg */
449706f2543Smrg
450706f2543Smrgint
451706f2543SmrgcompUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
452706f2543Smrg{
453706f2543Smrg    CompSubwindowsPtr	csw = GetCompSubwindows (pWin);
454706f2543Smrg    CompClientWindowPtr	ccw;
455706f2543Smrg
456706f2543Smrg    if (!csw)
457706f2543Smrg	return BadValue;
458706f2543Smrg    for (ccw = csw->clients; ccw; ccw = ccw->next)
459706f2543Smrg	if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
460706f2543Smrg	{
461706f2543Smrg	    FreeResource (ccw->id, RT_NONE);
462706f2543Smrg	    return Success;
463706f2543Smrg	}
464706f2543Smrg    return BadValue;
465706f2543Smrg}
466706f2543Smrg
467706f2543Smrg/*
468706f2543Smrg * Add redirection information for one subwindow (during reparent)
469706f2543Smrg */
470706f2543Smrg
471706f2543Smrgint
472706f2543SmrgcompRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
473706f2543Smrg{
474706f2543Smrg    CompSubwindowsPtr	csw = GetCompSubwindows (pParent);
475706f2543Smrg    CompClientWindowPtr	ccw;
476706f2543Smrg
477706f2543Smrg    if (!csw)
478706f2543Smrg	return Success;
479706f2543Smrg    for (ccw = csw->clients; ccw; ccw = ccw->next)
480706f2543Smrg    {
481706f2543Smrg	int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)],
482706f2543Smrg				      pWin, ccw->update);
483706f2543Smrg	if (ret != Success)
484706f2543Smrg	    return ret;
485706f2543Smrg    }
486706f2543Smrg    return Success;
487706f2543Smrg}
488706f2543Smrg
489706f2543Smrg/*
490706f2543Smrg * Remove redirection information for one subwindow (during reparent)
491706f2543Smrg */
492706f2543Smrg
493706f2543Smrgint
494706f2543SmrgcompUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
495706f2543Smrg{
496706f2543Smrg    CompSubwindowsPtr	csw = GetCompSubwindows (pParent);
497706f2543Smrg    CompClientWindowPtr	ccw;
498706f2543Smrg
499706f2543Smrg    if (!csw)
500706f2543Smrg	return Success;
501706f2543Smrg    for (ccw = csw->clients; ccw; ccw = ccw->next)
502706f2543Smrg    {
503706f2543Smrg	int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)],
504706f2543Smrg					pWin, ccw->update);
505706f2543Smrg	if (ret != Success)
506706f2543Smrg	    return ret;
507706f2543Smrg    }
508706f2543Smrg    return Success;
509706f2543Smrg}
510706f2543Smrg
511706f2543Smrgstatic int
512706f2543SmrgbgNoneVisitWindow(WindowPtr pWin, void *null)
513706f2543Smrg{
514706f2543Smrg    if (pWin->backgroundState != BackgroundPixmap)
515706f2543Smrg	return WT_WALKCHILDREN;
516706f2543Smrg    if (pWin->background.pixmap != None)
517706f2543Smrg	return WT_WALKCHILDREN;
518706f2543Smrg
519706f2543Smrg    return WT_STOPWALKING;
520706f2543Smrg}
521706f2543Smrg
522706f2543Smrgstatic PixmapPtr
523706f2543SmrgcompNewPixmap (WindowPtr pWin, int x, int y, int w, int h, Bool map)
524706f2543Smrg{
525706f2543Smrg    ScreenPtr	    pScreen = pWin->drawable.pScreen;
526706f2543Smrg    WindowPtr	    pParent = pWin->parent;
527706f2543Smrg    PixmapPtr	    pPixmap;
528706f2543Smrg
529706f2543Smrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth,
530706f2543Smrg					CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
531706f2543Smrg
532706f2543Smrg    if (!pPixmap)
533706f2543Smrg	return 0;
534706f2543Smrg
535706f2543Smrg    pPixmap->screen_x = x;
536706f2543Smrg    pPixmap->screen_y = y;
537706f2543Smrg
538706f2543Smrg    /* resize allocations will update later in compCopyWindow, not here */
539706f2543Smrg    if (!map)
540706f2543Smrg	return pPixmap;
541706f2543Smrg
542706f2543Smrg    /*
543706f2543Smrg     * If there's no bg=None in the tree, we're done.
544706f2543Smrg     *
545706f2543Smrg     * We could optimize this more by collection the regions of all the
546706f2543Smrg     * bg=None subwindows and feeding that in as the clip for the
547706f2543Smrg     * CopyArea below, but since window trees are shallow these days it
548706f2543Smrg     * might not be worth the effort.
549706f2543Smrg     */
550706f2543Smrg    if (TraverseTree(pWin, bgNoneVisitWindow, NULL) == WT_NOMATCH)
551706f2543Smrg	return pPixmap;
552706f2543Smrg
553706f2543Smrg    /*
554706f2543Smrg     * Copy bits from the parent into the new pixmap so that it will
555706f2543Smrg     * have "reasonable" contents in case for background None areas.
556706f2543Smrg     */
557706f2543Smrg    if (pParent->drawable.depth == pWin->drawable.depth)
558706f2543Smrg    {
559706f2543Smrg	GCPtr	pGC = GetScratchGC (pWin->drawable.depth, pScreen);
560706f2543Smrg
561706f2543Smrg	if (pGC)
562706f2543Smrg	{
563706f2543Smrg	    ChangeGCVal val;
564706f2543Smrg	    val.val = IncludeInferiors;
565706f2543Smrg
566706f2543Smrg	    ValidateGC(&pPixmap->drawable, pGC);
567706f2543Smrg	    ChangeGC (serverClient, pGC, GCSubwindowMode, &val);
568706f2543Smrg	    (*pGC->ops->CopyArea) (&pParent->drawable,
569706f2543Smrg				   &pPixmap->drawable,
570706f2543Smrg				   pGC,
571706f2543Smrg				   x - pParent->drawable.x,
572706f2543Smrg				   y - pParent->drawable.y,
573706f2543Smrg				   w, h, 0, 0);
574706f2543Smrg	    FreeScratchGC (pGC);
575706f2543Smrg	}
576706f2543Smrg    }
577706f2543Smrg    else
578706f2543Smrg    {
579706f2543Smrg	PictFormatPtr	pSrcFormat = compWindowFormat (pParent);
580706f2543Smrg	PictFormatPtr	pDstFormat = compWindowFormat (pWin);
581706f2543Smrg	XID		inferiors = IncludeInferiors;
582706f2543Smrg	int		error;
583706f2543Smrg
584706f2543Smrg	PicturePtr	pSrcPicture = CreatePicture (None,
585706f2543Smrg						     &pParent->drawable,
586706f2543Smrg						     pSrcFormat,
587706f2543Smrg						     CPSubwindowMode,
588706f2543Smrg						     &inferiors,
589706f2543Smrg						     serverClient, &error);
590706f2543Smrg
591706f2543Smrg	PicturePtr	pDstPicture = CreatePicture (None,
592706f2543Smrg						     &pPixmap->drawable,
593706f2543Smrg						     pDstFormat,
594706f2543Smrg						     0, 0,
595706f2543Smrg						     serverClient, &error);
596706f2543Smrg
597706f2543Smrg	if (pSrcPicture && pDstPicture)
598706f2543Smrg	{
599706f2543Smrg	    CompositePicture (PictOpSrc,
600706f2543Smrg			      pSrcPicture,
601706f2543Smrg			      NULL,
602706f2543Smrg			      pDstPicture,
603706f2543Smrg			      x - pParent->drawable.x,
604706f2543Smrg			      y - pParent->drawable.y,
605706f2543Smrg			      0, 0, 0, 0, w, h);
606706f2543Smrg	}
607706f2543Smrg	if (pSrcPicture)
608706f2543Smrg	    FreePicture (pSrcPicture, 0);
609706f2543Smrg	if (pDstPicture)
610706f2543Smrg	    FreePicture (pDstPicture, 0);
611706f2543Smrg    }
612706f2543Smrg    return pPixmap;
613706f2543Smrg}
614706f2543Smrg
615706f2543SmrgBool
616706f2543SmrgcompAllocPixmap (WindowPtr pWin)
617706f2543Smrg{
618706f2543Smrg    int		    bw = (int) pWin->borderWidth;
619706f2543Smrg    int		    x = pWin->drawable.x - bw;
620706f2543Smrg    int		    y = pWin->drawable.y - bw;
621706f2543Smrg    int		    w = pWin->drawable.width + (bw << 1);
622706f2543Smrg    int		    h = pWin->drawable.height + (bw << 1);
623706f2543Smrg    PixmapPtr	    pPixmap = compNewPixmap (pWin, x, y, w, h, TRUE);
624706f2543Smrg    CompWindowPtr   cw = GetCompWindow (pWin);
625706f2543Smrg
626706f2543Smrg    if (!pPixmap)
627706f2543Smrg	return FALSE;
628706f2543Smrg    if (cw->update == CompositeRedirectAutomatic)
629706f2543Smrg	pWin->redirectDraw = RedirectDrawAutomatic;
630706f2543Smrg    else
631706f2543Smrg	pWin->redirectDraw = RedirectDrawManual;
632706f2543Smrg
633706f2543Smrg    compSetPixmap (pWin, pPixmap);
634706f2543Smrg    cw->oldx = COMP_ORIGIN_INVALID;
635706f2543Smrg    cw->oldy = COMP_ORIGIN_INVALID;
636706f2543Smrg    cw->damageRegistered = FALSE;
637706f2543Smrg    if (cw->update == CompositeRedirectAutomatic)
638706f2543Smrg    {
639706f2543Smrg	DamageRegister (&pWin->drawable, cw->damage);
640706f2543Smrg	cw->damageRegistered = TRUE;
641706f2543Smrg    }
642706f2543Smrg    return TRUE;
643706f2543Smrg}
644706f2543Smrg
645706f2543Smrgvoid
646706f2543SmrgcompFreePixmap (WindowPtr pWin)
647706f2543Smrg{
648706f2543Smrg    ScreenPtr	    pScreen = pWin->drawable.pScreen;
649706f2543Smrg    PixmapPtr	    pRedirectPixmap, pParentPixmap;
650706f2543Smrg    CompWindowPtr   cw = GetCompWindow (pWin);
651706f2543Smrg
652706f2543Smrg    if (cw->damageRegistered)
653706f2543Smrg    {
654706f2543Smrg	DamageUnregister (&pWin->drawable, cw->damage);
655706f2543Smrg	cw->damageRegistered = FALSE;
656706f2543Smrg	DamageEmpty (cw->damage);
657706f2543Smrg    }
658706f2543Smrg    /*
659706f2543Smrg     * Move the parent-constrained border clip region back into
660706f2543Smrg     * the window so that ValidateTree will handle the unmap
661706f2543Smrg     * case correctly.  Unmap adds the window borderClip to the
662706f2543Smrg     * parent exposed area; regions beyond the parent cause crashes
663706f2543Smrg     */
664706f2543Smrg    RegionCopy(&pWin->borderClip, &cw->borderClip);
665706f2543Smrg    pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin);
666706f2543Smrg    pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
667706f2543Smrg    pWin->redirectDraw = RedirectDrawNone;
668706f2543Smrg    compSetPixmap (pWin, pParentPixmap);
669706f2543Smrg    (*pScreen->DestroyPixmap) (pRedirectPixmap);
670706f2543Smrg}
671706f2543Smrg
672706f2543Smrg/*
673706f2543Smrg * Make sure the pixmap is the right size and offset.  Allocate a new
674706f2543Smrg * pixmap to change size, adjust origin to change offset, leaving the
675706f2543Smrg * old pixmap in cw->pOldPixmap so bits can be recovered
676706f2543Smrg */
677706f2543SmrgBool
678706f2543SmrgcompReallocPixmap (WindowPtr pWin, int draw_x, int draw_y,
679706f2543Smrg		   unsigned int w, unsigned int h, int bw)
680706f2543Smrg{
681706f2543Smrg    ScreenPtr	    pScreen = pWin->drawable.pScreen;
682706f2543Smrg    PixmapPtr	    pOld = (*pScreen->GetWindowPixmap) (pWin);
683706f2543Smrg    PixmapPtr	    pNew;
684706f2543Smrg    CompWindowPtr   cw = GetCompWindow (pWin);
685706f2543Smrg    int		    pix_x, pix_y;
686706f2543Smrg    int		    pix_w, pix_h;
687706f2543Smrg
688706f2543Smrg    assert (cw && pWin->redirectDraw != RedirectDrawNone);
689706f2543Smrg    cw->oldx = pOld->screen_x;
690706f2543Smrg    cw->oldy = pOld->screen_y;
691706f2543Smrg    pix_x = draw_x - bw;
692706f2543Smrg    pix_y = draw_y - bw;
693706f2543Smrg    pix_w = w + (bw << 1);
694706f2543Smrg    pix_h = h + (bw << 1);
695706f2543Smrg    if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height)
696706f2543Smrg    {
697706f2543Smrg	pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h, FALSE);
698706f2543Smrg	if (!pNew)
699706f2543Smrg	    return FALSE;
700706f2543Smrg	cw->pOldPixmap = pOld;
701706f2543Smrg	compSetPixmap (pWin, pNew);
702706f2543Smrg    }
703706f2543Smrg    else
704706f2543Smrg    {
705706f2543Smrg	pNew = pOld;
706706f2543Smrg	cw->pOldPixmap = 0;
707706f2543Smrg    }
708706f2543Smrg    pNew->screen_x = pix_x;
709706f2543Smrg    pNew->screen_y = pix_y;
710706f2543Smrg    return TRUE;
711706f2543Smrg}
712