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