390 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			390 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  *
 | |
|  * Copyright © 2000 SuSE, Inc.
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that
 | |
|  * copyright notice and this permission notice appear in supporting
 | |
|  * documentation, and that the name of SuSE not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  SuSE makes no representations about the
 | |
|  * suitability of this software for any purpose.  It is provided "as is"
 | |
|  * without express or implied warranty.
 | |
|  *
 | |
|  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
 | |
|  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 | |
|  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
 | |
|  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  * Author:  Keith Packard, SuSE, Inc.
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "fb.h"
 | |
| #include "fboverlay.h"
 | |
| #include "shmint.h"
 | |
| 
 | |
| static DevPrivateKeyRec fbOverlayScreenPrivateKeyRec;
 | |
| 
 | |
| #define fbOverlayScreenPrivateKey (&fbOverlayScreenPrivateKeyRec)
 | |
| 
 | |
| DevPrivateKey
 | |
| fbOverlayGetScreenPrivateKey(void)
 | |
| {
 | |
|     return fbOverlayScreenPrivateKey;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Replace this if you want something supporting
 | |
|  * multiple overlays with the same depth
 | |
|  */
 | |
| Bool
 | |
| fbOverlayCreateWindow(WindowPtr pWin)
 | |
| {
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen);
 | |
|     int i;
 | |
|     PixmapPtr pPixmap;
 | |
| 
 | |
|     if (pWin->drawable.class != InputOutput)
 | |
|         return TRUE;
 | |
| 
 | |
|     if (pWin->drawable.bitsPerPixel == 32)
 | |
|         pWin->drawable.bitsPerPixel =
 | |
|             fbGetScreenPrivate(pWin->drawable.pScreen)->win32bpp;
 | |
| 
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|         pPixmap = pScrPriv->layer[i].u.run.pixmap;
 | |
|         if (pWin->drawable.depth == pPixmap->drawable.depth) {
 | |
|             dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin), pPixmap);
 | |
|             /*
 | |
|              * Make sure layer keys are written correctly by
 | |
|              * having non-root layers set to full while the
 | |
|              * root layer is set to empty.  This will cause
 | |
|              * all of the layers to get painted when the root
 | |
|              * is mapped
 | |
|              */
 | |
|             if (!pWin->parent) {
 | |
|                 RegionEmpty(&pScrPriv->layer[i].u.run.region);
 | |
|             }
 | |
|             return TRUE;
 | |
|         }
 | |
|     }
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| fbOverlayCloseScreen(ScreenPtr pScreen)
 | |
| {
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|         (*pScreen->DestroyPixmap) (pScrPriv->layer[i].u.run.pixmap);
 | |
|         RegionUninit(&pScrPriv->layer[i].u.run.region);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return layer containing this window
 | |
|  */
 | |
| int
 | |
| fbOverlayWindowLayer(WindowPtr pWin)
 | |
| {
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pWin->drawable.pScreen);
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++)
 | |
|         if (dixLookupPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin)) ==
 | |
|             (pointer) pScrPriv->layer[i].u.run.pixmap)
 | |
|             return i;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| fbOverlayCreateScreenResources(ScreenPtr pScreen)
 | |
| {
 | |
|     int i;
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
 | |
|     PixmapPtr pPixmap;
 | |
|     pointer pbits;
 | |
|     int width;
 | |
|     int depth;
 | |
|     BoxRec box;
 | |
| 
 | |
|     if (!miCreateScreenResources(pScreen))
 | |
|         return FALSE;
 | |
| 
 | |
|     box.x1 = 0;
 | |
|     box.y1 = 0;
 | |
|     box.x2 = pScreen->width;
 | |
|     box.y2 = pScreen->height;
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|         pbits = pScrPriv->layer[i].u.init.pbits;
 | |
|         width = pScrPriv->layer[i].u.init.width;
 | |
|         depth = pScrPriv->layer[i].u.init.depth;
 | |
|         pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0);
 | |
|         if (!pPixmap)
 | |
|             return FALSE;
 | |
|         if (!(*pScreen->ModifyPixmapHeader) (pPixmap, pScreen->width,
 | |
|                                              pScreen->height, depth,
 | |
|                                              BitsPerPixel(depth),
 | |
|                                              PixmapBytePad(width, depth),
 | |
|                                              pbits))
 | |
|             return FALSE;
 | |
|         pScrPriv->layer[i].u.run.pixmap = pPixmap;
 | |
|         RegionInit(&pScrPriv->layer[i].u.run.region, &box, 0);
 | |
|     }
 | |
|     pScreen->devPrivate = pScrPriv->layer[0].u.run.pixmap;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| fbOverlayPaintKey(DrawablePtr pDrawable,
 | |
|                   RegionPtr pRegion, CARD32 pixel, int layer)
 | |
