xref: /OK3568_Linux_fs/external/xserver/composite/compalloc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the next
12*4882a593Smuzhiyun  * paragraph) shall be included in all copies or substantial portions of the
13*4882a593Smuzhiyun  * Software.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*4882a593Smuzhiyun  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*4882a593Smuzhiyun  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*4882a593Smuzhiyun  * DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Copyright © 2003 Keith Packard
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * Permission to use, copy, modify, distribute, and sell this software and its
26*4882a593Smuzhiyun  * documentation for any purpose is hereby granted without fee, provided that
27*4882a593Smuzhiyun  * the above copyright notice appear in all copies and that both that
28*4882a593Smuzhiyun  * copyright notice and this permission notice appear in supporting
29*4882a593Smuzhiyun  * documentation, and that the name of Keith Packard not be used in
30*4882a593Smuzhiyun  * advertising or publicity pertaining to distribution of the software without
31*4882a593Smuzhiyun  * specific, written prior permission.  Keith Packard makes no
32*4882a593Smuzhiyun  * representations about the suitability of this software for any purpose.  It
33*4882a593Smuzhiyun  * is provided "as is" without express or implied warranty.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
36*4882a593Smuzhiyun  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
37*4882a593Smuzhiyun  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
38*4882a593Smuzhiyun  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
39*4882a593Smuzhiyun  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
40*4882a593Smuzhiyun  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
41*4882a593Smuzhiyun  * PERFORMANCE OF THIS SOFTWARE.
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
45*4882a593Smuzhiyun #include <dix-config.h>
46*4882a593Smuzhiyun #endif
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #include "compint.h"
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static Bool
compScreenUpdate(ClientPtr pClient,void * closure)51*4882a593Smuzhiyun compScreenUpdate(ClientPtr pClient, void *closure)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun     ScreenPtr pScreen = closure;
54*4882a593Smuzhiyun     CompScreenPtr cs = GetCompScreen(pScreen);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun     compCheckTree(pScreen);
57*4882a593Smuzhiyun     compPaintChildrenToWindow(pScreen->root);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun     /* Next damage will restore the worker */
60*4882a593Smuzhiyun     cs->pendingScreenUpdate = FALSE;
61*4882a593Smuzhiyun     return TRUE;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun void
compMarkAncestors(WindowPtr pWin)65*4882a593Smuzhiyun compMarkAncestors(WindowPtr pWin)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun     pWin = pWin->parent;
68*4882a593Smuzhiyun     while (pWin) {
69*4882a593Smuzhiyun         if (pWin->damagedDescendants)
70*4882a593Smuzhiyun             return;
71*4882a593Smuzhiyun         pWin->damagedDescendants = TRUE;
72*4882a593Smuzhiyun         pWin = pWin->parent;
73*4882a593Smuzhiyun     }
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun static void
compReportDamage(DamagePtr pDamage,RegionPtr pRegion,void * closure)77*4882a593Smuzhiyun compReportDamage(DamagePtr pDamage, RegionPtr pRegion, void *closure)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun     WindowPtr pWin = (WindowPtr) closure;
80*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
81*4882a593Smuzhiyun     CompScreenPtr cs = GetCompScreen(pScreen);
82*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun     if (!cs->pendingScreenUpdate) {
85*4882a593Smuzhiyun         QueueWorkProc(compScreenUpdate, serverClient, pScreen);
86*4882a593Smuzhiyun         cs->pendingScreenUpdate = TRUE;
87*4882a593Smuzhiyun     }
88*4882a593Smuzhiyun     cw->damaged = TRUE;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun     compMarkAncestors(pWin);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun static void
compDestroyDamage(DamagePtr pDamage,void * closure)94*4882a593Smuzhiyun compDestroyDamage(DamagePtr pDamage, void *closure)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun     WindowPtr pWin = (WindowPtr) closure;
97*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun     cw->damage = 0;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun static Bool
compMarkWindows(WindowPtr pWin,WindowPtr * ppLayerWin)103*4882a593Smuzhiyun compMarkWindows(WindowPtr pWin, WindowPtr *ppLayerWin)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
106*4882a593Smuzhiyun     WindowPtr pLayerWin = pWin;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun     if (!pWin->viewable)
109*4882a593Smuzhiyun         return FALSE;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun     (*pScreen->MarkOverlappedWindows) (pWin, pWin, &pLayerWin);
112*4882a593Smuzhiyun     (*pScreen->MarkWindow) (pLayerWin->parent);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun     *ppLayerWin = pLayerWin;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun     return TRUE;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static void
compHandleMarkedWindows(WindowPtr pWin,WindowPtr pLayerWin)120*4882a593Smuzhiyun compHandleMarkedWindows(WindowPtr pWin, WindowPtr pLayerWin)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun     (*pScreen->ValidateTree) (pLayerWin->parent, pLayerWin, VTOther);
125*4882a593Smuzhiyun     (*pScreen->HandleExposures) (pLayerWin->parent);
126*4882a593Smuzhiyun     if (pScreen->PostValidateTree)
127*4882a593Smuzhiyun         (*pScreen->PostValidateTree) (pLayerWin->parent, pLayerWin, VTOther);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun /*
131*4882a593Smuzhiyun  * Redirect one window for one client
132*4882a593Smuzhiyun  */
133*4882a593Smuzhiyun int
compRedirectWindow(ClientPtr pClient,WindowPtr pWin,int update)134*4882a593Smuzhiyun compRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
137*4882a593Smuzhiyun     CompClientWindowPtr ccw;
138*4882a593Smuzhiyun     CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
139*4882a593Smuzhiyun     WindowPtr pLayerWin;
140*4882a593Smuzhiyun     Bool anyMarked = FALSE;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun     if (pWin == cs->pOverlayWin) {
143*4882a593Smuzhiyun         return Success;
144*4882a593Smuzhiyun     }
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun     if (!pWin->parent)
147*4882a593Smuzhiyun         return BadMatch;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun     /*
150*4882a593Smuzhiyun      * Only one Manual update is allowed
151*4882a593Smuzhiyun      */
152*4882a593Smuzhiyun     if (cw && update == CompositeRedirectManual)
153*4882a593Smuzhiyun         for (ccw = cw->clients; ccw; ccw = ccw->next)
154*4882a593Smuzhiyun             if (ccw->update == CompositeRedirectManual)
155*4882a593Smuzhiyun                 return BadAccess;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun     /*
158*4882a593Smuzhiyun      * Allocate per-client per-window structure
159*4882a593Smuzhiyun      * The client *could* allocate multiple, but while supported,
160*4882a593Smuzhiyun      * it is not expected to be common
161*4882a593Smuzhiyun      */
162*4882a593Smuzhiyun     ccw = malloc(sizeof(CompClientWindowRec));
163*4882a593Smuzhiyun     if (!ccw)
164*4882a593Smuzhiyun         return BadAlloc;
165*4882a593Smuzhiyun     ccw->id = FakeClientID(pClient->index);
166*4882a593Smuzhiyun     ccw->update = update;
167*4882a593Smuzhiyun     /*
168*4882a593Smuzhiyun      * Now make sure there's a per-window structure to hang this from
169*4882a593Smuzhiyun      */
170*4882a593Smuzhiyun     if (!cw) {
171*4882a593Smuzhiyun         cw = malloc(sizeof(CompWindowRec));
172*4882a593Smuzhiyun         if (!cw) {
173*4882a593Smuzhiyun             free(ccw);
174*4882a593Smuzhiyun             return BadAlloc;
175*4882a593Smuzhiyun         }
176*4882a593Smuzhiyun         cw->damage = DamageCreate(compReportDamage,
177*4882a593Smuzhiyun                                   compDestroyDamage,
178*4882a593Smuzhiyun                                   DamageReportNonEmpty,
179*4882a593Smuzhiyun                                   FALSE, pWin->drawable.pScreen, pWin);
180*4882a593Smuzhiyun         if (!cw->damage) {
181*4882a593Smuzhiyun             free(ccw);
182*4882a593Smuzhiyun             free(cw);
183*4882a593Smuzhiyun             return BadAlloc;
184*4882a593Smuzhiyun         }
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun         anyMarked = compMarkWindows(pWin, &pLayerWin);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun         RegionNull(&cw->borderClip);
189*4882a593Smuzhiyun         cw->update = CompositeRedirectAutomatic;
190*4882a593Smuzhiyun         cw->clients = 0;
191*4882a593Smuzhiyun         cw->oldx = COMP_ORIGIN_INVALID;
192*4882a593Smuzhiyun         cw->oldy = COMP_ORIGIN_INVALID;
193*4882a593Smuzhiyun         cw->damageRegistered = FALSE;
194*4882a593Smuzhiyun         cw->damaged = FALSE;
195*4882a593Smuzhiyun         cw->pOldPixmap = NullPixmap;
196*4882a593Smuzhiyun         dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw);
197*4882a593Smuzhiyun     }
198*4882a593Smuzhiyun     ccw->next = cw->clients;
199*4882a593Smuzhiyun     cw->clients = ccw;
200*4882a593Smuzhiyun     if (!AddResource(ccw->id, CompositeClientWindowType, pWin))
201*4882a593Smuzhiyun         return BadAlloc;
202*4882a593Smuzhiyun     if (ccw->update == CompositeRedirectManual) {
203*4882a593Smuzhiyun         if (!anyMarked)
204*4882a593Smuzhiyun             anyMarked = compMarkWindows(pWin, &pLayerWin);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun         if (cw->damageRegistered) {
207*4882a593Smuzhiyun             DamageUnregister(cw->damage);
208*4882a593Smuzhiyun             cw->damageRegistered = FALSE;
209*4882a593Smuzhiyun         }
210*4882a593Smuzhiyun         cw->update = CompositeRedirectManual;
211*4882a593Smuzhiyun     }
212*4882a593Smuzhiyun     else if (cw->update == CompositeRedirectAutomatic && !cw->damageRegistered) {
213*4882a593Smuzhiyun         if (!anyMarked)
214*4882a593Smuzhiyun             anyMarked = compMarkWindows(pWin, &pLayerWin);
215*4882a593Smuzhiyun     }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun     if (!compCheckRedirect(pWin)) {
218*4882a593Smuzhiyun         FreeResource(ccw->id, RT_NONE);
219*4882a593Smuzhiyun         return BadAlloc;
220*4882a593Smuzhiyun     }
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun     if (anyMarked)
223*4882a593Smuzhiyun         compHandleMarkedWindows(pWin, pLayerWin);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun     return Success;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun void
compRestoreWindow(WindowPtr pWin,PixmapPtr pPixmap)229*4882a593Smuzhiyun compRestoreWindow(WindowPtr pWin, PixmapPtr pPixmap)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
232*4882a593Smuzhiyun     WindowPtr pParent = pWin->parent;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun     if (pParent->drawable.depth == pWin->drawable.depth) {
235*4882a593Smuzhiyun         GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen);
236*4882a593Smuzhiyun         int bw = (int) pWin->borderWidth;
237*4882a593Smuzhiyun         int x = bw;
238*4882a593Smuzhiyun         int y = bw;
239*4882a593Smuzhiyun         int w = pWin->drawable.width;
240*4882a593Smuzhiyun         int h = pWin->drawable.height;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun         if (pGC) {
243*4882a593Smuzhiyun             ChangeGCVal val;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun             val.val = IncludeInferiors;
246*4882a593Smuzhiyun             ChangeGC(NullClient, pGC, GCSubwindowMode, &val);
247*4882a593Smuzhiyun             ValidateGC(&pWin->drawable, pGC);
248*4882a593Smuzhiyun             (*pGC->ops->CopyArea) (&pPixmap->drawable,
249*4882a593Smuzhiyun                                    &pWin->drawable, pGC, x, y, w, h, 0, 0);
250*4882a593Smuzhiyun             FreeScratchGC(pGC);
251*4882a593Smuzhiyun         }
252*4882a593Smuzhiyun     }
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun /*
256*4882a593Smuzhiyun  * Free one of the per-client per-window resources, clearing
257*4882a593Smuzhiyun  * redirect and the per-window pointer as appropriate
258*4882a593Smuzhiyun  */
259*4882a593Smuzhiyun void
compFreeClientWindow(WindowPtr pWin,XID id)260*4882a593Smuzhiyun compFreeClientWindow(WindowPtr pWin, XID id)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
263*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
264*4882a593Smuzhiyun     CompClientWindowPtr ccw, *prev;
265*4882a593Smuzhiyun     Bool anyMarked = FALSE;
266*4882a593Smuzhiyun     WindowPtr pLayerWin;
267*4882a593Smuzhiyun     PixmapPtr pPixmap = NULL;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun     if (!cw)
270*4882a593Smuzhiyun         return;
271*4882a593Smuzhiyun     for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) {
272*4882a593Smuzhiyun         if (ccw->id == id) {
273*4882a593Smuzhiyun             *prev = ccw->next;
274*4882a593Smuzhiyun             if (ccw->update == CompositeRedirectManual)
275*4882a593Smuzhiyun                 cw->update = CompositeRedirectAutomatic;
276*4882a593Smuzhiyun             free(ccw);
277*4882a593Smuzhiyun             break;
278*4882a593Smuzhiyun         }
279*4882a593Smuzhiyun     }
280*4882a593Smuzhiyun     if (!cw->clients) {
281*4882a593Smuzhiyun         anyMarked = compMarkWindows(pWin, &pLayerWin);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun         if (pWin->redirectDraw != RedirectDrawNone) {
284*4882a593Smuzhiyun             pPixmap = (*pScreen->GetWindowPixmap) (pWin);
285*4882a593Smuzhiyun             compSetParentPixmap(pWin);
286*4882a593Smuzhiyun         }
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun         if (cw->damage)
289*4882a593Smuzhiyun             DamageDestroy(cw->damage);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun         RegionUninit(&cw->borderClip);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun         dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL);
294*4882a593Smuzhiyun         free(cw);
295*4882a593Smuzhiyun     }
296*4882a593Smuzhiyun     else if (cw->update == CompositeRedirectAutomatic &&
297*4882a593Smuzhiyun              !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) {
298*4882a593Smuzhiyun         anyMarked = compMarkWindows(pWin, &pLayerWin);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun         DamageRegister(&pWin->drawable, cw->damage);
301*4882a593Smuzhiyun         cw->damageRegistered = TRUE;
302*4882a593Smuzhiyun         pWin->redirectDraw = RedirectDrawAutomatic;
303*4882a593Smuzhiyun         DamageDamageRegion(&pWin->drawable, &pWin->borderSize);
304*4882a593Smuzhiyun     }
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun     if (anyMarked)
307*4882a593Smuzhiyun         compHandleMarkedWindows(pWin, pLayerWin);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun     if (pPixmap) {
310*4882a593Smuzhiyun         compRestoreWindow(pWin, pPixmap);
311*4882a593Smuzhiyun         (*pScreen->DestroyPixmap) (pPixmap);
312*4882a593Smuzhiyun     }
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun /*
316*4882a593Smuzhiyun  * This is easy, just free the appropriate resource.
317*4882a593Smuzhiyun  */
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun int
compUnredirectWindow(ClientPtr pClient,WindowPtr pWin,int update)320*4882a593Smuzhiyun compUnredirectWindow(ClientPtr pClient, WindowPtr pWin, int update)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
323*4882a593Smuzhiyun     CompClientWindowPtr ccw;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun     if (!cw)
326*4882a593Smuzhiyun         return BadValue;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun     for (ccw = cw->clients; ccw; ccw = ccw->next)
329*4882a593Smuzhiyun         if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) {
330*4882a593Smuzhiyun             FreeResource(ccw->id, RT_NONE);
331*4882a593Smuzhiyun             return Success;
332*4882a593Smuzhiyun         }
333*4882a593Smuzhiyun     return BadValue;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun /*
337*4882a593Smuzhiyun  * Redirect all subwindows for one client
338*4882a593Smuzhiyun  */
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun int
compRedirectSubwindows(ClientPtr pClient,WindowPtr pWin,int update)341*4882a593Smuzhiyun compRedirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun     CompSubwindowsPtr csw = GetCompSubwindows(pWin);
344*4882a593Smuzhiyun     CompClientWindowPtr ccw;
345*4882a593Smuzhiyun     WindowPtr pChild;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun     /*
348*4882a593Smuzhiyun      * Only one Manual update is allowed
349*4882a593Smuzhiyun      */
350*4882a593Smuzhiyun     if (csw && update == CompositeRedirectManual)
351*4882a593Smuzhiyun         for (ccw = csw->clients; ccw; ccw = ccw->next)
352*4882a593Smuzhiyun             if (ccw->update == CompositeRedirectManual)
353*4882a593Smuzhiyun                 return BadAccess;
354*4882a593Smuzhiyun     /*
355*4882a593Smuzhiyun      * Allocate per-client per-window structure
356*4882a593Smuzhiyun      * The client *could* allocate multiple, but while supported,
357*4882a593Smuzhiyun      * it is not expected to be common
358*4882a593Smuzhiyun      */
359*4882a593Smuzhiyun     ccw = malloc(sizeof(CompClientWindowRec));
360*4882a593Smuzhiyun     if (!ccw)
361*4882a593Smuzhiyun         return BadAlloc;
362*4882a593Smuzhiyun     ccw->id = FakeClientID(pClient->index);
363*4882a593Smuzhiyun     ccw->update = update;
364*4882a593Smuzhiyun     /*
365*4882a593Smuzhiyun      * Now make sure there's a per-window structure to hang this from
366*4882a593Smuzhiyun      */
367*4882a593Smuzhiyun     if (!csw) {
368*4882a593Smuzhiyun         csw = malloc(sizeof(CompSubwindowsRec));
369*4882a593Smuzhiyun         if (!csw) {
370*4882a593Smuzhiyun             free(ccw);
371*4882a593Smuzhiyun             return BadAlloc;
372*4882a593Smuzhiyun         }
373*4882a593Smuzhiyun         csw->update = CompositeRedirectAutomatic;
374*4882a593Smuzhiyun         csw->clients = 0;
375*4882a593Smuzhiyun         dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw);
376*4882a593Smuzhiyun     }
377*4882a593Smuzhiyun     /*
378*4882a593Smuzhiyun      * Redirect all existing windows
379*4882a593Smuzhiyun      */
380*4882a593Smuzhiyun     for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) {
381*4882a593Smuzhiyun         int ret = compRedirectWindow(pClient, pChild, update);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun         if (ret != Success) {
384*4882a593Smuzhiyun             for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
385*4882a593Smuzhiyun                 (void) compUnredirectWindow(pClient, pChild, update);
386*4882a593Smuzhiyun             if (!csw->clients) {
387*4882a593Smuzhiyun                 free(csw);
388*4882a593Smuzhiyun                 dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0);
389*4882a593Smuzhiyun             }
390*4882a593Smuzhiyun             free(ccw);
391*4882a593Smuzhiyun             return ret;
392*4882a593Smuzhiyun         }
393*4882a593Smuzhiyun     }
394*4882a593Smuzhiyun     /*
395*4882a593Smuzhiyun      * Hook into subwindows list
396*4882a593Smuzhiyun      */
397*4882a593Smuzhiyun     ccw->next = csw->clients;
398*4882a593Smuzhiyun     csw->clients = ccw;
399*4882a593Smuzhiyun     if (!AddResource(ccw->id, CompositeClientSubwindowsType, pWin))
400*4882a593Smuzhiyun         return BadAlloc;
401*4882a593Smuzhiyun     if (ccw->update == CompositeRedirectManual) {
402*4882a593Smuzhiyun         csw->update = CompositeRedirectManual;
403*4882a593Smuzhiyun         /*
404*4882a593Smuzhiyun          * tell damage extension that damage events for this client are
405*4882a593Smuzhiyun          * critical output
406*4882a593Smuzhiyun          */
407*4882a593Smuzhiyun         DamageExtSetCritical(pClient, TRUE);
408*4882a593Smuzhiyun         pWin->inhibitBGPaint = TRUE;
409*4882a593Smuzhiyun     }
410*4882a593Smuzhiyun     return Success;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun /*
414*4882a593Smuzhiyun  * Free one of the per-client per-subwindows resources,
415*4882a593Smuzhiyun  * which frees one redirect per subwindow
416*4882a593Smuzhiyun  */
417*4882a593Smuzhiyun void
compFreeClientSubwindows(WindowPtr pWin,XID id)418*4882a593Smuzhiyun compFreeClientSubwindows(WindowPtr pWin, XID id)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun     CompSubwindowsPtr csw = GetCompSubwindows(pWin);
421*4882a593Smuzhiyun     CompClientWindowPtr ccw, *prev;
422*4882a593Smuzhiyun     WindowPtr pChild;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun     if (!csw)
425*4882a593Smuzhiyun         return;
426*4882a593Smuzhiyun     for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) {
427*4882a593Smuzhiyun         if (ccw->id == id) {
428*4882a593Smuzhiyun             ClientPtr pClient = clients[CLIENT_ID(id)];
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun             *prev = ccw->next;
431*4882a593Smuzhiyun             if (ccw->update == CompositeRedirectManual) {
432*4882a593Smuzhiyun                 /*
433*4882a593Smuzhiyun                  * tell damage extension that damage events for this client are
434*4882a593Smuzhiyun                  * critical output
435*4882a593Smuzhiyun                  */
436*4882a593Smuzhiyun                 DamageExtSetCritical(pClient, FALSE);
437*4882a593Smuzhiyun                 csw->update = CompositeRedirectAutomatic;
438*4882a593Smuzhiyun                 pWin->inhibitBGPaint = FALSE;
439*4882a593Smuzhiyun                 if (pWin->mapped)
440*4882a593Smuzhiyun                     (*pWin->drawable.pScreen->ClearToBackground) (pWin, 0, 0, 0,
441*4882a593Smuzhiyun                                                                   0, TRUE);
442*4882a593Smuzhiyun             }
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun             /*
445*4882a593Smuzhiyun              * Unredirect all existing subwindows
446*4882a593Smuzhiyun              */
447*4882a593Smuzhiyun             for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
448*4882a593Smuzhiyun                 (void) compUnredirectWindow(pClient, pChild, ccw->update);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun             free(ccw);
451*4882a593Smuzhiyun             break;
452*4882a593Smuzhiyun         }
453*4882a593Smuzhiyun     }
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun     /*
456*4882a593Smuzhiyun      * Check if all of the per-client records are gone
457*4882a593Smuzhiyun      */
458*4882a593Smuzhiyun     if (!csw->clients) {
459*4882a593Smuzhiyun         dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL);
460*4882a593Smuzhiyun         free(csw);
461*4882a593Smuzhiyun     }
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun /*
465*4882a593Smuzhiyun  * This is easy, just free the appropriate resource.
466*4882a593Smuzhiyun  */
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun int
compUnredirectSubwindows(ClientPtr pClient,WindowPtr pWin,int update)469*4882a593Smuzhiyun compUnredirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun     CompSubwindowsPtr csw = GetCompSubwindows(pWin);
472*4882a593Smuzhiyun     CompClientWindowPtr ccw;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun     if (!csw)
475*4882a593Smuzhiyun         return BadValue;
476*4882a593Smuzhiyun     for (ccw = csw->clients; ccw; ccw = ccw->next)
477*4882a593Smuzhiyun         if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) {
478*4882a593Smuzhiyun             FreeResource(ccw->id, RT_NONE);
479*4882a593Smuzhiyun             return Success;
480*4882a593Smuzhiyun         }
481*4882a593Smuzhiyun     return BadValue;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun /*
485*4882a593Smuzhiyun  * Add redirection information for one subwindow (during reparent)
486*4882a593Smuzhiyun  */
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun int
compRedirectOneSubwindow(WindowPtr pParent,WindowPtr pWin)489*4882a593Smuzhiyun compRedirectOneSubwindow(WindowPtr pParent, WindowPtr pWin)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun     CompSubwindowsPtr csw = GetCompSubwindows(pParent);
492*4882a593Smuzhiyun     CompClientWindowPtr ccw;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun     if (!csw)
495*4882a593Smuzhiyun         return Success;
496*4882a593Smuzhiyun     for (ccw = csw->clients; ccw; ccw = ccw->next) {
497*4882a593Smuzhiyun         int ret = compRedirectWindow(clients[CLIENT_ID(ccw->id)],
498*4882a593Smuzhiyun                                      pWin, ccw->update);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun         if (ret != Success)
501*4882a593Smuzhiyun             return ret;
502*4882a593Smuzhiyun     }
503*4882a593Smuzhiyun     return Success;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun  * Remove redirection information for one subwindow (during reparent)
508*4882a593Smuzhiyun  */
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun int
compUnredirectOneSubwindow(WindowPtr pParent,WindowPtr pWin)511*4882a593Smuzhiyun compUnredirectOneSubwindow(WindowPtr pParent, WindowPtr pWin)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun     CompSubwindowsPtr csw = GetCompSubwindows(pParent);
514*4882a593Smuzhiyun     CompClientWindowPtr ccw;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun     if (!csw)
517*4882a593Smuzhiyun         return Success;
518*4882a593Smuzhiyun     for (ccw = csw->clients; ccw; ccw = ccw->next) {
519*4882a593Smuzhiyun         int ret = compUnredirectWindow(clients[CLIENT_ID(ccw->id)],
520*4882a593Smuzhiyun                                        pWin, ccw->update);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun         if (ret != Success)
523*4882a593Smuzhiyun             return ret;
524*4882a593Smuzhiyun     }
525*4882a593Smuzhiyun     return Success;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun static PixmapPtr
compNewPixmap(WindowPtr pWin,int x,int y,int w,int h)529*4882a593Smuzhiyun compNewPixmap(WindowPtr pWin, int x, int y, int w, int h)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
532*4882a593Smuzhiyun     WindowPtr pParent = pWin->parent;
533*4882a593Smuzhiyun     PixmapPtr pPixmap;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun     pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth,
536*4882a593Smuzhiyun                                         CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun     if (!pPixmap)
539*4882a593Smuzhiyun         return 0;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun     pPixmap->screen_x = x;
542*4882a593Smuzhiyun     pPixmap->screen_y = y;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun     if (pParent->drawable.depth == pWin->drawable.depth) {
545*4882a593Smuzhiyun         GCPtr pGC = GetScratchGC(pWin->drawable.depth, pScreen);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun         if (pGC) {
548*4882a593Smuzhiyun             ChangeGCVal val;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun             val.val = IncludeInferiors;
551*4882a593Smuzhiyun             ChangeGC(NullClient, pGC, GCSubwindowMode, &val);
552*4882a593Smuzhiyun             ValidateGC(&pPixmap->drawable, pGC);
553*4882a593Smuzhiyun             (*pGC->ops->CopyArea) (&pParent->drawable,
554*4882a593Smuzhiyun                                    &pPixmap->drawable,
555*4882a593Smuzhiyun                                    pGC,
556*4882a593Smuzhiyun                                    x - pParent->drawable.x,
557*4882a593Smuzhiyun                                    y - pParent->drawable.y, w, h, 0, 0);
558*4882a593Smuzhiyun             FreeScratchGC(pGC);
559*4882a593Smuzhiyun         }
560*4882a593Smuzhiyun     }
561*4882a593Smuzhiyun     else {
562*4882a593Smuzhiyun         PictFormatPtr pSrcFormat = PictureWindowFormat(pParent);
563*4882a593Smuzhiyun         PictFormatPtr pDstFormat = PictureWindowFormat(pWin);
564*4882a593Smuzhiyun         XID inferiors = IncludeInferiors;
565*4882a593Smuzhiyun         int error;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun         PicturePtr pSrcPicture = CreatePicture(None,
568*4882a593Smuzhiyun                                                &pParent->drawable,
569*4882a593Smuzhiyun                                                pSrcFormat,
570*4882a593Smuzhiyun                                                CPSubwindowMode,
571*4882a593Smuzhiyun                                                &inferiors,
572*4882a593Smuzhiyun                                                serverClient, &error);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun         PicturePtr pDstPicture = CreatePicture(None,
575*4882a593Smuzhiyun                                                &pPixmap->drawable,
576*4882a593Smuzhiyun                                                pDstFormat,
577*4882a593Smuzhiyun                                                0, 0,
578*4882a593Smuzhiyun                                                serverClient, &error);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun         if (pSrcPicture && pDstPicture) {
581*4882a593Smuzhiyun             CompositePicture(PictOpSrc,
582*4882a593Smuzhiyun                              pSrcPicture,
583*4882a593Smuzhiyun                              NULL,
584*4882a593Smuzhiyun                              pDstPicture,
585*4882a593Smuzhiyun                              x - pParent->drawable.x,
586*4882a593Smuzhiyun                              y - pParent->drawable.y, 0, 0, 0, 0, w, h);
587*4882a593Smuzhiyun         }
588*4882a593Smuzhiyun         if (pSrcPicture)
589*4882a593Smuzhiyun             FreePicture(pSrcPicture, 0);
590*4882a593Smuzhiyun         if (pDstPicture)
591*4882a593Smuzhiyun             FreePicture(pDstPicture, 0);
592*4882a593Smuzhiyun     }
593*4882a593Smuzhiyun     return pPixmap;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun Bool
compAllocPixmap(WindowPtr pWin)597*4882a593Smuzhiyun compAllocPixmap(WindowPtr pWin)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun     int bw = (int) pWin->borderWidth;
600*4882a593Smuzhiyun     int x = pWin->drawable.x - bw;
601*4882a593Smuzhiyun     int y = pWin->drawable.y - bw;
602*4882a593Smuzhiyun     int w = pWin->drawable.width + (bw << 1);
603*4882a593Smuzhiyun     int h = pWin->drawable.height + (bw << 1);
604*4882a593Smuzhiyun     PixmapPtr pPixmap = compNewPixmap(pWin, x, y, w, h);
605*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun     if (!pPixmap)
608*4882a593Smuzhiyun         return FALSE;
609*4882a593Smuzhiyun     if (cw->update == CompositeRedirectAutomatic)
610*4882a593Smuzhiyun         pWin->redirectDraw = RedirectDrawAutomatic;
611*4882a593Smuzhiyun     else
612*4882a593Smuzhiyun         pWin->redirectDraw = RedirectDrawManual;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun     compSetPixmap(pWin, pPixmap, bw);
615*4882a593Smuzhiyun     cw->oldx = COMP_ORIGIN_INVALID;
616*4882a593Smuzhiyun     cw->oldy = COMP_ORIGIN_INVALID;
617*4882a593Smuzhiyun     cw->damageRegistered = FALSE;
618*4882a593Smuzhiyun     if (cw->update == CompositeRedirectAutomatic) {
619*4882a593Smuzhiyun         DamageRegister(&pWin->drawable, cw->damage);
620*4882a593Smuzhiyun         cw->damageRegistered = TRUE;
621*4882a593Smuzhiyun     }
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun     /* Make sure our borderClip is up to date */
624*4882a593Smuzhiyun     RegionUninit(&cw->borderClip);
625*4882a593Smuzhiyun     RegionCopy(&cw->borderClip, &pWin->borderClip);
626*4882a593Smuzhiyun     cw->borderClipX = pWin->drawable.x;
627*4882a593Smuzhiyun     cw->borderClipY = pWin->drawable.y;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun     return TRUE;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun void
compSetParentPixmap(WindowPtr pWin)633*4882a593Smuzhiyun compSetParentPixmap(WindowPtr pWin)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
636*4882a593Smuzhiyun     PixmapPtr pParentPixmap;
637*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun     if (cw->damageRegistered) {
640*4882a593Smuzhiyun         DamageUnregister(cw->damage);
641*4882a593Smuzhiyun         cw->damageRegistered = FALSE;
642*4882a593Smuzhiyun         DamageEmpty(cw->damage);
643*4882a593Smuzhiyun     }
644*4882a593Smuzhiyun     /*
645*4882a593Smuzhiyun      * Move the parent-constrained border clip region back into
646*4882a593Smuzhiyun      * the window so that ValidateTree will handle the unmap
647*4882a593Smuzhiyun      * case correctly.  Unmap adds the window borderClip to the
648*4882a593Smuzhiyun      * parent exposed area; regions beyond the parent cause crashes
649*4882a593Smuzhiyun      */
650*4882a593Smuzhiyun     RegionCopy(&pWin->borderClip, &cw->borderClip);
651*4882a593Smuzhiyun     pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
652*4882a593Smuzhiyun     pWin->redirectDraw = RedirectDrawNone;
653*4882a593Smuzhiyun     compSetPixmap(pWin, pParentPixmap, pWin->borderWidth);
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun /*
657*4882a593Smuzhiyun  * Make sure the pixmap is the right size and offset.  Allocate a new
658*4882a593Smuzhiyun  * pixmap to change size, adjust origin to change offset, leaving the
659*4882a593Smuzhiyun  * old pixmap in cw->pOldPixmap so bits can be recovered
660*4882a593Smuzhiyun  */
661*4882a593Smuzhiyun Bool
compReallocPixmap(WindowPtr pWin,int draw_x,int draw_y,unsigned int w,unsigned int h,int bw)662*4882a593Smuzhiyun compReallocPixmap(WindowPtr pWin, int draw_x, int draw_y,
663*4882a593Smuzhiyun                   unsigned int w, unsigned int h, int bw)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun     ScreenPtr pScreen = pWin->drawable.pScreen;
666*4882a593Smuzhiyun     PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin);
667*4882a593Smuzhiyun     PixmapPtr pNew;
668*4882a593Smuzhiyun     CompWindowPtr cw = GetCompWindow(pWin);
669*4882a593Smuzhiyun     int pix_x, pix_y;
670*4882a593Smuzhiyun     int pix_w, pix_h;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun     assert(cw && pWin->redirectDraw != RedirectDrawNone);
673*4882a593Smuzhiyun     cw->oldx = pOld->screen_x;
674*4882a593Smuzhiyun     cw->oldy = pOld->screen_y;
675*4882a593Smuzhiyun     pix_x = draw_x - bw;
676*4882a593Smuzhiyun     pix_y = draw_y - bw;
677*4882a593Smuzhiyun     pix_w = w + (bw << 1);
678*4882a593Smuzhiyun     pix_h = h + (bw << 1);
679*4882a593Smuzhiyun     if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) {
680*4882a593Smuzhiyun         pNew = compNewPixmap(pWin, pix_x, pix_y, pix_w, pix_h);
681*4882a593Smuzhiyun         if (!pNew)
682*4882a593Smuzhiyun             return FALSE;
683*4882a593Smuzhiyun         cw->pOldPixmap = pOld;
684*4882a593Smuzhiyun         compSetPixmap(pWin, pNew, bw);
685*4882a593Smuzhiyun     }
686*4882a593Smuzhiyun     else {
687*4882a593Smuzhiyun         pNew = pOld;
688*4882a593Smuzhiyun         cw->pOldPixmap = 0;
689*4882a593Smuzhiyun     }
690*4882a593Smuzhiyun     pNew->screen_x = pix_x;
691*4882a593Smuzhiyun     pNew->screen_y = pix_y;
692*4882a593Smuzhiyun     return TRUE;
693*4882a593Smuzhiyun }
694