First import
[xorg_rtime.git] / xorg-server-1.4 / composite / compalloc.c
blob006e808401d89b5f6fe3d54f5c54e25c89e6a0a3
1 /*
2 * Copyright © 2006 Sun Microsystems
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Sun Microsystems not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Sun Microsystems makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
14 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
22 * Copyright © 2003 Keith Packard
24 * Permission to use, copy, modify, distribute, and sell this software and its
25 * documentation for any purpose is hereby granted without fee, provided that
26 * the above copyright notice appear in all copies and that both that
27 * copyright notice and this permission notice appear in supporting
28 * documentation, and that the name of Keith Packard not be used in
29 * advertising or publicity pertaining to distribution of the software without
30 * specific, written prior permission. Keith Packard makes no
31 * representations about the suitability of this software for any purpose. It
32 * is provided "as is" without express or implied warranty.
34 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
35 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
36 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
37 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
38 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
39 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
40 * PERFORMANCE OF THIS SOFTWARE.
43 #ifdef HAVE_DIX_CONFIG_H
44 #include <dix-config.h>
45 #endif
47 #include "compint.h"
49 static void
50 compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
52 WindowPtr pWin = (WindowPtr) closure;
53 ScreenPtr pScreen = pWin->drawable.pScreen;
54 CompScreenPtr cs = GetCompScreen (pScreen);
55 CompWindowPtr cw = GetCompWindow (pWin);
57 cs->damaged = TRUE;
58 cw->damaged = TRUE;
61 static void
62 compDestroyDamage (DamagePtr pDamage, void *closure)
64 WindowPtr pWin = (WindowPtr) closure;
65 CompWindowPtr cw = GetCompWindow (pWin);
67 cw->damage = 0;
71 * Redirect one window for one client
73 int
74 compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
76 CompWindowPtr cw = GetCompWindow (pWin);
77 CompClientWindowPtr ccw;
78 Bool wasMapped = pWin->mapped;
79 CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
81 if (pWin == cs->pOverlayWin) {
82 return Success;
86 * Only one Manual update is allowed
88 if (cw && update == CompositeRedirectManual)
89 for (ccw = cw->clients; ccw; ccw = ccw->next)
90 if (ccw->update == CompositeRedirectManual)
91 return BadAccess;
94 * Allocate per-client per-window structure
95 * The client *could* allocate multiple, but while supported,
96 * it is not expected to be common
98 ccw = xalloc (sizeof (CompClientWindowRec));
99 if (!ccw)
100 return BadAlloc;
101 ccw->id = FakeClientID (pClient->index);
102 ccw->update = update;
104 * Now make sure there's a per-window structure to hang this from
106 if (!cw)
108 cw = xalloc (sizeof (CompWindowRec));
109 if (!cw)
111 xfree (ccw);
112 return BadAlloc;
114 cw->damage = DamageCreate (compReportDamage,
115 compDestroyDamage,
116 DamageReportNonEmpty,
117 FALSE,
118 pWin->drawable.pScreen,
119 pWin);
120 if (!cw->damage)
122 xfree (ccw);
123 xfree (cw);
124 return BadAlloc;
126 if (wasMapped)
128 DisableMapUnmapEvents (pWin);
129 UnmapWindow (pWin, FALSE);
130 EnableMapUnmapEvents (pWin);
133 REGION_NULL (pScreen, &cw->borderClip);
134 cw->update = CompositeRedirectAutomatic;
135 cw->clients = 0;
136 cw->oldx = COMP_ORIGIN_INVALID;
137 cw->oldy = COMP_ORIGIN_INVALID;
138 cw->damageRegistered = FALSE;
139 cw->damaged = FALSE;
140 pWin->devPrivates[CompWindowPrivateIndex].ptr = cw;
142 ccw->next = cw->clients;
143 cw->clients = ccw;
144 if (!AddResource (ccw->id, CompositeClientWindowType, pWin))
145 return BadAlloc;
146 if (ccw->update == CompositeRedirectManual)
148 if (cw->damageRegistered)
150 DamageUnregister (&pWin->drawable, cw->damage);
151 cw->damageRegistered = FALSE;
153 cw->update = CompositeRedirectManual;
156 if (!compCheckRedirect (pWin))
158 FreeResource (ccw->id, RT_NONE);
159 return BadAlloc;
161 if (wasMapped && !pWin->mapped)
163 Bool overrideRedirect = pWin->overrideRedirect;
164 pWin->overrideRedirect = TRUE;
165 DisableMapUnmapEvents (pWin);
166 MapWindow (pWin, pClient);
167 EnableMapUnmapEvents (pWin);
168 pWin->overrideRedirect = overrideRedirect;
171 return Success;
175 * Free one of the per-client per-window resources, clearing
176 * redirect and the per-window pointer as appropriate
178 void
179 compFreeClientWindow (WindowPtr pWin, XID id)
181 CompWindowPtr cw = GetCompWindow (pWin);
182 CompClientWindowPtr ccw, *prev;
183 Bool wasMapped = pWin->mapped;
185 if (!cw)
186 return;
187 for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next)
189 if (ccw->id == id)
191 *prev = ccw->next;
192 if (ccw->update == CompositeRedirectManual)
193 cw->update = CompositeRedirectAutomatic;
194 xfree (ccw);
195 break;
198 if (!cw->clients)
200 if (wasMapped)
202 DisableMapUnmapEvents (pWin);
203 UnmapWindow (pWin, FALSE);
204 EnableMapUnmapEvents (pWin);
207 if (pWin->redirectDraw != RedirectDrawNone)
208 compFreePixmap (pWin);
210 if (cw->damage)
211 DamageDestroy (cw->damage);
213 REGION_UNINIT (pScreen, &cw->borderClip);
215 pWin->devPrivates[CompWindowPrivateIndex].ptr = 0;
216 xfree (cw);
218 else if (cw->update == CompositeRedirectAutomatic &&
219 !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone)
221 DamageRegister (&pWin->drawable, cw->damage);
222 cw->damageRegistered = TRUE;
223 pWin->redirectDraw = RedirectDrawAutomatic;
224 DamageDamageRegion (&pWin->drawable, &pWin->borderSize);
226 if (wasMapped && !pWin->mapped)
228 Bool overrideRedirect = pWin->overrideRedirect;
229 pWin->overrideRedirect = TRUE;
230 DisableMapUnmapEvents (pWin);
231 MapWindow (pWin, clients[CLIENT_ID(id)]);
232 EnableMapUnmapEvents (pWin);
233 pWin->overrideRedirect = overrideRedirect;
238 * This is easy, just free the appropriate resource.
242 compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
244 CompWindowPtr cw = GetCompWindow (pWin);
245 CompClientWindowPtr ccw;
247 if (!cw)
248 return BadValue;
250 for (ccw = cw->clients; ccw; ccw = ccw->next)
251 if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
253 FreeResource (ccw->id, RT_NONE);
254 return Success;
256 return BadValue;
260 * Redirect all subwindows for one client
264 compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
266 CompSubwindowsPtr csw = GetCompSubwindows (pWin);
267 CompClientWindowPtr ccw;
268 WindowPtr pChild;
271 * Only one Manual update is allowed
273 if (csw && update == CompositeRedirectManual)
274 for (ccw = csw->clients; ccw; ccw = ccw->next)
275 if (ccw->update == CompositeRedirectManual)
276 return BadAccess;
278 * Allocate per-client per-window structure
279 * The client *could* allocate multiple, but while supported,
280 * it is not expected to be common
282 ccw = xalloc (sizeof (CompClientWindowRec));
283 if (!ccw)
284 return BadAlloc;
285 ccw->id = FakeClientID (pClient->index);
286 ccw->update = update;
288 * Now make sure there's a per-window structure to hang this from
290 if (!csw)
292 csw = xalloc (sizeof (CompSubwindowsRec));
293 if (!csw)
295 xfree (ccw);
296 return BadAlloc;
298 csw->update = CompositeRedirectAutomatic;
299 csw->clients = 0;
300 pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = csw;
303 * Redirect all existing windows
305 for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
307 int ret = compRedirectWindow (pClient, pChild, update);
308 if (ret != Success)
310 for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
311 (void) compUnredirectWindow (pClient, pChild, update);
312 if (!csw->clients)
314 xfree (csw);
315 pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = 0;
317 xfree (ccw);
318 return ret;
322 * Hook into subwindows list
324 ccw->next = csw->clients;
325 csw->clients = ccw;
326 if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin))
327 return BadAlloc;
328 if (ccw->update == CompositeRedirectManual)
330 csw->update = CompositeRedirectManual;
332 * tell damage extension that damage events for this client are
333 * critical output
335 DamageExtSetCritical (pClient, TRUE);
337 return Success;
341 * Free one of the per-client per-subwindows resources,
342 * which frees one redirect per subwindow
344 void
345 compFreeClientSubwindows (WindowPtr pWin, XID id)
347 CompSubwindowsPtr csw = GetCompSubwindows (pWin);
348 CompClientWindowPtr ccw, *prev;
349 WindowPtr pChild;
351 if (!csw)
352 return;
353 for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next)
355 if (ccw->id == id)
357 ClientPtr pClient = clients[CLIENT_ID(id)];
359 *prev = ccw->next;
360 if (ccw->update == CompositeRedirectManual)
363 * tell damage extension that damage events for this client are
364 * critical output
366 DamageExtSetCritical (pClient, FALSE);
367 csw->update = CompositeRedirectAutomatic;
368 if (pWin->mapped)
369 (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE);
373 * Unredirect all existing subwindows
375 for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
376 (void) compUnredirectWindow (pClient, pChild, ccw->update);
378 xfree (ccw);
379 break;
384 * Check if all of the per-client records are gone
386 if (!csw->clients)
388 pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = 0;
389 xfree (csw);
394 * This is easy, just free the appropriate resource.
398 compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
400 CompSubwindowsPtr csw = GetCompSubwindows (pWin);
401 CompClientWindowPtr ccw;
403 if (!csw)
404 return BadValue;
405 for (ccw = csw->clients; ccw; ccw = ccw->next)
406 if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
408 FreeResource (ccw->id, RT_NONE);
409 return Success;
411 return BadValue;
415 * Add redirection information for one subwindow (during reparent)
419 compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
421 CompSubwindowsPtr csw = GetCompSubwindows (pParent);
422 CompClientWindowPtr ccw;
424 if (!csw)
425 return Success;
426 for (ccw = csw->clients; ccw; ccw = ccw->next)
428 int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)],
429 pWin, ccw->update);
430 if (ret != Success)
431 return ret;
433 return Success;
437 * Remove redirection information for one subwindow (during reparent)
441 compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
443 CompSubwindowsPtr csw = GetCompSubwindows (pParent);
444 CompClientWindowPtr ccw;
446 if (!csw)
447 return Success;
448 for (ccw = csw->clients; ccw; ccw = ccw->next)
450 int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)],
451 pWin, ccw->update);
452 if (ret != Success)
453 return ret;
455 return Success;
458 static PixmapPtr
459 compNewPixmap (WindowPtr pWin, int x, int y, int w, int h)
461 ScreenPtr pScreen = pWin->drawable.pScreen;
462 WindowPtr pParent = pWin->parent;
463 PixmapPtr pPixmap;
465 pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth);
467 if (!pPixmap)
468 return 0;
470 pPixmap->screen_x = x;
471 pPixmap->screen_y = y;
473 if (pParent->drawable.depth == pWin->drawable.depth)
475 GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen);
478 * Copy bits from the parent into the new pixmap so that it will
479 * have "reasonable" contents in case for background None areas.
481 if (pGC)
483 XID val = IncludeInferiors;
485 ValidateGC(&pPixmap->drawable, pGC);
486 dixChangeGC (serverClient, pGC, GCSubwindowMode, &val, NULL);
487 (*pGC->ops->CopyArea) (&pParent->drawable,
488 &pPixmap->drawable,
489 pGC,
490 x - pParent->drawable.x,
491 y - pParent->drawable.y,
492 w, h, 0, 0);
493 FreeScratchGC (pGC);
496 else
498 PictFormatPtr pSrcFormat = compWindowFormat (pParent);
499 PictFormatPtr pDstFormat = compWindowFormat (pWin);
500 XID inferiors = IncludeInferiors;
501 int error;
503 PicturePtr pSrcPicture = CreatePicture (None,
504 &pParent->drawable,
505 pSrcFormat,
506 CPSubwindowMode,
507 &inferiors,
508 serverClient, &error);
510 PicturePtr pDstPicture = CreatePicture (None,
511 &pPixmap->drawable,
512 pDstFormat,
513 0, 0,
514 serverClient, &error);
516 if (pSrcPicture && pDstPicture)
518 CompositePicture (PictOpSrc,
519 pSrcPicture,
520 NULL,
521 pDstPicture,
522 x - pParent->drawable.x,
523 y - pParent->drawable.y,
524 0, 0, 0, 0, w, h);
526 if (pSrcPicture)
527 FreePicture (pSrcPicture, 0);
528 if (pDstPicture)
529 FreePicture (pDstPicture, 0);
531 return pPixmap;
534 Bool
535 compAllocPixmap (WindowPtr pWin)
537 int bw = (int) pWin->borderWidth;
538 int x = pWin->drawable.x - bw;
539 int y = pWin->drawable.y - bw;
540 int w = pWin->drawable.width + (bw << 1);
541 int h = pWin->drawable.height + (bw << 1);
542 PixmapPtr pPixmap = compNewPixmap (pWin, x, y, w, h);
543 CompWindowPtr cw = GetCompWindow (pWin);
545 if (!pPixmap)
546 return FALSE;
547 if (cw->update == CompositeRedirectAutomatic)
548 pWin->redirectDraw = RedirectDrawAutomatic;
549 else
550 pWin->redirectDraw = RedirectDrawManual;
552 compSetPixmap (pWin, pPixmap);
553 cw->oldx = COMP_ORIGIN_INVALID;
554 cw->oldy = COMP_ORIGIN_INVALID;
555 cw->damageRegistered = FALSE;
556 if (cw->update == CompositeRedirectAutomatic)
558 DamageRegister (&pWin->drawable, cw->damage);
559 cw->damageRegistered = TRUE;
561 return TRUE;
564 void
565 compFreePixmap (WindowPtr pWin)
567 ScreenPtr pScreen = pWin->drawable.pScreen;
568 PixmapPtr pRedirectPixmap, pParentPixmap;
569 CompWindowPtr cw = GetCompWindow (pWin);
571 if (cw->damageRegistered)
573 DamageUnregister (&pWin->drawable, cw->damage);
574 cw->damageRegistered = FALSE;
575 DamageEmpty (cw->damage);
578 * Move the parent-constrained border clip region back into
579 * the window so that ValidateTree will handle the unmap
580 * case correctly. Unmap adds the window borderClip to the
581 * parent exposed area; regions beyond the parent cause crashes
583 REGION_COPY (pScreen, &pWin->borderClip, &cw->borderClip);
584 pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin);
585 pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
586 pWin->redirectDraw = RedirectDrawNone;
587 compSetPixmap (pWin, pParentPixmap);
588 (*pScreen->DestroyPixmap) (pRedirectPixmap);
592 * Make sure the pixmap is the right size and offset. Allocate a new
593 * pixmap to change size, adjust origin to change offset, leaving the
594 * old pixmap in cw->pOldPixmap so bits can be recovered
596 Bool
597 compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y,
598 unsigned int w, unsigned int h, int bw)
600 ScreenPtr pScreen = pWin->drawable.pScreen;
601 PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin);
602 PixmapPtr pNew;
603 CompWindowPtr cw = GetCompWindow (pWin);
604 int pix_x, pix_y;
605 int pix_w, pix_h;
607 assert (cw && pWin->redirectDraw != RedirectDrawNone);
608 cw->oldx = pOld->screen_x;
609 cw->oldy = pOld->screen_y;
610 pix_x = draw_x - bw;
611 pix_y = draw_y - bw;
612 pix_w = w + (bw << 1);
613 pix_h = h + (bw << 1);
614 if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height)
616 pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h);
617 if (!pNew)
618 return FALSE;
619 cw->pOldPixmap = pOld;
620 compSetPixmap (pWin, pNew);
622 else
624 pNew = pOld;
625 cw->pOldPixmap = 0;
627 pNew->screen_x = pix_x;
628 pNew->screen_y = pix_y;
629 return TRUE;