aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/Xext/mbufpx.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/Xext/mbufpx.c')
-rw-r--r--xorg-server/Xext/mbufpx.c650
1 files changed, 650 insertions, 0 deletions
diff --git a/xorg-server/Xext/mbufpx.c b/xorg-server/Xext/mbufpx.c
new file mode 100644
index 000000000..21d525906
--- /dev/null
+++ b/xorg-server/Xext/mbufpx.c
@@ -0,0 +1,650 @@
+/************************************************************
+
+Copyright 1989, 1998 The Open Group
+
+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.
+
+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 THE
+OPEN GROUP 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 Open Group 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 Open Group.
+
+********************************************************/
+
+#define NEED_REPLIES
+#define NEED_EVENTS
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdio.h>
+#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 "regionstr.h"
+#include "gcstruct.h"
+#include "inputstr.h"
+#include <sys/time.h>
+
+#define _MULTIBUF_SERVER_ /* don't want Xlib structures */
+#define _MULTIBUF_PIXMAP_
+#include <X11/extensions/multibufst.h>
+
+
+static Bool NoopDDA_True() { return TRUE; }
+
+static Bool pixPositionWindow();
+static int pixCreateImageBuffers();
+static void pixDisplayImageBuffers();
+static void pixClearImageBufferArea();
+static void pixDeleteBufferDrawable();
+static void pixWrapScreenFuncs();
+static void pixResetProc();
+
+Bool
+pixMultibufferInit(pScreen, pMBScreen)
+ ScreenPtr pScreen;
+ mbufScreenPtr pMBScreen;
+{
+ int i, j, k;
+ xMbufBufferInfo *pInfo;
+ int nInfo;
+ DepthPtr pDepth;
+ mbufPixmapPrivPtr pMBPriv;
+
+ pMBScreen->CreateImageBuffers = pixCreateImageBuffers;
+ pMBScreen->DestroyImageBuffers = (void (*)())NoopDDA;
+ pMBScreen->DisplayImageBuffers = pixDisplayImageBuffers;
+ pMBScreen->ClearImageBufferArea = pixClearImageBufferArea;
+ pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
+ pMBScreen->ChangeBufferAttributes = NoopDDA_True;
+ pMBScreen->DeleteBufferDrawable = pixDeleteBufferDrawable;
+ pMBScreen->WrapScreenFuncs = pixWrapScreenFuncs;
+ pMBScreen->ResetProc = pixResetProc;
+
+ /* Support every depth and visual combination that the screen does */
+
+ nInfo = 0;
+ for (i = 0; i < pScreen->numDepths; i++)
+ {
+ pDepth = &pScreen->allowedDepths[i];
+ nInfo += pDepth->numVids;
+ }
+
+ pInfo = (xMbufBufferInfo *) xalloc (nInfo * sizeof (xMbufBufferInfo));
+ if (!pInfo)
+ return FALSE;
+
+ k = 0;
+ for (i = 0; i < pScreen->numDepths; i++)
+ {
+ pDepth = &pScreen->allowedDepths[i];
+ for (j = 0; j < pDepth->numVids; j++)
+ {
+ pInfo[k].visualID = pDepth->vids[j];
+ pInfo[k].maxBuffers = 0;
+ pInfo[k].depth = pDepth->depth;
+ k++;
+ }
+ }
+
+ pMBScreen->nInfo = nInfo;
+ pMBScreen->pInfo = pInfo;
+
+ /*
+ * Setup the devPrivate to mbufScreenRec
+ */
+
+ pMBPriv = (mbufPixmapPrivPtr) xalloc(sizeof(* pMBPriv));
+ if (!pMBPriv)
+ {
+ xfree(pInfo);
+ return (FALSE);
+ }
+ pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
+ pMBPriv->PositionWindow = NULL;
+ pMBPriv->funcsWrapped = 0;
+
+ return TRUE;
+}
+
+/*ARGSUSED*/
+static int
+pixCreateImageBuffers (pWin, nbuf, ids, action, hint)
+ WindowPtr pWin;
+ int nbuf;
+ XID *ids;
+ int action;
+ int hint;
+{
+ mbufWindowPtr pMBWindow;
+ mbufBufferPtr pMBBuffer;
+ ScreenPtr pScreen;
+ int width, height, depth;
+ int i;
+
+ pMBWindow = MB_WINDOW_PRIV(pWin);
+
+ width = pWin->drawable.width;
+ height = pWin->drawable.height;
+ depth = pWin->drawable.depth;
+ pScreen = pWin->drawable.pScreen;
+
+ for (i = 0; i < nbuf; i++)
+ {
+ pMBBuffer = &pMBWindow->buffers[i];
+ pMBBuffer->pDrawable = (DrawablePtr)
+ (*pScreen->CreatePixmap) (pScreen, width, height, depth, 0);
+ if (!pMBBuffer->pDrawable)
+ break;
+
+ if (!AddResource (ids[i], MultibufferDrawableResType,
+ (pointer) pMBBuffer->pDrawable))
+ {
+ (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
+ break;
+ }
+ pMBBuffer->pDrawable->id = ids[i];
+
+ /*
+ * In the description of the CreateImageBuffers request:
+ * "If the window is mapped, or if these image buffers have
+ * backing store, their contents will be tiled with the window
+ * background, and zero or more expose events will be generated
+ * for each of these buffers."
+ */
+
+ (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
+ (pMBBuffer, 0,0, 0,0, TRUE);
+ }
+
+ return i;
+}
+
+/*
+ * set up the gc to clear the pixmaps;
+ */
+static Bool
+SetupBackgroundPainter (pWin, pGC)
+ WindowPtr pWin;
+ GCPtr pGC;
+{
+ XID gcvalues[4];
+ int ts_x_origin, ts_y_origin;
+ PixUnion background;
+ int backgroundState;
+ Mask gcmask;
+
+ /*
+ * First take care of any ParentRelative stuff by altering the
+ * tile/stipple origin to match the coordinates of the upper-left
+ * corner of the first ancestor without a ParentRelative background.
+ * This coordinate is, of course, negative.
+ */
+
+ ts_x_origin = ts_y_origin = 0;
+ while (pWin->backgroundState == ParentRelative) {
+ ts_x_origin -= pWin->origin.x;
+ ts_y_origin -= pWin->origin.y;
+ pWin = pWin->parent;
+ }
+ backgroundState = pWin->backgroundState;
+ background = pWin->background;
+
+ switch (backgroundState)
+ {
+ case BackgroundPixel:
+ gcvalues[0] = (XID) background.pixel;
+ gcvalues[1] = FillSolid;
+ gcmask = GCForeground|GCFillStyle;
+ break;
+
+ case BackgroundPixmap:
+ gcvalues[0] = FillTiled;
+ gcvalues[1] = (XID) background.pixmap;
+ gcvalues[2] = ts_x_origin;
+ gcvalues[3] = ts_y_origin;
+ gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin;
+ break;
+
+ default:
+ return FALSE;
+ }
+ DoChangeGC(pGC, gcmask, gcvalues, TRUE);
+ return TRUE;
+}
+
+static void
+MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects)
+ WindowPtr pWin;
+ DrawablePtr pDrawable;
+ int nrects;
+ xRectangle *pRects;
+{
+ GCPtr pGC;
+
+ pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
+ if (SetupBackgroundPainter(pWin, pGC))
+ {
+ ValidateGC(pDrawable, pGC);
+ (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, pRects);
+ }
+ FreeScratchGC(pGC);
+}
+
+static void
+MultibufferPaintBackgroundRegion(pWin, pDrawable, pRegion)
+ WindowPtr pWin;
+ DrawablePtr pDrawable;
+ RegionPtr pRegion;
+{
+ xRectangle *pRects;
+ int nrects = REGION_NUM_RECTS(pRegion);
+ BoxPtr pbox = REGION_RECTS(pRegion);
+
+ pRects = (xRectangle *)xalloc(nrects * sizeof(xRectangle));
+ if (pRects)
+ {
+ int i;
+ for (i = 0; i < nrects; i++)
+ {
+ pRects[i].x = pbox->x1;
+ pRects[i].y = pbox->y1;
+ pRects[i].width = pbox->x2 - pbox->x1;
+ pRects[i].height = pbox->y2 - pbox->y1;
+ }
+ MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects);
+ xfree(pRects);
+ }
+}
+
+static void
+pixDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
+ mbufBufferPtr *ppMBBuffer;
+ mbufWindowPtr *ppMBWindow;
+ int nbuf;
+{
+ GCPtr pGC = NULL;
+ PixmapPtr pPrevPixmap, pNewPixmap;
+ WindowPtr pWin;
+ RegionPtr pExposed;
+ int i;
+ mbufBufferPtr pPrevMBBuffer;
+ XID bool;
+ xRectangle r;
+
+ UpdateCurrentTime ();
+ for (i = 0; i < nbuf; i++)
+ {
+ pWin = ppMBWindow[i]->pWindow;
+
+ /* Time to get a different scratch GC? */
+
+ if (!pGC
+ || pGC->depth != pWin->drawable.depth
+ || pGC->pScreen != pWin->drawable.pScreen)
+ {
+ if (pGC) FreeScratchGC(pGC);
+ pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
+ }
+ pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
+ pPrevPixmap = (PixmapPtr) pPrevMBBuffer->pDrawable;
+ pNewPixmap = (PixmapPtr) ppMBBuffer[i]->pDrawable;
+
+ if (pPrevPixmap == pNewPixmap)
+ {
+ /* "If a specified buffer is already displayed, any delays and
+ * update action will still be performed for that buffer."
+ *
+ * We special-case this because applications do occasionally
+ * request a redundant DisplayImageBuffers, and we can save
+ * strokes by recognizing that the only update action that will
+ * change the buffer contents in this case is Background.
+ */
+ if (ppMBWindow[i]->updateAction == MultibufferUpdateActionBackground)
+ {
+ r.x = r.y = 0;
+ r.width = pWin->drawable.width;
+ r.height = pWin->drawable.height;
+ MultibufferPaintBackgroundRectangles(pWin, (DrawablePtr)pWin,
+ 1, &r);
+ }
+ }
+ else /* different buffer is being displayed */
+ {
+ /* perform update action */
+
+ switch (ppMBWindow[i]->updateAction)
+ {
+ case MultibufferUpdateActionUndefined:
+ break;
+
+ case MultibufferUpdateActionBackground:
+
+ r.x = r.y = 0;
+ r.width = pPrevPixmap->drawable.width;
+ r.height = pPrevPixmap->drawable.height;
+ MultibufferPaintBackgroundRectangles(pWin,
+ (DrawablePtr)pPrevPixmap,
+ 1, &r);
+ break;
+
+ case MultibufferUpdateActionUntouched:
+
+ /* copy the window to the pixmap that represents the
+ * currently displayed buffer
+ */
+
+ if (pPrevMBBuffer->eventMask & ExposureMask)
+ {
+ bool = TRUE;
+ DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
+ }
+ ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
+ pExposed = (*pGC->ops->CopyArea)((DrawablePtr) pWin,
+ (DrawablePtr) pPrevPixmap,
+ pGC,
+ 0, 0,
+ pWin->drawable.width,
+ pWin->drawable.height,
+ 0, 0);
+
+ /* if we couldn't copy the whole window to the buffer,
+ * send expose events (if any client wants them)
+ */
+
+ if (pPrevMBBuffer->eventMask & ExposureMask)
+ { /* some client wants expose events */
+ if (pExposed)
+ {
+ RegionPtr pWinSize;
+ extern RegionPtr CreateUnclippedWinSize();
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ pWinSize = CreateUnclippedWinSize (pWin);
+ /*
+ * pExposed is window-relative, but at this point
+ * pWinSize is screen-relative. Make pWinSize be
+ * window-relative so that region ops involving
+ * pExposed and pWinSize behave sensibly.
+ */
+ REGION_TRANSLATE(pScreen, pWinSize,
+ -pWin->drawable.x,
+ -pWin->drawable.y);
+ REGION_INTERSECT(pScreen, pExposed, pExposed, pWinSize);
+ REGION_DESTROY(pScreen, pWinSize);
+ MultibufferExpose (pPrevMBBuffer, pExposed);
+ REGION_DESTROY(pScreen, pExposed);
+ }
+ bool = FALSE;
+ DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
+ } /* end some client wants expose events */
+
+ break; /* end case MultibufferUpdateActionUntouched */
+
+ case MultibufferUpdateActionCopied:
+
+ ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
+ (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap,
+ (DrawablePtr)pPrevPixmap, pGC,
+ 0, 0, pWin->drawable.width,
+ pWin->drawable.height, 0, 0);
+ break;
+
+ } /* end switch on update action */
+
+ /* display the new buffer */
+
+ ValidateGC ((DrawablePtr)pWin, pGC);
+ (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap, (DrawablePtr)pWin,
+ pGC, 0, 0,
+ pWin->drawable.width, pWin->drawable.height,
+ 0, 0);
+ }
+
+ ppMBWindow[i]->lastUpdate = currentTime;
+ }
+
+ if (pGC) FreeScratchGC (pGC);
+ return;
+}
+
+/*
+ * resize the buffers when the window is resized
+ */
+
+static Bool
+pixPositionWindow (pWin, x, y)
+ WindowPtr pWin;
+ int x, y;
+{
+ ScreenPtr pScreen;
+ mbufPixmapPrivPtr pMBPriv;
+ mbufWindowPtr pMBWindow;
+ mbufBufferPtr pMBBuffer;
+ int width, height;
+ int i;
+ int dx, dy, dw, dh;
+ int sourcex, sourcey;
+ int destx, desty;
+ PixmapPtr pPixmap;
+ GCPtr pGC;
+ int savewidth, saveheight;
+ Bool clear;
+ RegionRec exposedRegion;
+ Bool ret;
+
+ pScreen = pWin->drawable.pScreen;
+ pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
+
+ UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
+ ret = (* pScreen->PositionWindow) (pWin, x, y);
+ REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
+
+ if (!(pMBWindow = MB_WINDOW_PRIV(pWin)))
+ return ret;
+
+ /* if new size is same as old, we're done */
+
+ if (pMBWindow->width == pWin->drawable.width &&
+ pMBWindow->height == pWin->drawable.height)
+ return ret;
+
+ width = pWin->drawable.width;
+ height = pWin->drawable.height;
+ dx = pWin->drawable.x - pMBWindow->x;
+ dy = pWin->drawable.x - pMBWindow->y;
+ dw = width - pMBWindow->width;
+ dh = height - pMBWindow->height;
+ GravityTranslate (0, 0, -dx, -dy, dw, dh,
+ pWin->bitGravity, &destx, &desty);
+
+ /* if the window grew, remember to paint the window background,
+ * and maybe send expose events, for the new areas of the buffers
+ */
+
+ clear = pMBWindow->width < width || pMBWindow->height < height ||
+ pWin->bitGravity == ForgetGravity;
+
+ sourcex = 0;
+ sourcey = 0;
+ savewidth = pMBWindow->width;
+ saveheight = pMBWindow->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;
+
+ pMBWindow->width = width;
+ pMBWindow->height = height;
+ pMBWindow->x = pWin->drawable.x;
+ pMBWindow->y = pWin->drawable.y;
+
+ if (clear)
+ {
+ BoxRec box;
+
+ box.x1 = box.y1 = 0;
+ box.x2 = width;
+ box.y2 = height;
+ REGION_INIT(pScreen, &exposedRegion, &box, 1);
+ if (pWin->bitGravity != ForgetGravity)
+ {
+ RegionRec preservedRegion;
+ box.x1 = destx;
+ box.y1 = desty;
+ box.x2 = destx + savewidth;
+ box.y2 = desty + saveheight;
+ REGION_INIT(pScreen, &preservedRegion, &box, 1);
+ REGION_SUBTRACT(pScreen, &exposedRegion, &exposedRegion, &preservedRegion);
+ REGION_UNINIT(pScreen, &preservedRegion);
+ }
+
+ } /* end if (clear) */
+
+ pGC = GetScratchGC (pWin->drawable.depth, pScreen);
+
+ /* create buffers with new window size */
+
+ for (i = 0; i < pMBWindow->numMultibuffer; i++)
+ {
+ pMBBuffer = &pMBWindow->buffers[i];
+ pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, pWin->drawable.depth,
+ CREATE_PIXMAP_USAGE_SCRATCH);
+ if (!pPixmap)
+ {
+ (* MB_SCREEN_PRIV(pScreen)->DestroyImageBuffers)(pWin);
+ break;
+ }
+ if (clear)
+ {
+ MultibufferPaintBackgroundRegion(pWin, (DrawablePtr)pPixmap, &exposedRegion);
+ MultibufferExpose(pMBBuffer, &exposedRegion);
+ }
+ if (pWin->bitGravity != ForgetGravity)
+ {
+ ValidateGC ((DrawablePtr)pPixmap, pGC);
+ (*pGC->ops->CopyArea) (pMBBuffer->pDrawable, (DrawablePtr)pPixmap,
+ pGC,
+ sourcex, sourcey, savewidth, saveheight,
+ destx, desty);
+ }
+ pPixmap->drawable.id = pMBBuffer->pDrawable->id;
+ (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
+ pMBBuffer->pDrawable = (DrawablePtr) pPixmap;
+ if (i != pMBWindow->displayedMultibuffer)
+ {
+ ChangeResourceValue (pPixmap->drawable.id,
+ MultibufferDrawableResType,
+ (pointer) pPixmap);
+ }
+ }
+ FreeScratchGC (pGC);
+ if (clear)
+ REGION_UNINIT(pScreen, &exposedRegion);
+ return TRUE;
+}
+
+static void
+pixWrapScreenFuncs(pScreen)
+ ScreenPtr pScreen;
+{
+ mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
+ WRAP_SCREEN_FUNC(pScreen, pMBPriv, PositionWindow, pixPositionWindow);
+}
+
+static void
+pixResetProc(pScreen)
+ ScreenPtr pScreen;
+{
+ mbufScreenPtr pMBScreen = MB_SCREEN_PRIV(pScreen);
+ mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
+
+ xfree(pMBScreen->pInfo);
+ xfree(pMBPriv);
+}
+
+static void
+pixClearImageBufferArea(pMBBuffer, x,y, width,height, exposures)
+ mbufBufferPtr pMBBuffer;
+ short x, y;
+ unsigned short width, height;
+ Bool exposures;
+{
+ WindowPtr pWin;
+ ScreenPtr pScreen;
+ BoxRec box;
+ RegionRec region;
+ int w_width, w_height;
+ DrawablePtr pDrawable;
+
+ pWin = pMBBuffer->pMBWindow->pWindow;
+ pScreen = pWin->drawable.pScreen;
+
+ w_width = pWin->drawable.width;
+ w_height = pWin->drawable.height;
+
+ box.x1 = x;
+ box.y1 = y;
+ box.x2 = width ? (box.x1 + width) : w_width;
+ box.y2 = height ? (box.y1 + height) : w_height;
+
+ if (box.x1 < 0) box.x1 = 0;
+ if (box.y1 < 0) box.y1 = 0;
+ if (box.x2 > w_width) box.x2 = w_width;
+ if (box.y2 > w_height) box.y2 = w_height;
+
+ REGION_INIT(pScreen, &region, &box, 1);
+
+ if (pMBBuffer->number == pMBBuffer->pMBWindow->displayedMultibuffer)
+ pDrawable = (DrawablePtr) pWin;
+ else
+ pDrawable = pMBBuffer->pDrawable;
+
+ MultibufferPaintBackgroundRegion(pWin, pDrawable, &region);
+
+ if (exposures)
+ MultibufferExpose(pMBBuffer, &region);
+
+ REGION_UNINIT(pScreen, &region);
+}
+
+static void
+pixDeleteBufferDrawable(pDrawable)
+ DrawablePtr pDrawable;
+{
+ (* pDrawable->pScreen->DestroyPixmap)((PixmapPtr) pDrawable);
+}