Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. | |
3 | * | |
4 | * All Rights Reserved. | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining | |
7 | * a copy of this software and associated documentation files (the | |
8 | * "Software"), to deal in the Software without restriction, including | |
9 | * without limitation on the rights to use, copy, modify, merge, | |
10 | * publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, | |
12 | * subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice (including the | |
15 | * next paragraph) shall be included in all copies or substantial | |
16 | * portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS | |
22 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
23 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
25 | * SOFTWARE. | |
26 | */ | |
27 | ||
28 | /* | |
29 | * Authors: | |
30 | * Kevin E. Martin <kem@redhat.com> | |
31 | * | |
32 | */ | |
33 | ||
34 | /** \file | |
35 | * Provides pixmap support. */ | |
36 | ||
37 | #ifdef HAVE_DMX_CONFIG_H | |
38 | #include <dmx-config.h> | |
39 | #endif | |
40 | ||
41 | #include "dmx.h" | |
42 | #include "dmxsync.h" | |
43 | #include "dmxpixmap.h" | |
44 | ||
45 | #include "pixmapstr.h" | |
46 | #include "servermd.h" | |
47 | #include "privates.h" | |
48 | ||
49 | /** Initialize a private area in \a pScreen for pixmap information. */ | |
50 | Bool | |
51 | dmxInitPixmap(ScreenPtr pScreen) | |
52 | { | |
53 | if (!dixRegisterPrivateKey | |
54 | (&dmxPixPrivateKeyRec, PRIVATE_PIXMAP, sizeof(dmxPixPrivRec))) | |
55 | return FALSE; | |
56 | ||
57 | return TRUE; | |
58 | } | |
59 | ||
60 | /** Create a pixmap on the back-end server. */ | |
61 | void | |
62 | dmxBECreatePixmap(PixmapPtr pPixmap) | |
63 | { | |
64 | ScreenPtr pScreen = pPixmap->drawable.pScreen; | |
65 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
66 | dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); | |
67 | ||
68 | /* Make sure we haven't already created this pixmap. This can | |
69 | * happen when the pixmap is used elsewhere (e.g., as a background | |
70 | * or border for a window) and the refcnt > 1. | |
71 | */ | |
72 | if (pPixPriv->pixmap) | |
73 | return; | |
74 | ||
75 | if (pPixmap->drawable.width && pPixmap->drawable.height) { | |
76 | pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay, | |
77 | dmxScreen->scrnWin, | |
78 | pPixmap->drawable.width, | |
79 | pPixmap->drawable.height, | |
80 | pPixmap->drawable.depth); | |
81 | dmxSync(dmxScreen, FALSE); | |
82 | } | |
83 | } | |
84 | ||
85 | /** Create a pixmap for \a pScreen with the specified \a width, \a | |
86 | * height, and \a depth. */ | |
87 | PixmapPtr | |
88 | dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, | |
89 | unsigned usage_hint) | |
90 | { | |
91 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
92 | PixmapPtr pPixmap; | |
93 | int bpp; | |
94 | dmxPixPrivPtr pPixPriv; | |
95 | ||
96 | #if 0 | |
97 | DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); | |
98 | if (pScreen->CreatePixmap) | |
99 | ret = pScreen->CreatePixmap(pPixmap); | |
100 | #endif | |
101 | ||
102 | /* Create pixmap on back-end server */ | |
103 | if (depth == 24) | |
104 | bpp = 32; | |
105 | else | |
106 | bpp = depth; | |
107 | ||
108 | pPixmap = AllocatePixmap(pScreen, 0); | |
109 | if (!pPixmap) | |
110 | return NullPixmap; | |
111 | ||
112 | pPixmap->drawable.type = DRAWABLE_PIXMAP; | |
113 | pPixmap->drawable.class = 0; | |
114 | pPixmap->drawable.pScreen = pScreen; | |
115 | pPixmap->drawable.depth = depth; | |
116 | pPixmap->drawable.bitsPerPixel = bpp; | |
117 | pPixmap->drawable.id = 0; | |
118 | pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; | |
119 | pPixmap->drawable.x = 0; | |
120 | pPixmap->drawable.y = 0; | |
121 | pPixmap->drawable.width = width; | |
122 | pPixmap->drawable.height = height; | |
123 | pPixmap->devKind = PixmapBytePad(width, bpp); | |
124 | pPixmap->refcnt = 1; | |
125 | pPixmap->usage_hint = usage_hint; | |
126 | ||
127 | pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); | |
128 | pPixPriv->pixmap = (Pixmap) 0; | |
129 | pPixPriv->detachedImage = NULL; | |
130 | ||
131 | /* Create the pixmap on the back-end server */ | |
132 | if (dmxScreen->beDisplay) { | |
133 | dmxBECreatePixmap(pPixmap); | |
134 | } | |
135 | ||
136 | #if 0 | |
137 | DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); | |
138 | #endif | |
139 | ||
140 | return pPixmap; | |
141 | } | |
142 | ||
143 | /** Destroy the pixmap on the back-end server. */ | |
144 | Bool | |
145 | dmxBEFreePixmap(PixmapPtr pPixmap) | |
146 | { | |
147 | ScreenPtr pScreen = pPixmap->drawable.pScreen; | |
148 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
149 | dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); | |
150 | ||
151 | if (pPixPriv->pixmap) { | |
152 | XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap); | |
153 | pPixPriv->pixmap = (Pixmap) 0; | |
154 | return TRUE; | |
155 | } | |
156 | ||
157 | return FALSE; | |
158 | } | |
159 | ||
160 | /** Destroy the pixmap pointed to by \a pPixmap. */ | |
161 | Bool | |
162 | dmxDestroyPixmap(PixmapPtr pPixmap) | |
163 | { | |
164 | ScreenPtr pScreen = pPixmap->drawable.pScreen; | |
165 | DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; | |
166 | Bool ret = TRUE; | |
167 | ||
168 | #if 0 | |
169 | DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); | |
170 | #endif | |
171 | ||
172 | if (--pPixmap->refcnt) | |
173 | return TRUE; | |
174 | ||
175 | /* Destroy pixmap on back-end server */ | |
176 | if (dmxScreen->beDisplay) { | |
177 | if (dmxBEFreePixmap(pPixmap)) { | |
178 | /* Also make sure that we destroy any detached image */ | |
179 | dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); | |
180 | ||
181 | if (pPixPriv->detachedImage) | |
182 | XDestroyImage(pPixPriv->detachedImage); | |
183 | dmxSync(dmxScreen, FALSE); | |
184 | } | |
185 | } | |
186 | FreePixmap(pPixmap); | |
187 | ||
188 | #if 0 | |
189 | if (pScreen->DestroyPixmap) | |
190 | ret = pScreen->DestroyPixmap(pPixmap); | |
191 | DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); | |
192 | #endif | |
193 | ||
194 | return ret; | |
195 | } | |
196 | ||
197 | /** Create and return a region based on the pixmap pointed to by \a | |
198 | * pPixmap. */ | |
199 | RegionPtr | |
200 | dmxBitmapToRegion(PixmapPtr pPixmap) | |
201 | { | |
202 | DMXScreenInfo *dmxScreen = &dmxScreens[pPixmap->drawable.pScreen->myNum]; | |
203 | dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); | |
204 | XImage *ximage; | |
205 | RegionPtr pReg, pTmpReg; | |
206 | int x, y; | |
207 | unsigned long previousPixel, currentPixel; | |
208 | BoxRec Box; | |
209 | Bool overlap; | |
210 | ||
211 | if (!dmxScreen->beDisplay) { | |
212 | pReg = RegionCreate(NullBox, 1); | |
213 | return pReg; | |
214 | } | |
215 | ||
216 | ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, | |
217 | pPixmap->drawable.width, pPixmap->drawable.height, | |
218 | 1, XYPixmap); | |
219 | ||
220 | pReg = RegionCreate(NullBox, 1); | |
221 | pTmpReg = RegionCreate(NullBox, 1); | |
222 | if (!pReg || !pTmpReg) { | |
223 | XDestroyImage(ximage); | |
224 | return NullRegion; | |
225 | } | |
226 | ||
227 | for (y = 0; y < pPixmap->drawable.height; y++) { | |
228 | Box.y1 = y; | |
229 | Box.y2 = y + 1; | |
230 | previousPixel = 0L; | |
231 | for (x = 0; x < pPixmap->drawable.width; x++) { | |
232 | currentPixel = XGetPixel(ximage, x, y); | |
233 | if (previousPixel != currentPixel) { | |
234 | if (previousPixel == 0L) { | |
235 | /* left edge */ | |
236 | Box.x1 = x; | |
237 | } | |
238 | else if (currentPixel == 0L) { | |
239 | /* right edge */ | |
240 | Box.x2 = x; | |
241 | RegionReset(pTmpReg, &Box); | |
242 | RegionAppend(pReg, pTmpReg); | |
243 | } | |
244 | previousPixel = currentPixel; | |
245 | } | |
246 | } | |
247 | if (previousPixel != 0L) { | |
248 | /* right edge because of the end of pixmap */ | |
249 | Box.x2 = pPixmap->drawable.width; | |
250 | RegionReset(pTmpReg, &Box); | |
251 | RegionAppend(pReg, pTmpReg); | |
252 | } | |
253 | } | |
254 | ||
255 | RegionDestroy(pTmpReg); | |
256 | XDestroyImage(ximage); | |
257 | ||
258 | RegionValidate(pReg, &overlap); | |
259 | ||
260 | dmxSync(dmxScreen, FALSE); | |
261 | return pReg; | |
262 | } |