/****************************************************************************** * * Copyright (c) 1994, 1995 Hewlett-Packard Company * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of the Hewlett-Packard * Company shall not be used in advertising or otherwise to promote the * sale, use or other dealings in this Software without prior written * authorization from the Hewlett-Packard Company. * * Machine-independent DBE code * *****************************************************************************/ /* INCLUDES */ #ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif #include <X11/X.h> #include <X11/Xproto.h> #include "misc.h" #include "os.h" #include "windowstr.h" #include "scrnintstr.h" #include "pixmapstr.h" #include "extnsionst.h" #include "dixstruct.h" #include "resource.h" #include "opaque.h" #include "dbestruct.h" #include "midbestr.h" #include "regionstr.h" #include "gcstruct.h" #include "inputstr.h" #include "midbe.h" #include "xace.h" #include <stdio.h> static DevPrivateKeyRec miDbeWindowPrivPrivKeyRec; #define miDbeWindowPrivPrivKey (&miDbeWindowPrivPrivKeyRec) /****************************************************************************** * * DBE MI Procedure: miDbeGetVisualInfo * * Description: * * This is the MI function for the DbeGetVisualInfo request. This function * is called through pDbeScreenPriv->GetVisualInfo. This function is also * called for the DbeAllocateBackBufferName request at the extension level; * it is called by ProcDbeAllocateBackBufferName() in dbe.c. * * If memory allocation fails or we can not get the visual info, this * function returns FALSE. Otherwise, it returns TRUE for success. * *****************************************************************************/ static Bool miDbeGetVisualInfo(ScreenPtr pScreen, XdbeScreenVisualInfo *pScrVisInfo) { register int i, j, k; register int count; DepthPtr pDepth; XdbeVisualInfo *visInfo; /* Determine number of visuals for this screen. */ for (i = 0, count = 0; i < pScreen->numDepths; i++) { count += pScreen->allowedDepths[i].numVids; } /* Allocate an array of XdbeVisualInfo items. */ if (!(visInfo = (XdbeVisualInfo *)malloc(count * sizeof(XdbeVisualInfo)))) { return FALSE; /* memory alloc failure */ } for (i = 0, k = 0; i < pScreen->numDepths; i++) { /* For each depth of this screen, get visual information. */ pDepth = &pScreen->allowedDepths[i]; for (j = 0; j < pDepth->numVids; j++) { /* For each visual for this depth of this screen, get visual ID * and visual depth. Since this is MI code, we will always return * the same performance level for all visuals (0). A higher * performance level value indicates higher performance. */ visInfo[k].visual = pDepth->vids[j]; visInfo[k].depth = pDepth->depth; visInfo[k].perflevel = 0; k++; } } /* Record the number of visuals and point visual_depth to * the array of visual info. */ pScrVisInfo->count = count; pScrVisInfo->visinfo = visInfo; return TRUE; /* success */ } /* miDbeGetVisualInfo() */ /****************************************************************************** * * DBE MI Procedure: miAllocBackBufferName * * Description: * * This is the MI function for the DbeAllocateBackBufferName request. * *****************************************************************************/ static int miDbeAllocBackBufferName(WindowPtr pWin, XID bufId, int swapAction) { ScreenPtr pScreen; DbeWindowPrivPtr pDbeWindowPriv; MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; DbeScreenPrivPtr pDbeScreenPriv; GCPtr pGC; xRectangle clearRect; int rc; pScreen = pWin->drawable.pScreen; pDbeWindowPriv = DBE_WINDOW_PRIV(pWin); if (pDbeWindowPriv->nBufferIDs == 0) { /* There is no buffer associated with the window. * We have to create the window priv priv. Remember, the window * priv was created at the DIX level, so all we need to do is * create the priv priv and attach it to the priv. */ pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); /* Setup the window priv priv. */ pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); pDbeWindowPrivPriv->pDbeWindowPriv = pDbeWindowPriv; /* Get a front pixmap. */ if (!(pDbeWindowPrivPriv->pFrontBuffer = (*pScreen->CreatePixmap)(pScreen, pDbeWindowPriv->width, pDbeWindowPriv->height, pWin->drawable.depth, 0))) { return BadAlloc; } /* Get a back pixmap. */ if (!(pDbeWindowPrivPriv->pBackBuffer = (*pScreen->CreatePixmap)(pScreen, pDbeWindowPriv->width, pDbeWindowPriv->height, pWin->drawable.depth, 0))) { (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pFrontBuffer); return BadAlloc; } /* Security creation/labeling check. */ rc = XaceHook(XACE_RESOURCE_ACCESS, serverClient, bufId, dbeDrawableResType, pDbeWindowPrivPriv->pBackBuffer, RT_WINDOW, pWin, DixCreateAccess); /* Make the back pixmap a DBE drawable resource. */ if (rc != Success || !AddResource(bufId, dbeDrawableResType, pDbeWindowPrivPriv->pBackBuffer)) { /* free the buffer and the drawable resource */ FreeResource(bufId, RT_NONE); return (rc == Success) ? BadAlloc : rc; } /* Clear the back buffer. */ pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen); if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) { ValidateGC((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, pGC); clearRect.x = clearRect.y = 0; clearRect.width = pDbeWindowPrivPriv->pBackBuffer->drawable.width; clearRect.height = pDbeWindowPrivPriv->pBackBuffer->drawable.height; (*pGC->ops->PolyFillRect)( (DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, pGC, 1, &clearRect); } FreeScratchGC(pGC); } /* if no buffer associated with the window */ else { /* A buffer is already associated with the window. * Place the new buffer ID information at the head of the ID list. */ /* Associate the new ID with an existing pixmap. */ pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); if (!AddResource(bufId, dbeDrawableResType, (pointer)pDbeWindowPrivPriv->pBackBuffer)) { return BadAlloc; } } return Success; } /* miDbeAllocBackBufferName() */ /****************************************************************************** * * DBE MI Procedure: miDbeAliasBuffers * * Description: * * This function associates all XIDs of a buffer with the back pixmap * stored in the window priv. * *****************************************************************************/ static void miDbeAliasBuffers(DbeWindowPrivPtr pDbeWindowPriv) { int i; MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); for (i = 0; i < pDbeWindowPriv->nBufferIDs; i++) { ChangeResourceValue(pDbeWindowPriv->IDs[i], dbeDrawableResType, (pointer)pDbeWindowPrivPriv->pBackBuffer); } } /* miDbeAliasBuffers() */ /****************************************************************************** * * DBE MI Procedure: miDbeSwapBuffers * * Description: * * This is the MI function for the DbeSwapBuffers request. * *****************************************************************************/ static int miDbeSwapBuffers(ClientPtr client, int *pNumWindows, DbeSwapInfoPtr swapInfo) { DbeScreenPrivPtr pDbeScreenPriv; GCPtr pGC; WindowPtr pWin; MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; PixmapPtr pTmpBuffer; xRectangle clearRect; pWin = swapInfo[0].pWindow; pDbeScreenPriv = DBE_SCREEN_PRIV_FROM_WINDOW(pWin); pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV_FROM_WINDOW(pWin); pGC = GetScratchGC(pWin->drawable.depth, pWin->drawable.pScreen); /* ********************************************************************** ** Setup before swap. ********************************************************************** */ switch(swapInfo[0].swapAction) { case XdbeUndefined: break; case XdbeBackground: break; case XdbeUntouched: ValidateGC((DrawablePtr)pDbeWindowPrivPriv->pFrontBuffer, pGC); (*pGC->ops->CopyArea)((DrawablePtr)pWin, (DrawablePtr)pDbeWindowPrivPriv->pFrontBuffer, pGC, 0, 0, pWin->drawable.width, pWin->drawable.height, 0, 0); break; case XdbeCopied: break; } /* ********************************************************************** ** Swap. ********************************************************************** */ ValidateGC((DrawablePtr)pWin, pGC); (*pGC->ops->CopyArea)((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, (DrawablePtr)pWin, pGC, 0, 0, pWin->drawable.width, pWin->drawable.height, 0, 0); /* ********************************************************************** ** Tasks after swap. ********************************************************************** */ switch(swapInfo[0].swapAction) { case XdbeUndefined: break; case XdbeBackground: if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) { ValidateGC((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, pGC); clearRect.x = 0; clearRect.y = 0; clearRect.width = pDbeWindowPrivPriv->pBackBuffer->drawable.width; clearRect.height = pDbeWindowPrivPriv->pBackBuffer->drawable.height; (*pGC->ops->PolyFillRect)( (DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, pGC, 1, &clearRect); } break; case XdbeUntouched: /* Swap pixmap pointers. */ pTmpBuffer = pDbeWindowPrivPriv->pBackBuffer; pDbeWindowPrivPriv->pBackBuffer = pDbeWindowPrivPriv->pFrontBuffer; pDbeWindowPrivPriv->pFrontBuffer = pTmpBuffer; miDbeAliasBuffers(pDbeWindowPrivPriv->pDbeWindowPriv); break; case XdbeCopied: break; } /* Remove the swapped window from the swap information array and decrement * pNumWindows to indicate to the DIX level how many windows were actually * swapped. */ if (*pNumWindows > 1) { /* We were told to swap more than one window, but we only swapped the * first one. Remove the first window in the list by moving the last * window to the beginning. */ swapInfo[0].pWindow = swapInfo[*pNumWindows - 1].pWindow; swapInfo[0].swapAction = swapInfo[*pNumWindows - 1].swapAction; /* Clear the last window information just to be safe. */ swapInfo[*pNumWindows - 1].pWindow = (WindowPtr)NULL; swapInfo[*pNumWindows - 1].swapAction = 0; } else { /* Clear the window information just to be safe. */ swapInfo[0].pWindow = (WindowPtr)NULL; swapInfo[0].swapAction = 0; } (*pNumWindows)--; FreeScratchGC(pGC); return Success; } /* miSwapBuffers() */ /****************************************************************************** * * DBE MI Procedure: miDbeWinPrivDelete * * Description: * * This is the MI function for deleting the dbeWindowPrivResType resource. * This function is invoked indirectly by calling FreeResource() to free * the resources associated with a DBE buffer ID. There are 5 ways that * miDbeWinPrivDelete() can be called by FreeResource(). They are: * * - A DBE window is destroyed, in which case the DbeDestroyWindow() * wrapper is invoked. The wrapper calls FreeResource() for all DBE * buffer IDs. * * - miDbeAllocBackBufferName() calls FreeResource() to clean up resources * after a buffer allocation failure. * * - The PositionWindow wrapper, miDbePositionWindow(), calls * FreeResource() when it fails to create buffers of the new size. * FreeResource() is called for all DBE buffer IDs. * * - FreeClientResources() calls FreeResource() when a client dies or the * the server resets. * * When FreeResource() is called for a DBE buffer ID, the delete function * for the only other type of DBE resource, dbeDrawableResType, is also * invoked. This delete function (DbeDrawableDelete) is a NOOP to make * resource deletion easier. It is not guaranteed which delete function is * called first. Hence, we will let miDbeWinPrivDelete() free all DBE * resources. * * This function deletes/frees the following stuff associated with * the window private: * * - the ID node in the ID list representing the passed in ID. * * In addition, pDbeWindowPriv->nBufferIDs is decremented. * * If this function is called for the last/only buffer ID for a window, * these are additionally deleted/freed: * * - the front and back pixmaps * - the window priv itself * *****************************************************************************/ static void miDbeWinPrivDelete(DbeWindowPrivPtr pDbeWindowPriv, XID bufId) { MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; if (pDbeWindowPriv->nBufferIDs != 0) { /* We still have at least one more buffer ID associated with this * window. */ return; } /* We have no more buffer IDs associated with this window. We need to * free some stuff. */ pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); /* Destroy the front and back pixmaps. */ if (pDbeWindowPrivPriv->pFrontBuffer) { (*pDbeWindowPriv->pWindow->drawable.pScreen->DestroyPixmap)( pDbeWindowPrivPriv->pFrontBuffer); } if (pDbeWindowPrivPriv->pBackBuffer) { (*pDbeWindowPriv->pWindow->drawable.pScreen->DestroyPixmap)( pDbeWindowPrivPriv->pBackBuffer); } } /* miDbeWinPrivDelete() */ /****************************************************************************** * * DBE MI Procedure: miDbePositionWindow * * Description: * * This function was cloned from miMbxPositionWindow() in mimultibuf.c. * This function resizes the buffer when the window is resized. * *****************************************************************************/ static Bool miDbePositionWindow(WindowPtr pWin, int x, int y) { ScreenPtr pScreen; DbeScreenPrivPtr pDbeScreenPriv; DbeWindowPrivPtr pDbeWindowPriv; int width, height; int dx, dy, dw, dh; int sourcex, sourcey; int destx, desty; int savewidth, saveheight; PixmapPtr pFrontBuffer; PixmapPtr pBackBuffer; Bool clear; GCPtr pGC; xRectangle clearRect; Bool ret; /* ************************************************************************** ** 1. Unwrap the member routine. ************************************************************************** */ pScreen = pWin->drawable.pScreen; pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); pScreen->PositionWindow = pDbeScreenPriv->PositionWindow; /* ************************************************************************** ** 2. Do any work necessary before the member routine is called. ** ** In this case we do not need to do anything. ************************************************************************** */ /* ************************************************************************** ** 3. Call the member routine, saving its result if necessary. ************************************************************************** */ ret = (*pScreen->PositionWindow)(pWin, x, y); /* ************************************************************************** ** 4. Rewrap the member routine, restoring the wrapper value first in case ** the wrapper (or something that it wrapped) change this value. ************************************************************************** */ pDbeScreenPriv->PositionWindow = pScreen->PositionWindow; pScreen->PositionWindow = miDbePositionWindow; /* ************************************************************************** ** 5. Do any work necessary after the member routine has been called. ************************************************************************** */ if (!(pDbeWindowPriv = DBE_WINDOW_PRIV(pWin))) { return ret; } if (pDbeWindowPriv->width == pWin->drawable.width && pDbeWindowPriv->height == pWin->drawable.height) { return ret; } width = pWin->drawable.width; height = pWin->drawable.height; dx = pWin->drawable.x - pDbeWindowPriv->x; dy = pWin->drawable.y - pDbeWindowPriv->y; dw = width - pDbeWindowPriv->width; dh = height - pDbeWindowPriv->height; GravityTranslate (0, 0, -dx, -dy, dw, dh, pWin->bitGravity, &destx, &desty); clear = ((pDbeWindowPriv->width < (unsigned short)width ) || (pDbeWindowPriv->height < (unsigned short)height) || (pWin->bitGravity == ForgetGravity)); sourcex = 0; sourcey = 0; savewidth = pDbeWindowPriv->width; saveheight = pDbeWindowPriv->height; /* Clip rectangle to source and destination. */ if (destx < 0) { savewidth += destx; sourcex -= destx; destx = 0; } if (destx + savewidth > width) { savewidth = width - destx; } if (desty < 0) { saveheight += desty; sourcey -= desty; desty = 0; } if (desty + saveheight > height) { saveheight = height - desty; } pDbeWindowPriv->width = width; pDbeWindowPriv->height = height; pDbeWindowPriv->x = pWin->drawable.x; pDbeWindowPriv->y = pWin->drawable.y; pGC = GetScratchGC (pWin->drawable.depth, pScreen); if (clear) { if ((*pDbeScreenPriv->SetupBackgroundPainter)(pWin, pGC)) { clearRect.x = 0; clearRect.y = 0; clearRect.width = width; clearRect.height = height; } else { clear = FALSE; } } /* Create DBE buffer pixmaps equal to size of resized window. */ pFrontBuffer = (*pScreen->CreatePixmap)(pScreen, width, height, pWin->drawable.depth, 0); pBackBuffer = (*pScreen->CreatePixmap)(pScreen, width, height, pWin->drawable.depth, 0); if (!pFrontBuffer || !pBackBuffer) { /* We failed at creating 1 or 2 of the pixmaps. */ if (pFrontBuffer) { (*pScreen->DestroyPixmap)(pFrontBuffer); } if (pBackBuffer) { (*pScreen->DestroyPixmap)(pBackBuffer); } /* Destroy all buffers for this window. */ while (pDbeWindowPriv) { /* DbeWindowPrivDelete() will free the window private if there no * more buffer IDs associated with this window. */ FreeResource(pDbeWindowPriv->IDs[0], RT_NONE); pDbeWindowPriv = DBE_WINDOW_PRIV(pWin); } FreeScratchGC(pGC); return FALSE; } else { /* Clear out the new DBE buffer pixmaps. */ MiDbeWindowPrivPrivPtr pDbeWindowPrivPriv; pDbeWindowPrivPriv = MI_DBE_WINDOW_PRIV_PRIV(pDbeWindowPriv); /* I suppose this could avoid quite a bit of work if * it computed the minimal area required. */ ValidateGC(&pFrontBuffer->drawable, pGC); if (clear) { (*pGC->ops->PolyFillRect)((DrawablePtr)pFrontBuffer, pGC, 1, &clearRect); } /* Copy the contents of the old front pixmap to the new one. */ if (pWin->bitGravity != ForgetGravity) { (*pGC->ops->CopyArea)((DrawablePtr)pDbeWindowPrivPriv->pFrontBuffer, (DrawablePtr)pFrontBuffer, pGC, sourcex, sourcey, savewidth, saveheight, destx, desty); } ValidateGC(&pBackBuffer->drawable, pGC); if (clear) { (*pGC->ops->PolyFillRect)((DrawablePtr)pBackBuffer , pGC, 1, &clearRect); } /* Copy the contents of the old back pixmap to the new one. */ if (pWin->bitGravity != ForgetGravity) { (*pGC->ops->CopyArea)((DrawablePtr)pDbeWindowPrivPriv->pBackBuffer, (DrawablePtr)pBackBuffer, pGC, sourcex, sourcey, savewidth, saveheight, destx, desty); } /* Destroy the old pixmaps, and point the DBE window priv to the new * pixmaps. */ (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pFrontBuffer); (*pScreen->DestroyPixmap)(pDbeWindowPrivPriv->pBackBuffer); pDbeWindowPrivPriv->pFrontBuffer = pFrontBuffer; pDbeWindowPrivPriv->pBackBuffer = pBackBuffer; /* Make sure all XID are associated with the new back pixmap. */ miDbeAliasBuffers(pDbeWindowPriv); FreeScratchGC(pGC); } return ret; } /* miDbePositionWindow() */ /****************************************************************************** * * DBE MI Procedure: miDbeResetProc * * Description: * * This function is called from DbeResetProc(), which is called at the end * of every server generation. This function peforms any MI-specific * shutdown tasks. * *****************************************************************************/ static void miDbeResetProc(ScreenPtr pScreen) { DbeScreenPrivPtr pDbeScreenPriv; pDbeScreenPriv = DBE_SCREEN_PRIV(pScreen); /* Unwrap wrappers */ pScreen->PositionWindow = pDbeScreenPriv->PositionWindow; } /* miDbeResetProc() */ /****************************************************************************** * * DBE MI Procedure: miDbeInit * * Description: * * This is the MI initialization function called by DbeExtensionInit(). * *****************************************************************************/ Bool miDbeInit(ScreenPtr pScreen, DbeScreenPrivPtr pDbeScreenPriv) { if (!dixRegisterPrivateKey(&miDbeWindowPrivPrivKeyRec, PRIVATE_DBE_WINDOW, sizeof(MiDbeWindowPrivPrivRec))) return FALSE; /* Wrap functions. */ pDbeScreenPriv->PositionWindow = pScreen->PositionWindow; pScreen->PositionWindow = miDbePositionWindow; /* Initialize the per-screen DBE function pointers. */ pDbeScreenPriv->GetVisualInfo = miDbeGetVisualInfo; pDbeScreenPriv->AllocBackBufferName = miDbeAllocBackBufferName; pDbeScreenPriv->SwapBuffers = miDbeSwapBuffers; pDbeScreenPriv->BeginIdiom = 0; pDbeScreenPriv->EndIdiom = 0; pDbeScreenPriv->ResetProc = miDbeResetProc; pDbeScreenPriv->WinPrivDelete = miDbeWinPrivDelete; return TRUE; } /* miDbeInit() */