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 */
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
27 #include <stdlib.h>
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"
39 static DevPrivateKeyRec shadowScrPrivateKeyRec;
40 #define shadowScrPrivateKey (&shadowScrPrivateKeyRec)
42 #define wrap(priv, real, mem) {\
43 priv->mem = real->mem; \
44 real->mem = shadow##mem; \
45 }
47 #define unwrap(priv, real, mem) {\
48 real->mem = priv->mem; \
49 }
51 static void
52 shadowRedisplay(ScreenPtr pScreen)
53 {
54 shadowBuf(pScreen);
55 RegionPtr pRegion;
57 if (!pBuf || !pBuf->pDamage || !pBuf->update)
58 return;
59 pRegion = DamageRegion(pBuf->pDamage);
60 if (RegionNotEmpty(pRegion)) {
61 (*pBuf->update)(pScreen, pBuf);
62 DamageEmpty(pBuf->pDamage);
63 }
64 }
66 static void
67 shadowBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead)
68 {
69 ScreenPtr pScreen = (ScreenPtr) data;
71 shadowRedisplay(pScreen);
72 }
74 static void
75 shadowWakeupHandler(pointer data, int i, pointer LastSelectMask)
76 {
77 }
79 static void
80 shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
81 unsigned int format, unsigned long planeMask, char *pdstLine)
82 {
83 ScreenPtr pScreen = pDrawable->pScreen;
84 shadowBuf(pScreen);
86 /* Many apps use GetImage to sync with the visable frame buffer */
87 if (pDrawable->type == DRAWABLE_WINDOW)
88 shadowRedisplay(pScreen);
89 unwrap(pBuf, pScreen, GetImage);
90 pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
91 wrap(pBuf, pScreen, GetImage);
92 }
94 #define BACKWARDS_COMPATIBILITY
96 static Bool
97 shadowCloseScreen(int i, ScreenPtr pScreen)
98 {
99 shadowBuf(pScreen);
101 unwrap(pBuf, pScreen, GetImage);
102 unwrap(pBuf, pScreen, CloseScreen);
103 shadowRemove(pScreen, pBuf->pPixmap);
104 DamageDestroy(pBuf->pDamage);
105 #ifdef BACKWARDS_COMPATIBILITY
106 RegionUninit(&pBuf->damage); /* bc */
107 #endif
108 if (pBuf->pPixmap)
109 pScreen->DestroyPixmap(pBuf->pPixmap);
110 free(pBuf);
111 return pScreen->CloseScreen(i, pScreen);
112 }
114 #ifdef BACKWARDS_COMPATIBILITY
115 static void
116 shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure)
117 {
118 ScreenPtr pScreen = closure;
119 shadowBufPtr pBuf = (shadowBufPtr)
120 dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey);
122 /* Register the damaged region, use DamageReportNone below when we
123 * want to break BC below... */
124 RegionUnion(&pDamage->damage, &pDamage->damage, pRegion);
126 /*
127 * BC hack. In 7.0 and earlier several drivers would inspect the
128 * 'damage' member directly, so we have to keep it existing.
129 */
130 RegionCopy(&pBuf->damage, pRegion);
131 }
132 #endif
134 Bool
135 shadowSetup(ScreenPtr pScreen)
136 {
137 shadowBufPtr pBuf;
139 if (!dixRegisterPrivateKey(&shadowScrPrivateKeyRec, PRIVATE_SCREEN, 0))
140 return FALSE;
142 if (!DamageSetup(pScreen))
143 return FALSE;
145 pBuf = malloc(sizeof(shadowBufRec));
146 if (!pBuf)
147 return FALSE;
148 #ifdef BACKWARDS_COMPATIBILITY
149 pBuf->pDamage = DamageCreate((DamageReportFunc)shadowReportFunc,
150 (DamageDestroyFunc)NULL,
151 DamageReportRawRegion,
152 TRUE, pScreen, pScreen);
153 #else
154 pBuf->pDamage = DamageCreate((DamageReportFunc)NULL,
155 (DamageDestroyFunc)NULL,
156 DamageReportNone,
157 TRUE, pScreen, pScreen);
158 #endif
159 if (!pBuf->pDamage) {
160 free(pBuf);
161 return FALSE;
162 }
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
175 dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf);
176 return TRUE;
177 }
179 Bool
180 shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update,
181 ShadowWindowProc window, int randr, void *closure)
182 {
183 shadowBuf(pScreen);
185 if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler,
186 (pointer)pScreen))
187 return FALSE;
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 }
216 void
217 shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap)
218 {
219 shadowBuf(pScreen);
221 if (pBuf->pPixmap) {
222 DamageUnregister(&pBuf->pPixmap->drawable, pBuf->pDamage);
223 pBuf->update = 0;
224 pBuf->window = 0;
225 pBuf->randr = 0;
226 pBuf->closure = 0;
227 pBuf->pPixmap = 0;
228 }
230 RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler,
231 (pointer) pScreen);
232 }
234 Bool
235 shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window)
236 {
237 PixmapPtr pPixmap;
239 pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height,
240 pScreen->rootDepth, 0);
241 if (!pPixmap)
242 return FALSE;
244 if (!shadowSetup(pScreen)) {
245 pScreen->DestroyPixmap(pPixmap);
246 return FALSE;
247 }
249 shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0);
251 return TRUE;
252 }