Home | History | Annotate | Line # | Download | only in dmx
      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 (at) 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 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. */
     59 void 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. */
     84 PixmapPtr 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. */
    138 Bool 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. */
    154 Bool 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. */
    190 RegionPtr 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