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 
39 static 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 
55 static void
shadowRedisplay(ScreenPtr pScreen)56 shadowRedisplay(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 
70 static void
shadowBlockHandler(ScreenPtr pScreen,void * timeout)71 shadowBlockHandler(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 
82 static void
shadowGetImage(DrawablePtr pDrawable,int sx,int sy,int w,int h,unsigned int format,unsigned long planeMask,char * pdstLine)83 shadowGetImage(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 visable 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 
98 static Bool
shadowCloseScreen(ScreenPtr pScreen)99 shadowCloseScreen(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 
114 Bool
shadowSetup(ScreenPtr pScreen)115 shadowSetup(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 
149 Bool
shadowAdd(ScreenPtr pScreen,PixmapPtr pPixmap,ShadowUpdateProc update,ShadowWindowProc window,int randr,void * closure)150 shadowAdd(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 
182 void
shadowRemove(ScreenPtr pScreen,PixmapPtr pPixmap)183 shadowRemove(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