dmxpixmap.c revision 706f2543
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. */
50Bool dmxInitPixmap(ScreenPtr pScreen)
51{
52    if (!dixRegisterPrivateKey(&dmxPixPrivateKeyRec, PRIVATE_PIXMAP, sizeof(dmxPixPrivRec)))
53	return FALSE;
54
55    return TRUE;
56}
57
58/** Create a pixmap on the back-end server. */
59void dmxBECreatePixmap(PixmapPtr pPixmap)
60{
61    ScreenPtr      pScreen   = pPixmap->drawable.pScreen;
62    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
63    dmxPixPrivPtr  pPixPriv  = DMX_GET_PIXMAP_PRIV(pPixmap);
64
65    /* Make sure we haven't already created this pixmap.  This can
66     * happen when the pixmap is used elsewhere (e.g., as a background
67     * or border for a window) and the refcnt > 1.
68     */
69    if (pPixPriv->pixmap)
70	return;
71
72    if (pPixmap->drawable.width && pPixmap->drawable.height) {
73	pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay,
74					 dmxScreen->scrnWin,
75					 pPixmap->drawable.width,
76					 pPixmap->drawable.height,
77					 pPixmap->drawable.depth);
78	dmxSync(dmxScreen, FALSE);
79    }
80}
81
82/** Create a pixmap for \a pScreen with the specified \a width, \a
83 *  height, and \a depth. */
84PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth,
85			  unsigned usage_hint)
86{
87    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
88    PixmapPtr      pPixmap;
89    int            bpp;
90    dmxPixPrivPtr  pPixPriv;
91
92#if 0
93    DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen);
94    if (pScreen->CreatePixmap)
95	ret = pScreen->CreatePixmap(pPixmap);
96#endif
97
98    /* Create pixmap on back-end server */
99    if (depth == 24) bpp = 32;
100    else             bpp = depth;
101
102    pPixmap = AllocatePixmap(pScreen, 0);
103    if (!pPixmap)
104	return NullPixmap;
105
106    pPixmap->drawable.type = DRAWABLE_PIXMAP;
107    pPixmap->drawable.class = 0;
108    pPixmap->drawable.pScreen = pScreen;
109    pPixmap->drawable.depth = depth;
110    pPixmap->drawable.bitsPerPixel = bpp;
111    pPixmap->drawable.id = 0;
112    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
113    pPixmap->drawable.x = 0;
114    pPixmap->drawable.y = 0;
115    pPixmap->drawable.width = width;
116    pPixmap->drawable.height = height;
117    pPixmap->devKind = PixmapBytePad(width, bpp);
118    pPixmap->refcnt = 1;
119    pPixmap->usage_hint = usage_hint;
120
121    pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
122    pPixPriv->pixmap = (Pixmap)0;
123    pPixPriv->detachedImage = NULL;
124
125    /* Create the pixmap on the back-end server */
126    if (dmxScreen->beDisplay) {
127	dmxBECreatePixmap(pPixmap);
128    }
129
130#if 0
131    DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen);
132#endif
133
134    return pPixmap;
135}
136
137/** Destroy the pixmap on the back-end server. */
138Bool dmxBEFreePixmap(PixmapPtr pPixmap)
139{
140    ScreenPtr      pScreen = pPixmap->drawable.pScreen;
141    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
142    dmxPixPrivPtr  pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
143
144    if (pPixPriv->pixmap) {
145	XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap);
146	pPixPriv->pixmap = (Pixmap)0;
147	return TRUE;
148    }
149
150    return FALSE;
151}
152
153/** Destroy the pixmap pointed to by \a pPixmap. */
154Bool dmxDestroyPixmap(PixmapPtr pPixmap)
155{
156    ScreenPtr      pScreen = pPixmap->drawable.pScreen;
157    DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
158    Bool           ret = TRUE;
159
160#if 0
161    DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen);
162#endif
163
164    if (--pPixmap->refcnt)
165	return TRUE;
166
167    /* Destroy pixmap on back-end server */
168    if (dmxScreen->beDisplay) {
169	if (dmxBEFreePixmap(pPixmap)) {
170	    /* Also make sure that we destroy any detached image */
171	    dmxPixPrivPtr  pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
172	    if (pPixPriv->detachedImage)
173		XDestroyImage(pPixPriv->detachedImage);
174	    dmxSync(dmxScreen, FALSE);
175	}
176    }
177    FreePixmap(pPixmap);
178
179#if 0
180    if (pScreen->DestroyPixmap)
181	ret = pScreen->DestroyPixmap(pPixmap);
182    DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen);
183#endif
184
185    return ret;
186}
187
188/** Create and return a region based on the pixmap pointed to by \a
189 *  pPixmap. */
190RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap)
191{
192    DMXScreenInfo *dmxScreen = &dmxScreens[pPixmap->drawable.pScreen->myNum];
193    dmxPixPrivPtr  pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
194    XImage        *ximage;
195    RegionPtr      pReg, pTmpReg;
196    int            x, y;
197    unsigned long  previousPixel, currentPixel;
198    BoxRec         Box;
199    Bool           overlap;
200
201    if (!dmxScreen->beDisplay) {
202	pReg = RegionCreate(NullBox, 1);
203	return pReg;
204    }
205
206    ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0,
207		       pPixmap->drawable.width, pPixmap->drawable.height,
208		       1, XYPixmap);
209
210    pReg = RegionCreate(NullBox, 1);
211    pTmpReg = RegionCreate(NullBox, 1);
212    if(!pReg || !pTmpReg) {
213	XDestroyImage(ximage);
214	return NullRegion;
215    }
216
217    for (y = 0; y < pPixmap->drawable.height; y++) {
218	Box.y1 = y;
219	Box.y2 = y + 1;
220	previousPixel = 0L;
221	for (x = 0; x < pPixmap->drawable.width; x++) {
222	    currentPixel = XGetPixel(ximage, x, y);
223	    if (previousPixel != currentPixel) {
224		if (previousPixel == 0L) {
225		    /* left edge */
226		    Box.x1 = x;
227		} else if (currentPixel == 0L) {
228		    /* right edge */
229		    Box.x2 = x;
230		    RegionReset(pTmpReg, &Box);
231		    RegionAppend(pReg, pTmpReg);
232		}
233		previousPixel = currentPixel;
234	    }
235	}
236	if (previousPixel != 0L) {
237	    /* right edge because of the end of pixmap */
238	    Box.x2 = pPixmap->drawable.width;
239	    RegionReset(pTmpReg, &Box);
240	    RegionAppend(pReg, pTmpReg);
241	}
242    }
243
244    RegionDestroy(pTmpReg);
245    XDestroyImage(ximage);
246
247    RegionValidate(pReg, &overlap);
248
249    dmxSync(dmxScreen, FALSE);
250    return pReg;
251}
252