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