| {
 | |
|     fbFillRegionSolid(pDrawable, pRegion, 0,
 | |
|                       fbReplicatePixel(pixel, pDrawable->bitsPerPixel));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Track visible region for each layer
 | |
|  */
 | |
| void
 | |
| fbOverlayUpdateLayerRegion(ScreenPtr pScreen, int layer, RegionPtr prgn)
 | |
| {
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
 | |
|     int i;
 | |
|     RegionRec rgnNew;
 | |
| 
 | |
|     if (!prgn || !RegionNotEmpty(prgn))
 | |
|         return;
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|         if (i == layer) {
 | |
|             /* add new piece to this fb */
 | |
|             RegionUnion(&pScrPriv->layer[i].u.run.region,
 | |
|                         &pScrPriv->layer[i].u.run.region, prgn);
 | |
|         }
 | |
|         else if (RegionNotEmpty(&pScrPriv->layer[i].u.run.region)) {
 | |
|             /* paint new piece with chroma key */
 | |
|             RegionNull(&rgnNew);
 | |
|             RegionIntersect(&rgnNew, prgn, &pScrPriv->layer[i].u.run.region);
 | |
|             (*pScrPriv->PaintKey) (&pScrPriv->layer[i].u.run.pixmap->drawable,
 | |
|                                    &rgnNew, pScrPriv->layer[i].key, i);
 | |
|             RegionUninit(&rgnNew);
 | |
|             /* remove piece from other fbs */
 | |
|             RegionSubtract(&pScrPriv->layer[i].u.run.region,
 | |
|                            &pScrPriv->layer[i].u.run.region, prgn);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Copy only areas in each layer containing real bits
 | |
|  */
 | |
| void
 | |
| fbOverlayCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
 | |
| {
 | |
|     ScreenPtr pScreen = pWin->drawable.pScreen;
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
 | |
|     RegionRec rgnDst;
 | |
|     int dx, dy;
 | |
|     int i;
 | |
|     RegionRec layerRgn[FB_OVERLAY_MAX];
 | |
|     PixmapPtr pPixmap;
 | |
| 
 | |
|     dx = ptOldOrg.x - pWin->drawable.x;
 | |
|     dy = ptOldOrg.y - pWin->drawable.y;
 | |
| 
 | |
|     /*
 | |
|      * Clip to existing bits
 | |
|      */
 | |
|     RegionTranslate(prgnSrc, -dx, -dy);
 | |
|     RegionNull(&rgnDst);
 | |
|     RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
 | |
|     RegionTranslate(&rgnDst, dx, dy);
 | |
|     /*
 | |
|      * Compute the portion of each fb affected by this copy
 | |
|      */
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|         RegionNull(&layerRgn[i]);
 | |
|         RegionIntersect(&layerRgn[i], &rgnDst,
 | |
|                         &pScrPriv->layer[i].u.run.region);
 | |
|         if (RegionNotEmpty(&layerRgn[i])) {
 | |
|             RegionTranslate(&layerRgn[i], -dx, -dy);
 | |
|             pPixmap = pScrPriv->layer[i].u.run.pixmap;
 | |
|             miCopyRegion(&pPixmap->drawable, &pPixmap->drawable,
 | |
|                          0,
 | |
|                          &layerRgn[i], dx, dy, pScrPriv->CopyWindow, 0,
 | |
|                          (void *) (long) i);
 | |
|         }
 | |
|     }
 | |
|     /*
 | |
|      * Update regions
 | |
|      */
 | |
|     for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|         if (RegionNotEmpty(&layerRgn[i]))
 | |
|             fbOverlayUpdateLayerRegion(pScreen, i, &layerRgn[i]);
 | |
| 
 | |
|         RegionUninit(&layerRgn[i]);
 | |
|     }
 | |
|     RegionUninit(&rgnDst);
 | |
| }
 | |
| 
 | |
| void
 | |
| fbOverlayWindowExposures(WindowPtr pWin,
 | |
|                          RegionPtr prgn, RegionPtr other_exposed)
 | |
| {
 | |
|     fbOverlayUpdateLayerRegion(pWin->drawable.pScreen,
 | |
|                                fbOverlayWindowLayer(pWin), prgn);
 | |
|     miWindowExposures(pWin, prgn, other_exposed);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| fbOverlaySetupScreen(ScreenPtr pScreen,
 | |
|                      pointer pbits1,
 | |
|                      pointer pbits2,
 | |
|                      int xsize,
 | |
|                      int ysize,
 | |
|                      int dpix,
 | |
|                      int dpiy, int width1, int width2, int bpp1, int bpp2)
 | |
| {
 | |
|     return fbSetupScreen(pScreen,
 | |
|                          pbits1, xsize, ysize, dpix, dpiy, width1, bpp1);
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| fb24_32OverlayCreateScreenResources(ScreenPtr pScreen)
 | |
| {
 | |
|     FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
 | |
|     int pitch;
 | |
|     Bool retval;
 | |
|     int i;
 | |
| 
 | |
|     if ((retval = fbOverlayCreateScreenResources(pScreen))) {
 | |
|         for (i = 0; i < pScrPriv->nlayers; i++) {
 | |
|             /* fix the screen pixmap */
 | |
|             PixmapPtr pPix = (PixmapPtr) pScrPriv->layer[i].u.run.pixmap;
 | |
| 
 | |
|             if (pPix->drawable.bitsPerPixel == 32) {
 | |
|                 pPix->drawable.bitsPerPixel = 24;
 | |
|                 pitch = BitmapBytePad(pPix->drawable.width * 24);
 | |
|                 pPix->devKind = pitch;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| fbOverlayFinishScreenInit(ScreenPtr pScreen,
 | |
|                           pointer pbits1,
 | |
|                           pointer pbits2,
 | |
|                           int xsize,
 | |
|                           int ysize,
 | |
|                           int dpix,
 | |
|                           int dpiy,
 | |
|                           int width1,
 | |
|                           int width2,
 | |
|                           int bpp1, int bpp2, int depth1, int depth2)
 | |
| {
 | |
|     VisualPtr visuals;
 | |
|     DepthPtr depths;
 | |
|     int nvisuals;
 | |
|     int ndepths;
 | |
|     int bpp = 0, imagebpp = 32;
 | |
|     VisualID defaultVisual;
 | |
|     FbOverlayScrPrivPtr pScrPriv;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey
 | |
|         (&fbOverlayScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
 | |
|         return FALSE;
 | |
| 
 | |
|     pScrPriv = malloc(sizeof(FbOverlayScrPrivRec));
 | |
|     if (!pScrPriv)
 | |
|         return FALSE;
 | |
| 
 | |
|     if (bpp1 == 32 || bpp2 == 32)
 | |
|         bpp = 32;
 | |
|     else if (bpp1 == 24 || bpp2 == 24)
 | |
|         bpp = 24;
 | |
| 
 | |
|     if (bpp == 24) {
 | |
|         int f;
 | |
| 
 | |
|         imagebpp = 32;
 | |
|         /*
 | |
|          * Check to see if we're advertising a 24bpp image format,
 | |
|          * in which case windows will use it in preference to a 32 bit
 | |
|          * format.
 | |
|          */
 | |
|         for (f = 0; f < screenInfo.numPixmapFormats; f++) {
 | |
|             if (screenInfo.formats[f].bitsPerPixel == 24) {
 | |
|                 imagebpp = 24;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (imagebpp == 32) {
 | |
|         fbGetScreenPrivate(pScreen)->win32bpp = bpp;
 | |
|         fbGetScreenPrivate(pScreen)->pix32bpp = bpp;
 | |
|     }
 | |
|     else {
 | |
|         fbGetScreenPrivate(pScreen)->win32bpp = 32;
 | |
|         fbGetScreenPrivate(pScreen)->pix32bpp = 32;
 | |
|     }
 | |
| 
 | |
|     if (!fbInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &depth1,
 | |
|                        &defaultVisual, ((unsigned long) 1 << (bpp1 - 1)) |
 | |
|                        ((unsigned long) 1 << (bpp2 - 1)), 8)) {
 | |
|         free(pScrPriv);
 | |
|         return FALSE;
 | |
|     }
 | |
|     if (!miScreenInit(pScreen, 0, xsize, ysize, dpix, dpiy, 0,
 | |
|                       depth1, ndepths, depths,
 | |
|                       defaultVisual, nvisuals, visuals)) {
 | |
|         free(pScrPriv);
 | |
|         return FALSE;
 | |
|     }
 | |
|     /* MI thinks there's no frame buffer */
 | |
| #ifdef MITSHM
 | |
|     ShmRegisterFbFuncs(pScreen);
 | |
| #endif
 | |
|     pScreen->minInstalledCmaps = 1;
 | |
|     pScreen->maxInstalledCmaps = 2;
 | |
| 
 | |
|     pScrPriv->nlayers = 2;
 | |
|     pScrPriv->PaintKey = fbOverlayPaintKey;
 | |
|     pScrPriv->CopyWindow = fbCopyWindowProc;
 | |
|     pScrPriv->layer[0].u.init.pbits = pbits1;
 | |
|     pScrPriv->layer[0].u.init.width = width1;
 | |
|     pScrPriv->layer[0].u.init.depth = depth1;
 | |
| 
 | |
|     pScrPriv->layer[1].u.init.pbits = pbits2;
 | |
|     pScrPriv->layer[1].u.init.width = width2;
 | |
|     pScrPriv->layer[1].u.init.depth = depth2;
 | |
|     dixSetPrivate(&pScreen->devPrivates, fbOverlayScreenPrivateKey, pScrPriv);
 | |
| 
 | |
|     /* overwrite miCloseScreen with our own */
 | |
|     pScreen->CloseScreen = fbOverlayCloseScreen;
 | |
|     pScreen->CreateScreenResources = fbOverlayCreateScreenResources;
 | |
|     pScreen->CreateWindow = fbOverlayCreateWindow;
 | |
|     pScreen->WindowExposures = fbOverlayWindowExposures;
 | |
|     pScreen->CopyWindow = fbOverlayCopyWindow;
 | |
|     if (bpp == 24 && imagebpp == 32) {
 | |
|         pScreen->ModifyPixmapHeader = fb24_32ModifyPixmapHeader;
 | |
|         pScreen->CreateScreenResources = fb24_32OverlayCreateScreenResources;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 |