1/*
2 * Copyright © 2000 Keith Packard
3 *
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 Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD 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.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include <stdlib.h>
28
29#include    <X11/X.h>
30#include    "scrnintstr.h"
31#include    "windowstr.h"
32#include    "dixfontstr.h"
33#include    "mi.h"
34#include    "regionstr.h"
35#include    "globals.h"
36#include    "gcstruct.h"
37#include    "shadow.h"
38
39static DevPrivateKeyRec shadowScrPrivateKeyRec;
40#define shadowScrPrivateKey (&shadowScrPrivateKeyRec)
41
42#define shadowGetBuf(pScr) ((shadowBufPtr) \
43    dixLookupPrivate(&(pScr)->devPrivates, shadowScrPrivateKey))
44#define shadowBuf(pScr)            shadowBufPtr pBuf = shadowGetBuf(pScr)
45
46#define wrap(priv, real, mem) {\
47    priv->mem = real->mem; \
48    real->mem = shadow##mem; \
49}
50
51#define unwrap(priv, real, mem) {\
52    real->mem = priv->mem; \
53}
54
55static void
56shadowRedisplay(ScreenPtr pScreen)
57{
58    shadowBuf(pScreen);
59    RegionPtr pRegion;
60
61    if (!pBuf || !pBuf->pDamage || !pBuf->update)
62        return;
63    pRegion = DamageRegion(pBuf->pDamage);
64    if (RegionNotEmpty(pRegion)) {
65        (*pBuf->update) (pScreen, pBuf);
66        DamageEmpty(pBuf->pDamage);
67    }
68}
69
70static void
71shadowBlockHandler(ScreenPtr pScreen, void *timeout)
72{
73    shadowBuf(pScreen);
74
75    shadowRedisplay(pScreen);
76
77    unwrap(pBuf, pScreen, BlockHandler);
78    pScreen->BlockHandler(pScreen, timeout);
79    wrap(pBuf, pScreen, BlockHandler);
80}
81
82static void
83shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
84               unsigned int format, unsigned long planeMask, char *pdstLine)
85{
86    ScreenPtr pScreen = pDrawable->pScreen;
87
88    shadowBuf(pScreen);
89
90    /* Many apps use GetImage to sync with the visible frame buffer */
91    if (pDrawable->type == DRAWABLE_WINDOW)
92        shadowRedisplay(pScreen);
93    unwrap(pBuf, pScreen, GetImage);
94    pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
95    wrap(pBuf, pScreen, GetImage);
96}
97
98static Bool
99shadowCloseScreen(ScreenPtr pScreen)
100{
101    shadowBuf(pScreen);
102
103    unwrap(pBuf, pScreen, GetImage);
104    unwrap(pBuf, pScreen, CloseScreen);
105    unwrap(pBuf, pScreen, BlockHandler);
106    shadowRemove(pScreen, pBuf->pPixmap);
107    DamageDestroy(pBuf->pDamage);
108    if (pBuf->pPixmap)
109        pScreen->DestroyPixmap(pBuf->pPixmap);
110    free(pBuf);
111    return pScreen->CloseScreen(pScreen);
112}
113
114Bool
115shadowSetup(ScreenPtr pScreen)
116{
117    shadowBufPtr pBuf;
118
119    if (!dixRegisterPrivateKey(&shadowScrPrivateKeyRec, PRIVATE_SCREEN, 0))
120        return FALSE;
121
122    if (!DamageSetup(pScreen))
123        return FALSE;
124
125    pBuf = malloc(sizeof(shadowBufRec));
126    if (!pBuf)
127        return FALSE;
128    pBuf->pDamage = DamageCreate((DamageReportFunc) NULL,
129                                 (DamageDestroyFunc) NULL,
130                                 DamageReportNone, TRUE, pScreen, pScreen);
131    if (!pBuf->pDamage) {
132        free(pBuf);
133        return FALSE;
134    }
135
136    wrap(pBuf, pScreen, CloseScreen);
137    wrap(pBuf, pScreen, GetImage);
138    wrap(pBuf, pScreen, BlockHandler);
139    pBuf->update = 0;
140    pBuf->window = 0;
141    pBuf->pPixmap = 0;
142    pBuf->closure = 0;
143    pBuf->randr = 0;
144
145    dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf);
146    return TRUE;
147}
148
149Bool
150shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update,
151          ShadowWindowProc window, int randr, void *closure)
152{
153    shadowBuf(pScreen);
154
155    /*
156     * Map simple rotation values to bitmasks; fortunately,
157     * these are all unique
158     */
159    switch (randr) {
160    case 0:
161        randr = SHADOW_ROTATE_0;
162        break;
163    case 90:
164        randr = SHADOW_ROTATE_90;
165        break;
166    case 180:
167        randr = SHADOW_ROTATE_180;
168        break;
169    case 270:
170        randr = SHADOW_ROTATE_270;
171        break;
172    }
173    pBuf->update = update;
174    pBuf->window = window;
175    pBuf->randr = randr;
176    pBuf->closure = closure;
177    pBuf->pPixmap = pPixmap;
178    DamageRegister(&pPixmap->drawable, pBuf->pDamage);
179    return TRUE;
180}
181
182void
183shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap)
184{
185    shadowBuf(pScreen);
186
187    if (pBuf->pPixmap) {
188        DamageUnregister(pBuf->pDamage);
189        pBuf->update = 0;
190        pBuf->window = 0;
191        pBuf->randr = 0;
192        pBuf->closure = 0;
193        pBuf->pPixmap = 0;
194    }
195}
196