First import
[xorg_rtime.git] / xorg-server-1.4 / Xext / mbufpx.c
blob16717d330393962de3e58a24ec9b0ef697c63f5f
1 /************************************************************
3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 ********************************************************/
27 #define NEED_REPLIES
28 #define NEED_EVENTS
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
31 #endif
33 #include <stdio.h>
34 #include <X11/X.h>
35 #include <X11/Xproto.h>
36 #include "misc.h"
37 #include "os.h"
38 #include "windowstr.h"
39 #include "scrnintstr.h"
40 #include "pixmapstr.h"
41 #include "extnsionst.h"
42 #include "dixstruct.h"
43 #include "resource.h"
44 #include "opaque.h"
45 #include "regionstr.h"
46 #include "gcstruct.h"
47 #include "inputstr.h"
48 #include <sys/time.h>
50 #define _MULTIBUF_SERVER_ /* don't want Xlib structures */
51 #define _MULTIBUF_PIXMAP_
52 #include <X11/extensions/multibufst.h>
55 static Bool NoopDDA_True() { return TRUE; }
57 static Bool pixPositionWindow();
58 static int pixCreateImageBuffers();
59 static void pixDisplayImageBuffers();
60 static void pixClearImageBufferArea();
61 static void pixDeleteBufferDrawable();
62 static void pixWrapScreenFuncs();
63 static void pixResetProc();
65 Bool
66 pixMultibufferInit(pScreen, pMBScreen)
67 ScreenPtr pScreen;
68 mbufScreenPtr pMBScreen;
70 int i, j, k;
71 xMbufBufferInfo *pInfo;
72 int nInfo;
73 DepthPtr pDepth;
74 mbufPixmapPrivPtr pMBPriv;
76 pMBScreen->CreateImageBuffers = pixCreateImageBuffers;
77 pMBScreen->DestroyImageBuffers = (void (*)())NoopDDA;
78 pMBScreen->DisplayImageBuffers = pixDisplayImageBuffers;
79 pMBScreen->ClearImageBufferArea = pixClearImageBufferArea;
80 pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
81 pMBScreen->ChangeBufferAttributes = NoopDDA_True;
82 pMBScreen->DeleteBufferDrawable = pixDeleteBufferDrawable;
83 pMBScreen->WrapScreenFuncs = pixWrapScreenFuncs;
84 pMBScreen->ResetProc = pixResetProc;
86 /* Support every depth and visual combination that the screen does */
88 nInfo = 0;
89 for (i = 0; i < pScreen->numDepths; i++)
91 pDepth = &pScreen->allowedDepths[i];
92 nInfo += pDepth->numVids;
95 pInfo = (xMbufBufferInfo *) xalloc (nInfo * sizeof (xMbufBufferInfo));
96 if (!pInfo)
97 return FALSE;
99 k = 0;
100 for (i = 0; i < pScreen->numDepths; i++)
102 pDepth = &pScreen->allowedDepths[i];
103 for (j = 0; j < pDepth->numVids; j++)
105 pInfo[k].visualID = pDepth->vids[j];
106 pInfo[k].maxBuffers = 0;
107 pInfo[k].depth = pDepth->depth;
108 k++;
112 pMBScreen->nInfo = nInfo;
113 pMBScreen->pInfo = pInfo;
116 * Setup the devPrivate to mbufScreenRec
119 pMBPriv = (mbufPixmapPrivPtr) xalloc(sizeof(* pMBPriv));
120 if (!pMBPriv)
122 xfree(pInfo);
123 return (FALSE);
125 pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
126 pMBPriv->PositionWindow = NULL;
127 pMBPriv->funcsWrapped = 0;
129 return TRUE;
132 /*ARGSUSED*/
133 static int
134 pixCreateImageBuffers (pWin, nbuf, ids, action, hint)
135 WindowPtr pWin;
136 int nbuf;
137 XID *ids;
138 int action;
139 int hint;
141 mbufWindowPtr pMBWindow;
142 mbufBufferPtr pMBBuffer;
143 ScreenPtr pScreen;
144 int width, height, depth;
145 int i;
147 pMBWindow = MB_WINDOW_PRIV(pWin);
149 width = pWin->drawable.width;
150 height = pWin->drawable.height;
151 depth = pWin->drawable.depth;
152 pScreen = pWin->drawable.pScreen;
154 for (i = 0; i < nbuf; i++)
156 pMBBuffer = &pMBWindow->buffers[i];
157 pMBBuffer->pDrawable = (DrawablePtr)
158 (*pScreen->CreatePixmap) (pScreen, width, height, depth);
159 if (!pMBBuffer->pDrawable)
160 break;
162 if (!AddResource (ids[i], MultibufferDrawableResType,
163 (pointer) pMBBuffer->pDrawable))
165 (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
166 break;
168 pMBBuffer->pDrawable->id = ids[i];
171 * In the description of the CreateImageBuffers request:
172 * "If the window is mapped, or if these image buffers have
173 * backing store, their contents will be tiled with the window
174 * background, and zero or more expose events will be generated
175 * for each of these buffers."
178 (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
179 (pMBBuffer, 0,0, 0,0, TRUE);
182 return i;
186 * set up the gc to clear the pixmaps;
188 static Bool
189 SetupBackgroundPainter (pWin, pGC)
190 WindowPtr pWin;
191 GCPtr pGC;
193 XID gcvalues[4];
194 int ts_x_origin, ts_y_origin;
195 PixUnion background;
196 int backgroundState;
197 Mask gcmask;
200 * First take care of any ParentRelative stuff by altering the
201 * tile/stipple origin to match the coordinates of the upper-left
202 * corner of the first ancestor without a ParentRelative background.
203 * This coordinate is, of course, negative.
206 ts_x_origin = ts_y_origin = 0;
207 while (pWin->backgroundState == ParentRelative) {
208 ts_x_origin -= pWin->origin.x;
209 ts_y_origin -= pWin->origin.y;
210 pWin = pWin->parent;
212 backgroundState = pWin->backgroundState;
213 background = pWin->background;
215 switch (backgroundState)
217 case BackgroundPixel:
218 gcvalues[0] = (XID) background.pixel;
219 gcvalues[1] = FillSolid;
220 gcmask = GCForeground|GCFillStyle;
221 break;
223 case BackgroundPixmap:
224 gcvalues[0] = FillTiled;
225 gcvalues[1] = (XID) background.pixmap;
226 gcvalues[2] = ts_x_origin;
227 gcvalues[3] = ts_y_origin;
228 gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin;
229 break;
231 default:
232 return FALSE;
234 DoChangeGC(pGC, gcmask, gcvalues, TRUE);
235 return TRUE;
238 static void
239 MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects)
240 WindowPtr pWin;
241 DrawablePtr pDrawable;
242 int nrects;
243 xRectangle *pRects;
245 GCPtr pGC;
247 pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
248 if (SetupBackgroundPainter(pWin, pGC))
250 ValidateGC(pDrawable, pGC);
251 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, pRects);
253 FreeScratchGC(pGC);
256 static void
257 MultibufferPaintBackgroundRegion(pWin, pDrawable, pRegion)
258 WindowPtr pWin;
259 DrawablePtr pDrawable;
260 RegionPtr pRegion;
262 xRectangle *pRects;
263 int nrects = REGION_NUM_RECTS(pRegion);
264 BoxPtr pbox = REGION_RECTS(pRegion);
266 pRects = (xRectangle *)ALLOCATE_LOCAL(nrects * sizeof(xRectangle));
267 if (pRects)
269 int i;
270 for (i = 0; i < nrects; i++)
272 pRects[i].x = pbox->x1;
273 pRects[i].y = pbox->y1;
274 pRects[i].width = pbox->x2 - pbox->x1;
275 pRects[i].height = pbox->y2 - pbox->y1;
277 MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects);
278 DEALLOCATE_LOCAL(pRects);
282 static void
283 pixDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
284 mbufBufferPtr *ppMBBuffer;
285 mbufWindowPtr *ppMBWindow;
286 int nbuf;
288 GCPtr pGC = NULL;
289 PixmapPtr pPrevPixmap, pNewPixmap;
290 WindowPtr pWin;
291 RegionPtr pExposed;
292 int i;
293 mbufBufferPtr pPrevMBBuffer;
294 XID bool;
295 xRectangle r;
297 UpdateCurrentTime ();
298 for (i = 0; i < nbuf; i++)
300 pWin = ppMBWindow[i]->pWindow;
302 /* Time to get a different scratch GC? */
304 if (!pGC
305 || pGC->depth != pWin->drawable.depth
306 || pGC->pScreen != pWin->drawable.pScreen)
308 if (pGC) FreeScratchGC(pGC);
309 pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
311 pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
312 pPrevPixmap = (PixmapPtr) pPrevMBBuffer->pDrawable;
313 pNewPixmap = (PixmapPtr) ppMBBuffer[i]->pDrawable;
315 if (pPrevPixmap == pNewPixmap)
317 /* "If a specified buffer is already displayed, any delays and
318 * update action will still be performed for that buffer."
320 * We special-case this because applications do occasionally
321 * request a redundant DisplayImageBuffers, and we can save
322 * strokes by recognizing that the only update action that will
323 * change the buffer contents in this case is Background.
325 if (ppMBWindow[i]->updateAction == MultibufferUpdateActionBackground)
327 r.x = r.y = 0;
328 r.width = pWin->drawable.width;
329 r.height = pWin->drawable.height;
330 MultibufferPaintBackgroundRectangles(pWin, (DrawablePtr)pWin,
331 1, &r);
334 else /* different buffer is being displayed */
336 /* perform update action */
338 switch (ppMBWindow[i]->updateAction)
340 case MultibufferUpdateActionUndefined:
341 break;
343 case MultibufferUpdateActionBackground:
345 r.x = r.y = 0;
346 r.width = pPrevPixmap->drawable.width;
347 r.height = pPrevPixmap->drawable.height;
348 MultibufferPaintBackgroundRectangles(pWin,
349 (DrawablePtr)pPrevPixmap,
350 1, &r);
351 break;
353 case MultibufferUpdateActionUntouched:
355 /* copy the window to the pixmap that represents the
356 * currently displayed buffer
359 if (pPrevMBBuffer->eventMask & ExposureMask)
361 bool = TRUE;
362 DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
364 ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
365 pExposed = (*pGC->ops->CopyArea)((DrawablePtr) pWin,
366 (DrawablePtr) pPrevPixmap,
367 pGC,
368 0, 0,
369 pWin->drawable.width,
370 pWin->drawable.height,
371 0, 0);
373 /* if we couldn't copy the whole window to the buffer,
374 * send expose events (if any client wants them)
377 if (pPrevMBBuffer->eventMask & ExposureMask)
378 { /* some client wants expose events */
379 if (pExposed)
381 RegionPtr pWinSize;
382 extern RegionPtr CreateUnclippedWinSize();
383 ScreenPtr pScreen = pWin->drawable.pScreen;
384 pWinSize = CreateUnclippedWinSize (pWin);
386 * pExposed is window-relative, but at this point
387 * pWinSize is screen-relative. Make pWinSize be
388 * window-relative so that region ops involving
389 * pExposed and pWinSize behave sensibly.
391 REGION_TRANSLATE(pScreen, pWinSize,
392 -pWin->drawable.x,
393 -pWin->drawable.y);
394 REGION_INTERSECT(pScreen, pExposed, pExposed, pWinSize);
395 REGION_DESTROY(pScreen, pWinSize);
396 MultibufferExpose (pPrevMBBuffer, pExposed);
397 REGION_DESTROY(pScreen, pExposed);
399 bool = FALSE;
400 DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
401 } /* end some client wants expose events */
403 break; /* end case MultibufferUpdateActionUntouched */
405 case MultibufferUpdateActionCopied:
407 ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
408 (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap,
409 (DrawablePtr)pPrevPixmap, pGC,
410 0, 0, pWin->drawable.width,
411 pWin->drawable.height, 0, 0);
412 break;
414 } /* end switch on update action */
416 /* display the new buffer */
418 ValidateGC ((DrawablePtr)pWin, pGC);
419 (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap, (DrawablePtr)pWin,
420 pGC, 0, 0,
421 pWin->drawable.width, pWin->drawable.height,
422 0, 0);
425 ppMBWindow[i]->lastUpdate = currentTime;
428 if (pGC) FreeScratchGC (pGC);
429 return;
433 * resize the buffers when the window is resized
436 static Bool
437 pixPositionWindow (pWin, x, y)
438 WindowPtr pWin;
439 int x, y;
441 ScreenPtr pScreen;
442 mbufPixmapPrivPtr pMBPriv;
443 mbufWindowPtr pMBWindow;
444 mbufBufferPtr pMBBuffer;
445 int width, height;
446 int i;
447 int dx, dy, dw, dh;
448 int sourcex, sourcey;
449 int destx, desty;
450 PixmapPtr pPixmap;
451 GCPtr pGC;
452 int savewidth, saveheight;
453 Bool clear;
454 RegionRec exposedRegion;
455 Bool ret;
457 pScreen = pWin->drawable.pScreen;
458 pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
460 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
461 ret = (* pScreen->PositionWindow) (pWin, x, y);
462 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
464 if (!(pMBWindow = MB_WINDOW_PRIV(pWin)))
465 return ret;
467 /* if new size is same as old, we're done */
469 if (pMBWindow->width == pWin->drawable.width &&
470 pMBWindow->height == pWin->drawable.height)
471 return ret;
473 width = pWin->drawable.width;
474 height = pWin->drawable.height;
475 dx = pWin->drawable.x - pMBWindow->x;
476 dy = pWin->drawable.x - pMBWindow->y;
477 dw = width - pMBWindow->width;
478 dh = height - pMBWindow->height;
479 GravityTranslate (0, 0, -dx, -dy, dw, dh,
480 pWin->bitGravity, &destx, &desty);
482 /* if the window grew, remember to paint the window background,
483 * and maybe send expose events, for the new areas of the buffers
486 clear = pMBWindow->width < width || pMBWindow->height < height ||
487 pWin->bitGravity == ForgetGravity;
489 sourcex = 0;
490 sourcey = 0;
491 savewidth = pMBWindow->width;
492 saveheight = pMBWindow->height;
493 /* clip rectangle to source and destination */
494 if (destx < 0)
496 savewidth += destx;
497 sourcex -= destx;
498 destx = 0;
500 if (destx + savewidth > width)
501 savewidth = width - destx;
502 if (desty < 0)
504 saveheight += desty;
505 sourcey -= desty;
506 desty = 0;
508 if (desty + saveheight > height)
509 saveheight = height - desty;
511 pMBWindow->width = width;
512 pMBWindow->height = height;
513 pMBWindow->x = pWin->drawable.x;
514 pMBWindow->y = pWin->drawable.y;
516 if (clear)
518 BoxRec box;
520 box.x1 = box.y1 = 0;
521 box.x2 = width;
522 box.y2 = height;
523 REGION_INIT(pScreen, &exposedRegion, &box, 1);
524 if (pWin->bitGravity != ForgetGravity)
526 RegionRec preservedRegion;
527 box.x1 = destx;
528 box.y1 = desty;
529 box.x2 = destx + savewidth;
530 box.y2 = desty + saveheight;
531 REGION_INIT(pScreen, &preservedRegion, &box, 1);
532 REGION_SUBTRACT(pScreen, &exposedRegion, &exposedRegion, &preservedRegion);
533 REGION_UNINIT(pScreen, &preservedRegion);
536 } /* end if (clear) */
538 pGC = GetScratchGC (pWin->drawable.depth, pScreen);
540 /* create buffers with new window size */
542 for (i = 0; i < pMBWindow->numMultibuffer; i++)
544 pMBBuffer = &pMBWindow->buffers[i];
545 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, pWin->drawable.depth);
546 if (!pPixmap)
548 (* MB_SCREEN_PRIV(pScreen)->DestroyImageBuffers)(pWin);
549 break;
551 if (clear)
553 MultibufferPaintBackgroundRegion(pWin, (DrawablePtr)pPixmap, &exposedRegion);
554 MultibufferExpose(pMBBuffer, &exposedRegion);
556 if (pWin->bitGravity != ForgetGravity)
558 ValidateGC ((DrawablePtr)pPixmap, pGC);
559 (*pGC->ops->CopyArea) (pMBBuffer->pDrawable, (DrawablePtr)pPixmap,
560 pGC,
561 sourcex, sourcey, savewidth, saveheight,
562 destx, desty);
564 pPixmap->drawable.id = pMBBuffer->pDrawable->id;
565 (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
566 pMBBuffer->pDrawable = (DrawablePtr) pPixmap;
567 if (i != pMBWindow->displayedMultibuffer)
569 ChangeResourceValue (pPixmap->drawable.id,
570 MultibufferDrawableResType,
571 (pointer) pPixmap);
574 FreeScratchGC (pGC);
575 if (clear)
576 REGION_UNINIT(pScreen, &exposedRegion);
577 return TRUE;
580 static void
581 pixWrapScreenFuncs(pScreen)
582 ScreenPtr pScreen;
584 mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
585 WRAP_SCREEN_FUNC(pScreen, pMBPriv, PositionWindow, pixPositionWindow);
588 static void
589 pixResetProc(pScreen)
590 ScreenPtr pScreen;
592 mbufScreenPtr pMBScreen = MB_SCREEN_PRIV(pScreen);
593 mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
595 xfree(pMBScreen->pInfo);
596 xfree(pMBPriv);
599 static void
600 pixClearImageBufferArea(pMBBuffer, x,y, width,height, exposures)
601 mbufBufferPtr pMBBuffer;
602 short x, y;
603 unsigned short width, height;
604 Bool exposures;
606 WindowPtr pWin;
607 ScreenPtr pScreen;
608 BoxRec box;
609 RegionRec region;
610 int w_width, w_height;
611 DrawablePtr pDrawable;
613 pWin = pMBBuffer->pMBWindow->pWindow;
614 pScreen = pWin->drawable.pScreen;
616 w_width = pWin->drawable.width;
617 w_height = pWin->drawable.height;
619 box.x1 = x;
620 box.y1 = y;
621 box.x2 = width ? (box.x1 + width) : w_width;
622 box.y2 = height ? (box.y1 + height) : w_height;
624 if (box.x1 < 0) box.x1 = 0;
625 if (box.y1 < 0) box.y1 = 0;
626 if (box.x2 > w_width) box.x2 = w_width;
627 if (box.y2 > w_height) box.y2 = w_height;
629 REGION_INIT(pScreen, &region, &box, 1);
631 if (pMBBuffer->number == pMBBuffer->pMBWindow->displayedMultibuffer)
632 pDrawable = (DrawablePtr) pWin;
633 else
634 pDrawable = pMBBuffer->pDrawable;
636 MultibufferPaintBackgroundRegion(pWin, pDrawable, &region);
638 if (exposures)
639 MultibufferExpose(pMBBuffer, &region);
641 REGION_UNINIT(pScreen, &region);
644 static void
645 pixDeleteBufferDrawable(pDrawable)
646 DrawablePtr pDrawable;
648 (* pDrawable->pScreen->DestroyPixmap)((PixmapPtr) pDrawable);