Imported Upstream version 1.15.1
[deb_xorg-server.git] / miext / shadow / shadow.c
CommitLineData
a09e091a
JB
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
41#define shadowScrPrivateKey (&shadowScrPrivateKeyRec)
42
43#define wrap(priv, real, mem) {\
44 priv->mem = real->mem; \
45 real->mem = shadow##mem; \
46}
47
48#define unwrap(priv, real, mem) {\
49 real->mem = priv->mem; \
50}
51
52static void
53shadowRedisplay(ScreenPtr pScreen)
54{
55 shadowBuf(pScreen);
56 RegionPtr pRegion;
57
58 if (!pBuf || !pBuf->pDamage || !pBuf->update)
59 return;
60 pRegion = DamageRegion(pBuf->pDamage);
61 if (RegionNotEmpty(pRegion)) {
62 (*pBuf->update) (pScreen, pBuf);
63 DamageEmpty(pBuf->pDamage);
64 }
65}
66
67static void
68shadowBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead)
69{
70 ScreenPtr pScreen = (ScreenPtr) data;
71
72 shadowRedisplay(pScreen);
73}
74
75static void
76shadowWakeupHandler(pointer data, int i, pointer LastSelectMask)
77{
78}
79
80static void
81shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
82 unsigned int format, unsigned long planeMask, char *pdstLine)
83{
84 ScreenPtr pScreen = pDrawable->pScreen;
85
86 shadowBuf(pScreen);
87
88 /* Many apps use GetImage to sync with the visable frame buffer */
89 if (pDrawable->type == DRAWABLE_WINDOW)
90 shadowRedisplay(pScreen);
91 unwrap(pBuf, pScreen, GetImage);
92 pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
93 wrap(pBuf, pScreen, GetImage);
94}
95
96#define BACKWARDS_COMPATIBILITY
97
98static Bool
99shadowCloseScreen(ScreenPtr pScreen)
100{
101 shadowBuf(pScreen);
102
103 unwrap(pBuf, pScreen, GetImage);
104 unwrap(pBuf, pScreen, CloseScreen);
105 shadowRemove(pScreen, pBuf->pPixmap);
106 DamageDestroy(pBuf->pDamage);
107#ifdef BACKWARDS_COMPATIBILITY
108 RegionUninit(&pBuf->damage); /* bc */
109#endif
110 if (pBuf->pPixmap)
111 pScreen->DestroyPixmap(pBuf->pPixmap);
112 free(pBuf);
113 return pScreen->CloseScreen(pScreen);
114}
115
116#ifdef BACKWARDS_COMPATIBILITY
117static void
118shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure)
119{
120 ScreenPtr pScreen = closure;
121 shadowBufPtr pBuf = (shadowBufPtr)
122 dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey);
123
124 /* Register the damaged region, use DamageReportNone below when we
125 * want to break BC below... */
126 RegionUnion(&pDamage->damage, &pDamage->damage, pRegion);
127
128 /*
129 * BC hack. In 7.0 and earlier several drivers would inspect the
130 * 'damage' member directly, so we have to keep it existing.
131 */
132 RegionCopy(&pBuf->damage, pRegion);
133}
134#endif
135
136Bool
137shadowSetup(ScreenPtr pScreen)
138{
139 shadowBufPtr pBuf;
140
141 if (!dixRegisterPrivateKey(&shadowScrPrivateKeyRec, PRIVATE_SCREEN, 0))
142 return FALSE;
143
144 if (!DamageSetup(pScreen))
145 return FALSE;
146
147 pBuf = malloc(sizeof(shadowBufRec));
148 if (!pBuf)
149 return FALSE;
150#ifdef BACKWARDS_COMPATIBILITY
151 pBuf->pDamage = DamageCreate((DamageReportFunc) shadowReportFunc,
152 (DamageDestroyFunc) NULL,
153 DamageReportRawRegion, TRUE, pScreen, pScreen);
154#else
155 pBuf->pDamage = DamageCreate((DamageReportFunc) NULL,
156 (DamageDestroyFunc) NULL,
157 DamageReportNone, TRUE, pScreen, pScreen);
158#endif
159 if (!pBuf->pDamage) {
160 free(pBuf);
161 return FALSE;
162 }
163
164 wrap(pBuf, pScreen, CloseScreen);
165 wrap(pBuf, pScreen, GetImage);
166 pBuf->update = 0;
167 pBuf->window = 0;
168 pBuf->pPixmap = 0;
169 pBuf->closure = 0;
170 pBuf->randr = 0;
171#ifdef BACKWARDS_COMPATIBILITY
172 RegionNull(&pBuf->damage); /* bc */
173#endif
174
175 dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf);
176 return TRUE;
177}
178
179Bool
180shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update,
181 ShadowWindowProc window, int randr, void *closure)
182{
183 shadowBuf(pScreen);
184
185 if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler,
186 (pointer) pScreen))
187 return FALSE;
188
189 /*
190 * Map simple rotation values to bitmasks; fortunately,
191 * these are all unique
192 */
193 switch (randr) {
194 case 0:
195 randr = SHADOW_ROTATE_0;
196 break;
197 case 90:
198 randr = SHADOW_ROTATE_90;
199 break;
200 case 180:
201 randr = SHADOW_ROTATE_180;
202 break;
203 case 270:
204 randr = SHADOW_ROTATE_270;
205 break;
206 }
207 pBuf->update = update;
208 pBuf->window = window;
209 pBuf->randr = randr;
210 pBuf->closure = closure;
211 pBuf->pPixmap = pPixmap;
212 DamageRegister(&pPixmap->drawable, pBuf->pDamage);
213 return TRUE;
214}
215
216void
217shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap)
218{
219 shadowBuf(pScreen);
220
221 if (pBuf->pPixmap) {
222 DamageUnregister(pBuf->pDamage);
223 pBuf->update = 0;
224 pBuf->window = 0;
225 pBuf->randr = 0;
226 pBuf->closure = 0;
227 pBuf->pPixmap = 0;
228 }
229
230 RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler,
231 (pointer) pScreen);
232}
233
234Bool
235shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window)
236{
237 PixmapPtr pPixmap;
238
239 pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height,
240 pScreen->rootDepth, 0);
241 if (!pPixmap)
242 return FALSE;
243
244 if (!shadowSetup(pScreen)) {
245 pScreen->DestroyPixmap(pPixmap);
246 return FALSE;
247 }
248
249 shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0);
250
251 return TRUE;
252}