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