]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/Xext/mbufpx.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / Xext / mbufpx.c
1 /************************************************************
2
3 Copyright (c) 1989  X Consortium
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
25
26 ********************************************************/
27
28 /* $XConsortium: mbufpx.c,v 1.5 94/04/17 20:32:54 dpw Exp $ */
29 /* $XFree86: xc/programs/Xserver/Xext/mbufpx.c,v 3.0 1994/05/08 05:17:32 dawes Exp $ */
30 #define NEED_REPLIES
31 #define NEED_EVENTS
32 #include <stdio.h>
33 #include "X.h"
34 #include "Xproto.h"
35 #include "misc.h"
36 #include "os.h"
37 #include "windowstr.h"
38 #include "scrnintstr.h"
39 #include "pixmapstr.h"
40 #include "extnsionst.h"
41 #include "dixstruct.h"
42 #include "resource.h"
43 #include "opaque.h"
44 #include "regionstr.h"
45 #include "gcstruct.h"
46 #include "inputstr.h"
47 #ifndef MINIX
48 #include <sys/time.h>
49 #endif
50
51 #define _MULTIBUF_SERVER_       /* don't want Xlib structures */
52 #define _MULTIBUF_PIXMAP_
53 #include "multibufst.h"
54
55
56 static Bool NoopDDA_True() { return TRUE; }
57
58 static Bool pixPositionWindow();
59 static int  pixCreateImageBuffers();
60 static void pixDisplayImageBuffers();
61 static void pixClearImageBufferArea();
62 static void pixDeleteBufferDrawable();
63 static void pixWrapScreenFuncs();
64 static void pixResetProc();
65
66 Bool
67 pixMultibufferInit(pScreen, pMBScreen)
68     ScreenPtr pScreen;
69     mbufScreenPtr pMBScreen;
70 {
71     int                 i, j, k;
72     xMbufBufferInfo     *pInfo;
73     int                 nInfo;
74     DepthPtr            pDepth;
75     mbufPixmapPrivPtr   pMBPriv;
76
77     pMBScreen->CreateImageBuffers = pixCreateImageBuffers;
78     pMBScreen->DestroyImageBuffers = (void (*)())NoopDDA;
79     pMBScreen->DisplayImageBuffers = pixDisplayImageBuffers;
80     pMBScreen->ClearImageBufferArea = pixClearImageBufferArea;
81     pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
82     pMBScreen->ChangeBufferAttributes = NoopDDA_True;
83     pMBScreen->DeleteBufferDrawable = pixDeleteBufferDrawable;
84     pMBScreen->WrapScreenFuncs = pixWrapScreenFuncs;
85     pMBScreen->ResetProc = pixResetProc;
86
87     /* Support every depth and visual combination that the screen does */
88
89     nInfo = 0;
90     for (i = 0; i < pScreen->numDepths; i++)
91     {
92         pDepth = &pScreen->allowedDepths[i];
93         nInfo += pDepth->numVids;
94     }
95
96     pInfo = (xMbufBufferInfo *) xalloc (nInfo * sizeof (xMbufBufferInfo));
97     if (!pInfo)
98         return FALSE;
99
100     k = 0;
101     for (i = 0; i < pScreen->numDepths; i++)
102     {
103         pDepth = &pScreen->allowedDepths[i];
104         for (j = 0; j < pDepth->numVids; j++)
105         {
106             pInfo[k].visualID = pDepth->vids[j];
107             pInfo[k].maxBuffers = 0;
108             pInfo[k].depth = pDepth->depth;
109             k++;
110         }
111     }
112
113     pMBScreen->nInfo = nInfo;
114     pMBScreen->pInfo = pInfo;
115
116     /*
117      * Setup the devPrivate to mbufScreenRec
118      */
119
120     pMBPriv = (mbufPixmapPrivPtr) xalloc(sizeof(* pMBPriv));
121     if (!pMBPriv)
122     {
123         xfree(pInfo);
124         return (FALSE);
125     }
126     pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
127     pMBPriv->PositionWindow = NULL;
128     pMBPriv->funcsWrapped = 0;
129
130     return TRUE;
131 }
132
133 /*ARGSUSED*/
134 static int
135 pixCreateImageBuffers (pWin, nbuf, ids, action, hint)
136     WindowPtr   pWin;
137     int         nbuf;
138     XID         *ids;
139     int         action;
140     int         hint;
141 {
142     mbufWindowPtr       pMBWindow;
143     mbufBufferPtr       pMBBuffer;
144     ScreenPtr           pScreen;
145     int                 width, height, depth;
146     int                 i;
147
148     pMBWindow = MB_WINDOW_PRIV(pWin);
149
150     width = pWin->drawable.width;
151     height = pWin->drawable.height;
152     depth = pWin->drawable.depth;
153     pScreen = pWin->drawable.pScreen;
154
155     for (i = 0; i < nbuf; i++)
156     {
157         pMBBuffer = &pMBWindow->buffers[i];
158         pMBBuffer->pDrawable = (DrawablePtr)
159             (*pScreen->CreatePixmap) (pScreen, width, height, depth);
160         if (!pMBBuffer->pDrawable)
161             break;
162
163         if (!AddResource (ids[i], MultibufferDrawableResType,
164                           (pointer) pMBBuffer->pDrawable))
165         {
166             (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
167             break;
168         }
169         pMBBuffer->pDrawable->id = ids[i];
170
171         /*
172          * In the description of the CreateImageBuffers request:
173          * "If the window is mapped, or if these image buffers have
174          *  backing store, their contents will be tiled with the window
175          *  background, and zero or more expose events will be generated
176          *  for each of these buffers."
177          */
178
179         (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
180             (pMBBuffer, 0,0, 0,0, TRUE);
181     }
182
183     return i;
184 }
185
186 /*
187  * set up the gc to clear the pixmaps;
188  */
189 static Bool
190 SetupBackgroundPainter (pWin, pGC)
191     WindowPtr   pWin;
192     GCPtr       pGC;
193 {
194     XID             gcvalues[4];
195     int             ts_x_origin, ts_y_origin;
196     PixUnion        background;
197     int             backgroundState;
198     Mask            gcmask;
199
200     /*
201      * First take care of any ParentRelative stuff by altering the
202      * tile/stipple origin to match the coordinates of the upper-left
203      * corner of the first ancestor without a ParentRelative background.
204      * This coordinate is, of course, negative.
205      */
206
207     ts_x_origin = ts_y_origin = 0;
208     while (pWin->backgroundState == ParentRelative) {
209         ts_x_origin -= pWin->origin.x;
210         ts_y_origin -= pWin->origin.y;
211         pWin = pWin->parent;
212     }
213     backgroundState = pWin->backgroundState;
214     background = pWin->background;
215
216     switch (backgroundState)
217     {
218     case BackgroundPixel:
219         gcvalues[0] = (XID) background.pixel;
220         gcvalues[1] = FillSolid;
221         gcmask = GCForeground|GCFillStyle;
222         break;
223
224     case BackgroundPixmap:
225         gcvalues[0] = FillTiled;
226         gcvalues[1] = (XID) background.pixmap;
227         gcvalues[2] = ts_x_origin;
228         gcvalues[3] = ts_y_origin;
229         gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin;
230         break;
231
232     default:
233         return FALSE;
234     }
235     DoChangeGC(pGC, gcmask, gcvalues, TRUE);
236     return TRUE;
237 }
238
239 static void
240 MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects)
241     WindowPtr pWin;
242     DrawablePtr pDrawable;
243     int nrects;
244     xRectangle *pRects;
245 {
246     GCPtr      pGC;
247
248     pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
249     if (SetupBackgroundPainter(pWin, pGC))
250     {
251         ValidateGC(pDrawable, pGC);
252         (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, pRects);
253     }
254     FreeScratchGC(pGC);
255 }
256
257 static void
258 MultibufferPaintBackgroundRegion(pWin, pDrawable, pRegion)
259     WindowPtr pWin;
260     DrawablePtr pDrawable;
261     RegionPtr pRegion;
262 {
263     xRectangle *pRects;
264     int nrects  = REGION_NUM_RECTS(pRegion);
265     BoxPtr pbox = REGION_RECTS(pRegion);
266
267     pRects = (xRectangle *)ALLOCATE_LOCAL(nrects * sizeof(xRectangle));
268     if (pRects)
269     {
270         int i;
271         for (i = 0; i < nrects; i++)
272         {
273             pRects[i].x = pbox->x1;
274             pRects[i].y = pbox->y1;
275             pRects[i].width  = pbox->x2 - pbox->x1;
276             pRects[i].height = pbox->y2 - pbox->y1;
277         }
278         MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects);
279         DEALLOCATE_LOCAL(pRects);
280     }
281 }
282
283 static void
284 pixDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
285     mbufBufferPtr           *ppMBBuffer;
286     mbufWindowPtr           *ppMBWindow;
287     int             nbuf;
288 {
289     GCPtr           pGC = NULL;
290     PixmapPtr       pPrevPixmap, pNewPixmap;
291     WindowPtr       pWin;
292     RegionPtr       pExposed;
293     int             i;
294     mbufBufferPtr  pPrevMBBuffer;
295     XID             bool;
296     xRectangle      r;
297
298     UpdateCurrentTime ();
299     for (i = 0; i < nbuf; i++)
300     {
301         pWin = ppMBWindow[i]->pWindow;
302
303         /* Time to get a different scratch GC? */
304
305         if (!pGC
306             || pGC->depth   != pWin->drawable.depth
307             || pGC->pScreen != pWin->drawable.pScreen)
308         {
309             if (pGC) FreeScratchGC(pGC);
310             pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
311         }
312         pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
313         pPrevPixmap = (PixmapPtr) pPrevMBBuffer->pDrawable;
314         pNewPixmap = (PixmapPtr) ppMBBuffer[i]->pDrawable;
315
316         if (pPrevPixmap == pNewPixmap)
317         {
318           /* "If a specified buffer is already displayed, any delays and
319            *  update action will still be performed for that buffer."
320            *
321            *  We special-case this because applications do occasionally
322            *  request a redundant DisplayImageBuffers, and we can save
323            *  strokes by recognizing that the only update action that will
324            *  change the buffer contents in this case is Background.
325            */
326             if (ppMBWindow[i]->updateAction == MultibufferUpdateActionBackground)
327             {
328                 r.x = r.y = 0;
329                 r.width  = pWin->drawable.width;
330                 r.height = pWin->drawable.height;
331                 MultibufferPaintBackgroundRectangles(pWin, (DrawablePtr)pWin,
332                                                      1, &r);
333             }
334         }
335         else /* different buffer is being displayed */
336         {
337             /* perform update action */
338
339             switch (ppMBWindow[i]->updateAction)
340             {
341             case MultibufferUpdateActionUndefined:
342                 break;
343
344             case MultibufferUpdateActionBackground:
345
346                 r.x = r.y = 0;
347                 r.width  = pPrevPixmap->drawable.width;
348                 r.height = pPrevPixmap->drawable.height;
349                 MultibufferPaintBackgroundRectangles(pWin,
350                                                      (DrawablePtr)pPrevPixmap,
351                                                      1, &r);
352                 break;
353
354             case MultibufferUpdateActionUntouched:
355                 
356                 /* copy the window to the pixmap that represents the
357                  * currently displayed buffer
358                  */
359
360                 if (pPrevMBBuffer->eventMask & ExposureMask)
361                 {
362                     bool = TRUE;
363                     DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
364                 }
365                 ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
366                 pExposed = (*pGC->ops->CopyArea)((DrawablePtr) pWin,
367                                                  (DrawablePtr) pPrevPixmap,
368                                                  pGC,
369                                                  0, 0,
370                                                  pWin->drawable.width,
371                                                  pWin->drawable.height,
372                                                  0, 0);
373
374                 /* if we couldn't copy the whole window to the buffer,
375                  * send expose events (if any client wants them)
376                  */
377
378                 if (pPrevMBBuffer->eventMask & ExposureMask)
379                 { /* some client wants expose events */
380                     if (pExposed)
381                     {
382                         RegionPtr        pWinSize;
383                         extern RegionPtr CreateUnclippedWinSize();
384                         ScreenPtr pScreen = pWin->drawable.pScreen;
385                         pWinSize = CreateUnclippedWinSize (pWin);
386                         /*
387                          * pExposed is window-relative, but at this point
388                          * pWinSize is screen-relative.  Make pWinSize be
389                          * window-relative so that region ops involving
390                          * pExposed and pWinSize behave sensibly.
391                          */
392                         REGION_TRANSLATE(pScreen, pWinSize,
393                                                      -pWin->drawable.x,
394                                                      -pWin->drawable.y);
395                         REGION_INTERSECT(pScreen, pExposed, pExposed, pWinSize);
396                         REGION_DESTROY(pScreen, pWinSize);
397                         MultibufferExpose (pPrevMBBuffer, pExposed);
398                         REGION_DESTROY(pScreen, pExposed);
399                     }
400                     bool = FALSE;
401                     DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
402                 } /* end some client wants expose events */
403
404                 break; /* end case MultibufferUpdateActionUntouched */
405
406             case MultibufferUpdateActionCopied:
407
408                 ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
409                 (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap,
410                                        (DrawablePtr)pPrevPixmap, pGC,
411                                        0, 0, pWin->drawable.width,
412                                        pWin->drawable.height, 0, 0);
413                 break;
414
415             } /* end switch on update action */
416
417             /* display the new buffer */
418
419             ValidateGC ((DrawablePtr)pWin, pGC);
420             (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap, (DrawablePtr)pWin,
421                                    pGC, 0, 0,
422                                    pWin->drawable.width, pWin->drawable.height,
423                                    0, 0);
424         }
425
426         ppMBWindow[i]->lastUpdate = currentTime;
427     }
428
429     if (pGC) FreeScratchGC (pGC);
430     return;
431 }
432
433 /*
434  * resize the buffers when the window is resized
435  */ 
436
437 static Bool
438 pixPositionWindow (pWin, x, y)
439     WindowPtr   pWin;
440     int         x, y;
441 {
442     ScreenPtr       pScreen;
443     mbufPixmapPrivPtr pMBPriv;
444     mbufWindowPtr   pMBWindow;
445     mbufBufferPtr   pMBBuffer;
446     int             width, height;
447     int             i;
448     int             dx, dy, dw, dh;
449     int             sourcex, sourcey;
450     int             destx, desty;
451     PixmapPtr       pPixmap;
452     GCPtr           pGC;
453     int             savewidth, saveheight;
454     Bool            clear;
455     RegionRec       exposedRegion;
456     Bool            ret;
457
458     pScreen = pWin->drawable.pScreen;
459     pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
460
461     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
462     ret = (* pScreen->PositionWindow) (pWin, x, y);
463     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
464
465     if (!(pMBWindow = MB_WINDOW_PRIV(pWin)))
466         return ret;
467
468     /* if new size is same as old, we're done */
469
470     if (pMBWindow->width == pWin->drawable.width &&
471         pMBWindow->height == pWin->drawable.height)
472         return ret;
473
474     width = pWin->drawable.width;
475     height = pWin->drawable.height;
476     dx = pWin->drawable.x - pMBWindow->x;
477     dy = pWin->drawable.x - pMBWindow->y;
478     dw = width - pMBWindow->width;
479     dh = height - pMBWindow->height;
480     GravityTranslate (0, 0, -dx, -dy, dw, dh,
481                       pWin->bitGravity, &destx, &desty);
482
483     /* if the window grew, remember to paint the window background,
484      * and maybe send expose events, for the new areas of the buffers
485      */
486
487     clear = pMBWindow->width < width || pMBWindow->height < height ||
488             pWin->bitGravity == ForgetGravity;
489
490     sourcex = 0;
491     sourcey = 0;
492     savewidth = pMBWindow->width;
493     saveheight = pMBWindow->height;
494     /* clip rectangle to source and destination */
495     if (destx < 0)
496     {
497         savewidth += destx;
498         sourcex -= destx;
499         destx = 0;
500     }
501     if (destx + savewidth > width)
502         savewidth = width - destx;
503     if (desty < 0)
504     {
505         saveheight += desty;
506         sourcey -= desty;
507         desty = 0;
508     }
509     if (desty + saveheight > height)
510         saveheight = height - desty;
511
512     pMBWindow->width = width;
513     pMBWindow->height = height;
514     pMBWindow->x = pWin->drawable.x;
515     pMBWindow->y = pWin->drawable.y;
516
517     if (clear)
518     {
519         BoxRec box;
520
521         box.x1 = box.y1 = 0;
522         box.x2 = width;
523         box.y2 = height;
524         REGION_INIT(pScreen, &exposedRegion, &box, 1);
525         if (pWin->bitGravity != ForgetGravity)
526         {
527             RegionRec preservedRegion;
528             box.x1 = destx;
529             box.y1 = desty;
530             box.x2 = destx + savewidth;
531             box.y2 = desty + saveheight;
532             REGION_INIT(pScreen, &preservedRegion, &box, 1);
533             REGION_SUBTRACT(pScreen, &exposedRegion, &exposedRegion, &preservedRegion);
534             REGION_UNINIT(pScreen, &preservedRegion);
535         }
536
537     } /* end if (clear) */
538
539     pGC = GetScratchGC (pWin->drawable.depth, pScreen);
540
541     /* create buffers with new window size */
542
543     for (i = 0; i < pMBWindow->numMultibuffer; i++)
544     {
545         pMBBuffer = &pMBWindow->buffers[i];
546         pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, pWin->drawable.depth);
547         if (!pPixmap)
548         {
549             (* MB_SCREEN_PRIV(pScreen)->DestroyImageBuffers)(pWin);
550             break;
551         }
552         if (clear)
553         {
554             MultibufferPaintBackgroundRegion(pWin, (DrawablePtr)pPixmap, &exposedRegion);
555             MultibufferExpose(pMBBuffer, &exposedRegion);
556         }
557         if (pWin->bitGravity != ForgetGravity)
558         {
559             ValidateGC ((DrawablePtr)pPixmap, pGC);
560             (*pGC->ops->CopyArea) (pMBBuffer->pDrawable, (DrawablePtr)pPixmap,
561                                    pGC,
562                                    sourcex, sourcey, savewidth, saveheight,
563                                    destx, desty);
564         }
565         pPixmap->drawable.id = pMBBuffer->pDrawable->id;
566         (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
567         pMBBuffer->pDrawable = (DrawablePtr) pPixmap;
568         if (i != pMBWindow->displayedMultibuffer)
569         {
570             ChangeResourceValue (pPixmap->drawable.id,
571                                  MultibufferDrawableResType,
572                                  (pointer) pPixmap);
573         }
574     }
575     FreeScratchGC (pGC);
576     if (clear)
577         REGION_UNINIT(pScreen, &exposedRegion);
578     return TRUE;
579 }
580
581 static void
582 pixWrapScreenFuncs(pScreen)
583     ScreenPtr pScreen;
584 {
585     mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
586     WRAP_SCREEN_FUNC(pScreen, pMBPriv, PositionWindow, pixPositionWindow);
587 }
588
589 static void
590 pixResetProc(pScreen)
591     ScreenPtr pScreen;
592 {
593     mbufScreenPtr pMBScreen = MB_SCREEN_PRIV(pScreen);
594     mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
595
596     xfree(pMBScreen->pInfo);
597     xfree(pMBPriv);
598 }
599
600 static void
601 pixClearImageBufferArea(pMBBuffer, x,y, width,height, exposures)
602     mbufBufferPtr       pMBBuffer;
603     short               x, y;
604     unsigned short      width, height;
605     Bool                exposures;
606 {
607     WindowPtr pWin;
608     ScreenPtr pScreen;
609     BoxRec box;
610     RegionRec region;
611     int w_width, w_height;
612     DrawablePtr pDrawable;
613
614     pWin = pMBBuffer->pMBWindow->pWindow;
615     pScreen = pWin->drawable.pScreen;
616
617     w_width  = pWin->drawable.width;
618     w_height = pWin->drawable.height;
619
620     box.x1 = x;
621     box.y1 = y;
622     box.x2 = width  ? (box.x1 + width)  : w_width;
623     box.y2 = height ? (box.y1 + height) : w_height;
624
625     if (box.x1 < 0)        box.x1 = 0;
626     if (box.y1 < 0)        box.y1 = 0;
627     if (box.x2 > w_width)  box.x2 = w_width;
628     if (box.y2 > w_height) box.y2 = w_height;
629
630     REGION_INIT(pScreen, &region, &box, 1);
631
632     if (pMBBuffer->number == pMBBuffer->pMBWindow->displayedMultibuffer)
633       pDrawable = (DrawablePtr) pWin;
634     else
635       pDrawable = pMBBuffer->pDrawable;
636
637     MultibufferPaintBackgroundRegion(pWin, pDrawable, &region);
638
639     if (exposures)
640         MultibufferExpose(pMBBuffer, &region);
641
642     REGION_UNINIT(pScreen, &region);
643 }
644
645 static void
646 pixDeleteBufferDrawable(pDrawable)
647     DrawablePtr pDrawable;
648 {
649     (* pDrawable->pScreen->DestroyPixmap)((PixmapPtr) pDrawable);
650 }