/* * $XFree86: xc/programs/Xserver/miext/layer/layerinit.c,v 1.6tsi Exp $ * * Copyright © 2001 Keith Packard, member of The XFree86 Project, 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 Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD 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. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include "layerstr.h" int layerScrPrivateIndex; int layerGCPrivateIndex; int layerWinPrivateIndex; int layerGeneration; /* * Call this before wrapping stuff for acceleration, it * gives layer pointers to the raw frame buffer functions */ extern const GCFuncs fbGCFuncs; extern GCFuncs shadowGCFuncs; Bool LayerStartInit (ScreenPtr pScreen) { LayerScreenPtr pScrPriv; if (layerGeneration != serverGeneration) { layerScrPrivateIndex = AllocateScreenPrivateIndex (); if (layerScrPrivateIndex == -1) return FALSE; layerGCPrivateIndex = AllocateGCPrivateIndex (); if (layerGCPrivateIndex == -1) return FALSE; layerWinPrivateIndex = AllocateWindowPrivateIndex (); if (layerWinPrivateIndex == -1) return FALSE; layerGeneration = serverGeneration; } if (!AllocateGCPrivate (pScreen, layerGCPrivateIndex, sizeof (LayerGCRec))) return FALSE; if (!AllocateWindowPrivate (pScreen, layerWinPrivateIndex, sizeof (LayerWinRec))) return FALSE; pScrPriv = (LayerScreenPtr) xalloc (sizeof (LayerScreenRec)); if (!pScrPriv) return FALSE; pScrPriv->nkinds = 0; pScrPriv->kinds = 0; pScrPriv->pLayers = 0; pScreen->devPrivates[layerScrPrivateIndex].ptr = (pointer) pScrPriv; /* * Add fb kind -- always 0 */ if (LayerNewKind (pScreen) < 0) { pScreen->devPrivates[layerScrPrivateIndex].ptr = 0; xfree (pScrPriv); return FALSE; } /* * Add shadow kind -- always 1 */ if (!shadowSetup (pScreen)) return FALSE; if (LayerNewKind (pScreen) < 0) { pScreen->devPrivates[layerScrPrivateIndex].ptr = 0; xfree (pScrPriv->kinds); xfree (pScrPriv); return FALSE; } return TRUE; } /* * Initialize wrappers for each acceleration type and * call this function, it will move the needed functions * into a new LayerKind and replace them with the generic * functions. */ int LayerNewKind (ScreenPtr pScreen) { layerScrPriv(pScreen); LayerKindPtr pLayKind, pLayKinds; #ifdef RENDER PictureScreenPtr ps = GetPictureScreen (pScreen); #endif LayerPtr pLayer; /* * Allocate a new kind structure */ if (pLayScr->kinds) pLayKinds = (LayerKindPtr) xrealloc ((pointer) pLayScr->kinds, (pLayScr->nkinds + 1) * sizeof (LayerKindRec)); else pLayKinds = (LayerKindPtr) xalloc (sizeof (LayerKindRec)); if (!pLayKinds) return -1; /* * Fix up existing layers to point at the new kind */ for (pLayer = pLayScr->pLayers; pLayer; pLayer = pLayer->pNext) { int kind = pLayer->pKind - pLayScr->kinds; pLayer->pKind = &pLayKinds[kind]; } pLayScr->kinds = pLayKinds; pLayKind = &pLayScr->kinds[pLayScr->nkinds]; pLayKind->kind = pLayScr->nkinds; /* * Extract wrapped functions from screen and stick in kind */ pLayKind->CloseScreen = pScreen->CloseScreen; pLayKind->CreateWindow = pScreen->CreateWindow; pLayKind->DestroyWindow = pScreen->DestroyWindow; pLayKind->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; pLayKind->PaintWindowBackground = pScreen->PaintWindowBackground; pLayKind->PaintWindowBorder = pScreen->PaintWindowBorder; pLayKind->CopyWindow = pScreen->CopyWindow; pLayKind->CreatePixmap = pScreen->CreatePixmap; pLayKind->DestroyPixmap = pScreen->DestroyPixmap; pLayKind->CreateGC = pScreen->CreateGC; #ifdef RENDER if (ps) { pLayKind->Composite = ps->Composite; pLayKind->Glyphs = ps->Glyphs; pLayKind->CompositeRects = ps->CompositeRects; } #endif /* * If not underlying frame buffer kind, * replace screen functions with those */ if (pLayKind->kind != 0) { pScreen->CloseScreen = pLayKinds->CloseScreen; pScreen->CreateWindow = pLayKinds->CreateWindow; pScreen->DestroyWindow = pLayKinds->DestroyWindow; pScreen->ChangeWindowAttributes = pLayKinds->ChangeWindowAttributes; pScreen->PaintWindowBackground = pLayKinds->PaintWindowBackground; pScreen->PaintWindowBorder = pLayKinds->PaintWindowBorder; pScreen->CopyWindow = pLayKinds->CopyWindow; pScreen->CreatePixmap = pLayKinds->CreatePixmap; pScreen->DestroyPixmap = pLayKinds->DestroyPixmap; pScreen->CreateGC = pLayKinds->CreateGC; #ifdef RENDER if (ps) { ps->Composite = pLayKinds->Composite; ps->Glyphs = pLayKinds->Glyphs; ps->CompositeRects = pLayKinds->CompositeRects; } #endif } pLayScr->nkinds++; return pLayKind->kind; } /* * Finally, call this function and layer * will wrap the screen functions and prepare for execution */ Bool LayerFinishInit (ScreenPtr pScreen) { #ifdef RENDER PictureScreenPtr ps = GetPictureScreen (pScreen); #endif pScreen->CloseScreen = layerCloseScreen; pScreen->CreateWindow = layerCreateWindow; pScreen->DestroyWindow = layerDestroyWindow; pScreen->ChangeWindowAttributes = layerChangeWindowAttributes; pScreen->PaintWindowBackground = layerPaintWindowBackground; pScreen->PaintWindowBorder = layerPaintWindowBorder; pScreen->CopyWindow = layerCopyWindow; pScreen->CreatePixmap = layerCreatePixmap; pScreen->DestroyPixmap = layerDestroyPixmap; pScreen->CreateGC = layerCreateGC; #ifdef RENDER if (ps) { ps->Composite = layerComposite; ps->Glyphs = layerGlyphs; ps->CompositeRects = layerCompositeRects; } #endif return TRUE; } /* * At any point after LayerStartInit, a new layer can be created. */ LayerPtr LayerCreate (ScreenPtr pScreen, int kind, int depth, PixmapPtr pPixmap, ShadowUpdateProc update, ShadowWindowProc window, int randr, void *closure) { layerScrPriv(pScreen); LayerPtr pLay, *pPrev; LayerKindPtr pLayKind; if (kind < 0 || pLayScr->nkinds <= kind) return 0; pLayKind = &pLayScr->kinds[kind]; pLay = (LayerPtr) xalloc (sizeof (LayerRec)); if (!pLay) return 0; /* * Initialize the layer */ pLay->pNext = 0; pLay->pKind = pLayKind; pLay->refcnt = 1; pLay->windows = 0; pLay->depth = depth; pLay->pPixmap = pPixmap; pLay->update = update; pLay->window = window; pLay->randr = randr; pLay->closure = closure; if (pPixmap == LAYER_SCREEN_PIXMAP) pLay->freePixmap = FALSE; else { pLay->freePixmap = TRUE; if (pPixmap) pPixmap->refcnt++; } REGION_NULL(pScreen, &pLay->region); /* * Hook the layer at the end of the list */ for (pPrev = &pLayScr->pLayers; *pPrev; pPrev = &(*pPrev)->pNext) ; *pPrev = pLay; return pLay; } /* * Change a layer pixmap */ void LayerSetPixmap (ScreenPtr pScreen, LayerPtr pLayer, PixmapPtr pPixmap) { LayerDestroyPixmap (pScreen, pLayer); pLayer->pPixmap = pPixmap; if (pPixmap == LAYER_SCREEN_PIXMAP) pLayer->freePixmap = FALSE; else { if (pPixmap) pPixmap->refcnt++; pLayer->freePixmap = TRUE; } } /* * Destroy a layer. The layer must not contain any windows. */ void LayerDestroy (ScreenPtr pScreen, LayerPtr pLay) { layerScrPriv(pScreen); LayerPtr *pPrev; --pLay->refcnt; if (pLay->refcnt > 0) return; /* * Unhook the layer from the list */ for (pPrev = &pLayScr->pLayers; *pPrev; pPrev = &(*pPrev)->pNext) if (*pPrev == pLay) { *pPrev = pLay->pNext; break; } /* * Free associated storage */ LayerDestroyPixmap (pScreen, pLay); REGION_UNINIT (pScreen, &pLay->region); xfree (pLay); } /* * CloseScreen wrapper */ Bool layerCloseScreen (int index, ScreenPtr pScreen) { layerScrPriv(pScreen); int kind; /* XXX this is a mess -- fbCloseScreen can only be called once, * and yet the intervening layers need to be called as well. */ kind = pLayScr->nkinds - 1; pScreen->CloseScreen = pLayScr->kinds[kind].CloseScreen; (*pScreen->CloseScreen) (index, pScreen); /* * make sure the shadow layer is cleaned up as well */ if (kind != LAYER_SHADOW) xfree (shadowGetScrPriv (pScreen)); xfree (pLayScr->kinds); xfree (pLayScr); pScreen->devPrivates[layerScrPrivateIndex].ptr = 0; return TRUE; }