]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/Xext/mbuf.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / programs / Xserver / Xext / mbuf.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: mbuf.c /main/25 1996/12/02 10:19:23 lehors $ */
29 /* $XFree86: xc/programs/Xserver/Xext/mbuf.c,v 3.3 1997/01/18 06:52:58 dawes Exp $ */
30 #define NEED_REPLIES
31 #define NEED_EVENTS
32 #include <stdio.h>
33 #include "X.h"
34 #include "Xproto.h"
35 #include "window.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 #define _MULTIBUF_SERVER_       /* don't want Xlib structures */
45 #include "regionstr.h"
46 #include "gcstruct.h"
47 #include "inputstr.h"
48 #include "multibufst.h"
49 #if !defined(WIN32) && !defined(MINIX) && !defined(Lynx)
50 #include <sys/time.h>
51 #endif
52
53 /* given an OtherClientPtr obj, get the ClientPtr */
54 #define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
55
56 /* given a MultibufferPtr b, get the ClientPtr */
57 #define bClient(b)   (clients[CLIENT_ID(b->pPixmap->drawable.id)])
58
59 #define ValidEventMasks (ExposureMask|MultibufferClobberNotifyMask|MultibufferUpdateNotifyMask)
60
61 static unsigned char    MultibufferReqCode;
62 static int              MultibufferEventBase;
63 static int              MultibufferErrorBase;
64 int                     MultibufferScreenIndex = -1;
65 int                     MultibufferWindowIndex = -1;
66
67 static void             PerformDisplayRequest (
68 #if NeedFunctionPrototypes
69                                 MultibuffersPtr * /* ppMultibuffers */,
70                                 MultibufferPtr * /* pMultibuffer */,
71                                 int /* nbuf */
72 #endif
73                                 );
74 static Bool             QueueDisplayRequest (
75 #if NeedFunctionPrototypes
76                                 ClientPtr /* client */,
77                                 TimeStamp /* activateTime */
78 #endif
79                                 );
80
81 static void             BumpTimeStamp (
82 #if NeedFunctionPrototypes
83                                 TimeStamp * /* ts */,
84                                 CARD32 /* inc */
85 #endif
86                                 );
87
88 static void             AliasMultibuffer (
89 #if NeedFunctionPrototypes
90                                 MultibuffersPtr /* pMultibuffers */,
91                                 int /* i */
92 #endif
93                                 );
94 static void             RecalculateMultibufferOtherEvents (
95 #if NeedFunctionPrototypes
96                                 MultibufferPtr /* pMultibuffer */
97 #endif
98                                 );
99 static int              EventSelectForMultibuffer(
100 #if NeedFunctionPrototypes
101                                 MultibufferPtr /* pMultibuffer */,
102                                 ClientPtr /* client */,
103                                 Mask /* mask */
104 #endif
105                                 );
106
107 /*
108  * The Pixmap associated with a buffer can be found as a resource
109  * with this type
110  */
111 RESTYPE                 MultibufferDrawableResType;
112 static int              MultibufferDrawableDelete (
113 #if NeedFunctionPrototypes
114                                 pointer /* value */,
115                                 XID /* id */
116 #endif
117                                 );
118 /*
119  * The per-buffer data can be found as a resource with this type.
120  * the resource id of the per-buffer data is the same as the resource
121  * id of the pixmap
122  */
123 static RESTYPE          MultibufferResType;
124 static int              MultibufferDelete (
125 #if NeedFunctionPrototypes
126                                 pointer /* value */,
127                                 XID /* id */
128 #endif
129                                 );
130
131 /*
132  * The per-window data can be found as a resource with this type,
133  * using the window resource id
134  */
135 static RESTYPE          MultibuffersResType;
136 static int              MultibuffersDelete (
137 #if NeedFunctionPrototypes
138                                 pointer /* value */,
139                                 XID /* id */
140 #endif
141                                 );
142
143 /*
144  * Clients other than the buffer creator attach event masks in
145  * OtherClient structures; each has a resource of this type.
146  */
147 static RESTYPE          OtherClientResType;
148 static int              OtherClientDelete (
149 #if NeedFunctionPrototypes
150                                 pointer /* value */,
151                                 XID /* id */
152 #endif
153                                 );
154
155 /****************
156  * MultibufferExtensionInit
157  *
158  * Called from InitExtensions in main()
159  *
160  ****************/
161
162 extern DISPATCH_PROC(ProcGetBufferAttributes);
163
164 static DISPATCH_PROC(ProcClearImageBufferArea);
165 static DISPATCH_PROC(ProcCreateImageBuffers);
166 static DISPATCH_PROC(ProcDestroyImageBuffers);
167 static DISPATCH_PROC(ProcDisplayImageBuffers);
168 static DISPATCH_PROC(ProcGetBufferInfo);
169 static DISPATCH_PROC(ProcGetBufferVersion);
170 static DISPATCH_PROC(ProcGetMBufferAttributes);
171 static DISPATCH_PROC(ProcMultibufferDispatch);
172 static DISPATCH_PROC(ProcSetBufferAttributes);
173 static DISPATCH_PROC(ProcSetMBufferAttributes);
174 static DISPATCH_PROC(SProcClearImageBufferArea);
175 static DISPATCH_PROC(SProcCreateImageBuffers);
176 static DISPATCH_PROC(SProcDestroyImageBuffers);
177 static DISPATCH_PROC(SProcDisplayImageBuffers);
178 static DISPATCH_PROC(SProcGetBufferAttributes);
179 static DISPATCH_PROC(SProcGetBufferInfo);
180 static DISPATCH_PROC(SProcGetBufferVersion);
181 static DISPATCH_PROC(SProcGetMBufferAttributes);
182 static DISPATCH_PROC(SProcMultibufferDispatch);
183 static DISPATCH_PROC(SProcSetBufferAttributes);
184 static DISPATCH_PROC(SProcSetMBufferAttributes);
185
186 static void             MultibufferResetProc(
187 #if NeedFunctionPrototypes
188                                 ExtensionEntry * /* extEntry */
189 #endif
190                                 );
191 static void             SClobberNotifyEvent(
192 #if NeedFunctionPrototypes
193                                 xMbufClobberNotifyEvent * /* from */,
194                                 xMbufClobberNotifyEvent * /* to */
195 # endif
196                                 );
197 static void             SUpdateNotifyEvent(
198 #if NeedFunctionPrototypes
199                                 xMbufUpdateNotifyEvent * /* from */,
200                                 xMbufUpdateNotifyEvent * /* to */
201 #endif
202                                 );
203 static Bool             MultibufferPositionWindow(
204 #if NeedFunctionPrototypes
205                                 WindowPtr /* pWin */,
206                                 int /* x */,
207                                 int /* y */
208 #endif
209                                 );
210
211 static void             SetupBackgroundPainter (
212 #if NeedFunctionPrototypes
213                                 WindowPtr /* pWin */,
214                                 GCPtr /* pGC */
215 #endif
216                                 );
217
218 static int              DeliverEventsToMultibuffer (
219 #if NeedFunctionPrototypes
220                                 MultibufferPtr /* pMultibuffer */,
221                                 xEvent * /* pEvents */,
222                                 int /* count */,
223                                 Mask /* filter */
224 #endif
225                                 );
226
227 void
228 MultibufferExtensionInit()
229 {
230     ExtensionEntry          *extEntry;
231     int                     i, j;
232     ScreenPtr               pScreen;
233     MultibufferScreenPtr    pMultibufferScreen;
234
235     /*
236      * allocate private pointers in windows and screens.  Allocating
237      * window privates may seem like an unnecessary expense, but every
238      * PositionWindow call must check to see if the window is
239      * multi-buffered; a resource lookup is too expensive.
240      */
241     MultibufferScreenIndex = AllocateScreenPrivateIndex ();
242     if (MultibufferScreenIndex < 0)
243         return;
244     MultibufferWindowIndex = AllocateWindowPrivateIndex ();
245     for (i = 0; i < screenInfo.numScreens; i++)
246     {
247         pScreen = screenInfo.screens[i];
248         if (!AllocateWindowPrivate (pScreen, MultibufferWindowIndex, 0) ||
249             !(pMultibufferScreen = (MultibufferScreenPtr) xalloc (sizeof (MultibufferScreenRec))))
250         {
251             for (j = 0; j < i; j++)
252                 xfree (screenInfo.screens[j]->devPrivates[MultibufferScreenIndex].ptr);
253             return;
254         }
255         pScreen->devPrivates[MultibufferScreenIndex].ptr = (pointer) pMultibufferScreen;
256         /*
257          * wrap PositionWindow to resize the pixmap when the window
258          * changes size
259          */
260         pMultibufferScreen->PositionWindow = pScreen->PositionWindow;
261         pScreen->PositionWindow = MultibufferPositionWindow;
262     }
263     /*
264      * create the resource types
265      */
266     MultibufferDrawableResType =
267         CreateNewResourceType(MultibufferDrawableDelete)|RC_CACHED|RC_DRAWABLE;
268     MultibufferResType = CreateNewResourceType(MultibufferDelete);
269     MultibuffersResType = CreateNewResourceType(MultibuffersDelete);
270     OtherClientResType = CreateNewResourceType(OtherClientDelete);
271     if (MultibufferDrawableResType && MultibufferResType &&
272         MultibuffersResType &&  OtherClientResType &&
273         (extEntry = AddExtension(MULTIBUFFER_PROTOCOL_NAME,
274                                  MultibufferNumberEvents, 
275                                  MultibufferNumberErrors,
276                                  ProcMultibufferDispatch, SProcMultibufferDispatch,
277                                  MultibufferResetProc, StandardMinorOpcode)))
278     {
279         MultibufferReqCode = (unsigned char)extEntry->base;
280         MultibufferEventBase = extEntry->eventBase;
281         MultibufferErrorBase = extEntry->errorBase;
282         EventSwapVector[MultibufferEventBase + MultibufferClobberNotify] = (EventSwapPtr) SClobberNotifyEvent;
283         EventSwapVector[MultibufferEventBase + MultibufferUpdateNotify] = (EventSwapPtr) SUpdateNotifyEvent;
284     }
285 }
286
287 /*ARGSUSED*/
288 static void
289 MultibufferResetProc (extEntry)
290 ExtensionEntry  *extEntry;
291 {
292     int                     i;
293     ScreenPtr               pScreen;
294     MultibufferScreenPtr    pMultibufferScreen;
295     
296     if (MultibufferScreenIndex < 0)
297         return;
298     for (i = 0; i < screenInfo.numScreens; i++)
299     {
300         pScreen = screenInfo.screens[i];
301         if (pScreen->devPrivates[MultibufferScreenIndex].ptr)
302         {
303             pMultibufferScreen = (MultibufferScreenPtr) pScreen->devPrivates[MultibufferScreenIndex].ptr;
304             pScreen->PositionWindow = pMultibufferScreen->PositionWindow;
305             xfree (pMultibufferScreen);
306         }
307     }
308 }
309
310 static int
311 ProcGetBufferVersion (client)
312     register ClientPtr  client;
313 {
314     xMbufGetBufferVersionReply  rep;
315     register int                n;
316
317     REQUEST_SIZE_MATCH (xMbufGetBufferVersionReq);
318     rep.type = X_Reply;
319     rep.length = 0;
320     rep.sequenceNumber = client->sequence;
321     rep.majorVersion = MULTIBUFFER_MAJOR_VERSION;
322     rep.minorVersion = MULTIBUFFER_MINOR_VERSION;
323     if (client->swapped) {
324         swaps(&rep.sequenceNumber, n);
325         swapl(&rep.length, n);
326     }
327     WriteToClient(client, sizeof (xMbufGetBufferVersionReply), (char *)&rep);
328     return (client->noClientException);
329 }
330
331 static void
332 SetupBackgroundPainter (pWin, pGC)
333     WindowPtr   pWin;
334     GCPtr       pGC;
335 {
336     pointer         gcvalues[4];
337     int             ts_x_origin, ts_y_origin;
338     PixUnion        background;
339     int             backgroundState;
340     Mask            gcmask;
341
342     /*
343      * First take care of any ParentRelative stuff by altering the
344      * tile/stipple origin to match the coordinates of the upper-left
345      * corner of the first ancestor without a ParentRelative background.
346      * This coordinate is, of course, negative.
347      */
348
349     ts_x_origin = ts_y_origin = 0;
350     while (pWin->backgroundState == ParentRelative) {
351         ts_x_origin -= pWin->origin.x;
352         ts_y_origin -= pWin->origin.y;
353         pWin = pWin->parent;
354     }
355     backgroundState = pWin->backgroundState;
356     background = pWin->background;
357
358     switch (backgroundState)
359     {
360     case BackgroundPixel:
361         gcvalues[0] = (pointer) background.pixel;
362         gcvalues[1] = (pointer) FillSolid;
363         gcmask = GCForeground|GCFillStyle;
364         break;
365
366     case BackgroundPixmap:
367         gcvalues[0] = (pointer) FillTiled;
368         gcvalues[1] = (pointer) background.pixmap;
369         gcvalues[2] = (pointer) ts_x_origin;
370         gcvalues[3] = (pointer) ts_y_origin;
371         gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin;
372         break;
373
374     default:
375         gcvalues[0] = (pointer) GXnoop;
376         gcmask = GCFunction;
377     }
378     DoChangeGC(pGC, gcmask, (XID *)gcvalues, TRUE);
379 }
380
381 int
382 CreateImageBuffers (pWin, nbuf, ids, action, hint)
383     WindowPtr   pWin;
384     int         nbuf;
385     XID         *ids;
386     int         action;
387     int         hint;
388 {
389     MultibuffersPtr     pMultibuffers;
390     MultibufferPtr      pMultibuffer;
391     ScreenPtr           pScreen;
392     int                 width, height, depth;
393     int                 i;
394     GCPtr               pClearGC = NULL;
395     xRectangle          clearRect;
396
397     DestroyImageBuffers(pWin);
398     pMultibuffers = (MultibuffersPtr) xalloc (sizeof (MultibuffersRec) +
399                                               nbuf * sizeof (MultibufferRec));
400     if (!pMultibuffers)
401         return BadAlloc;
402     pMultibuffers->pWindow = pWin;
403     pMultibuffers->buffers = (MultibufferPtr) (pMultibuffers + 1);
404     pMultibuffers->refcnt = pMultibuffers->numMultibuffer = 0;
405     if (!AddResource (pWin->drawable.id, MultibuffersResType, (pointer) pMultibuffers))
406         return BadAlloc;
407     width = pWin->drawable.width;
408     height = pWin->drawable.height;
409     depth = pWin->drawable.depth;
410     pScreen = pWin->drawable.pScreen;
411
412     if (pWin->backgroundState != None)
413     {
414         pClearGC = GetScratchGC (pWin->drawable.depth, pScreen);
415         SetupBackgroundPainter (pWin, pClearGC);
416         clearRect.x = clearRect.y = 0;
417         clearRect.width = width;
418         clearRect.height = height;
419     }
420
421     for (i = 0; i < nbuf; i++)
422     {
423         pMultibuffer = &pMultibuffers->buffers[i];
424         pMultibuffer->eventMask = 0L;
425         pMultibuffer->otherEventMask = 0L;
426         pMultibuffer->otherClients = (OtherClientsPtr) NULL;
427         pMultibuffer->number = i;
428         pMultibuffer->side = MultibufferSideMono;
429         pMultibuffer->clobber = MultibufferUnclobbered;
430         pMultibuffer->pMultibuffers = pMultibuffers;
431         if (!AddResource (ids[i], MultibufferResType, (pointer) pMultibuffer))
432             break;
433         pMultibuffer->pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, depth);
434         if (!pMultibuffer->pPixmap)
435             break;
436         if (!AddResource (ids[i], MultibufferDrawableResType, (pointer) pMultibuffer->pPixmap))
437         {
438             FreeResource (ids[i], MultibufferResType);
439             (*pScreen->DestroyPixmap) (pMultibuffer->pPixmap);
440             break;
441         }
442         pMultibuffer->pPixmap->drawable.id = ids[i];
443
444         if (i > 0 && pClearGC)
445         {
446             ValidateGC((DrawablePtr)pMultibuffer->pPixmap, pClearGC);
447             (*pClearGC->ops->PolyFillRect)((DrawablePtr)pMultibuffer->pPixmap,
448                                            pClearGC, 1, &clearRect);
449         }
450     }
451     pMultibuffers->numMultibuffer = i;
452     pMultibuffers->refcnt = i;
453     pMultibuffers->displayedMultibuffer = -1;
454     if (i > 0)
455         AliasMultibuffer (pMultibuffers, 0);
456     pMultibuffers->updateAction = action;
457     pMultibuffers->updateHint = hint;
458     pMultibuffers->windowMode = MultibufferModeMono;
459     pMultibuffers->lastUpdate.months = 0;
460     pMultibuffers->lastUpdate.milliseconds = 0;
461     pMultibuffers->width = width;
462     pMultibuffers->height = height;
463     pWin->devPrivates[MultibufferWindowIndex].ptr = (pointer) pMultibuffers;
464     if (pClearGC) FreeScratchGC(pClearGC);
465     return Success;
466 }
467
468 static int
469 ProcCreateImageBuffers (client)
470     register ClientPtr  client;
471 {
472     REQUEST(xMbufCreateImageBuffersReq);
473     xMbufCreateImageBuffersReply        rep;
474     register int                n;
475     WindowPtr                   pWin;
476     XID                         *ids;
477     int                         len, nbuf;
478     int                         i;
479     int                         err;
480
481     REQUEST_AT_LEAST_SIZE (xMbufCreateImageBuffersReq);
482     len = stuff->length - (sizeof(xMbufCreateImageBuffersReq) >> 2);
483     if (len == 0)
484         return BadLength;
485     if (!(pWin = LookupWindow (stuff->window, client)))
486         return BadWindow;
487     if (pWin->drawable.class == InputOnly)
488         return BadMatch;
489     switch (stuff->updateAction)
490     {
491     case MultibufferUpdateActionUndefined:
492     case MultibufferUpdateActionBackground:
493     case MultibufferUpdateActionUntouched:
494     case MultibufferUpdateActionCopied:
495         break;
496     default:
497         client->errorValue = stuff->updateAction;
498         return BadValue;
499     }
500     switch (stuff->updateHint)
501     {
502     case MultibufferUpdateHintFrequent:
503     case MultibufferUpdateHintIntermittent:
504     case MultibufferUpdateHintStatic:
505         break;
506     default:
507         client->errorValue = stuff->updateHint;
508         return BadValue;
509     }
510     nbuf = len;
511     ids = (XID *) &stuff[1];
512     for (i = 0; i < nbuf; i++)
513     {
514         LEGAL_NEW_RESOURCE(ids[i], client);
515     }
516     err = CreateImageBuffers (pWin, nbuf, ids,
517                               stuff->updateAction, stuff->updateHint);
518     if (err != Success)
519         return err;
520     rep.type = X_Reply;
521     rep.length = 0;
522     rep.sequenceNumber = client->sequence;
523     rep.numberBuffer = ((MultibuffersPtr) (pWin->devPrivates[MultibufferWindowIndex].ptr))->numMultibuffer;
524     if (client->swapped)
525     {
526         swaps(&rep.sequenceNumber, n);
527         swapl(&rep.length, n);
528         swaps(&rep.numberBuffer, n);
529     }
530     WriteToClient(client, sizeof (xMbufCreateImageBuffersReply), (char *)&rep);
531     return (client->noClientException);
532 }
533
534 static int
535 ProcDisplayImageBuffers (client)
536     register ClientPtr  client;
537 {
538     REQUEST(xMbufDisplayImageBuffersReq);
539     MultibufferPtr          *pMultibuffer;
540     MultibuffersPtr         *ppMultibuffers;
541     int             nbuf;
542     XID             *ids;
543     int             i, j;
544     CARD32          minDelay;
545     TimeStamp       activateTime, bufferTime;
546     
547     REQUEST_AT_LEAST_SIZE (xMbufDisplayImageBuffersReq);
548     nbuf = stuff->length - (sizeof (xMbufDisplayImageBuffersReq) >> 2);
549     if (!nbuf)
550         return Success;
551     minDelay = stuff->minDelay;
552     ids = (XID *) &stuff[1];
553     ppMultibuffers = (MultibuffersPtr *) ALLOCATE_LOCAL(nbuf * sizeof (MultibuffersPtr));
554     pMultibuffer = (MultibufferPtr *) ALLOCATE_LOCAL(nbuf * sizeof (MultibufferPtr));
555     if (!ppMultibuffers || !pMultibuffer)
556     {
557         if (ppMultibuffers) DEALLOCATE_LOCAL(ppMultibuffers);
558         if (pMultibuffer)   DEALLOCATE_LOCAL(pMultibuffer);
559         client->errorValue = 0;
560         return BadAlloc;
561     }
562     activateTime.months = 0;
563     activateTime.milliseconds = 0;
564     for (i = 0; i < nbuf; i++)
565     {
566         pMultibuffer[i] = (MultibufferPtr) LookupIDByType (ids[i], MultibufferResType);
567         if (!pMultibuffer[i])
568         {
569             DEALLOCATE_LOCAL(ppMultibuffers);
570             DEALLOCATE_LOCAL(pMultibuffer);
571             client->errorValue = ids[i];
572             return MultibufferErrorBase + MultibufferBadBuffer;
573         }
574         ppMultibuffers[i] = pMultibuffer[i]->pMultibuffers;
575         for (j = 0; j < i; j++)
576         {
577             if (ppMultibuffers[i] == ppMultibuffers[j])
578             {
579                 DEALLOCATE_LOCAL(ppMultibuffers);
580                 DEALLOCATE_LOCAL(pMultibuffer);
581                 client->errorValue = ids[i];
582                 return BadMatch;
583             }
584         }
585         bufferTime = ppMultibuffers[i]->lastUpdate;
586         BumpTimeStamp (&bufferTime, minDelay);
587         if (CompareTimeStamps (bufferTime, activateTime) == LATER)
588             activateTime = bufferTime;
589     }
590     UpdateCurrentTime ();
591     if (CompareTimeStamps (activateTime, currentTime) == LATER &&
592         QueueDisplayRequest (client, activateTime))
593     {
594         ;
595     }
596     else
597         PerformDisplayRequest (ppMultibuffers, pMultibuffer, nbuf);
598     DEALLOCATE_LOCAL(ppMultibuffers);
599     DEALLOCATE_LOCAL(pMultibuffer);
600     return Success;
601 }
602
603 static int
604 ProcDestroyImageBuffers (client)
605     register ClientPtr  client;
606 {
607     REQUEST (xMbufDestroyImageBuffersReq);
608     WindowPtr   pWin;
609
610     REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq);
611     if (!(pWin = LookupWindow (stuff->window, client)))
612         return BadWindow;
613     DestroyImageBuffers (pWin);
614     return Success;
615 }
616
617 static int
618 ProcSetMBufferAttributes (client)
619     register ClientPtr  client;
620 {
621     REQUEST (xMbufSetMBufferAttributesReq);
622     WindowPtr   pWin;
623     MultibuffersPtr     pMultibuffers;
624     int         len;
625     Mask        vmask;
626     Mask        index2;
627     CARD32      updateHint;
628     XID         *vlist;
629
630     REQUEST_AT_LEAST_SIZE (xMbufSetMBufferAttributesReq);
631     pWin = LookupWindow (stuff->window, client);
632     if (!pWin)
633         return BadWindow;
634     pMultibuffers = (MultibuffersPtr)LookupIDByType (pWin->drawable.id, MultibuffersResType);
635     if (!pMultibuffers)
636         return BadMatch;
637     len = stuff->length - (sizeof (xMbufSetMBufferAttributesReq) >> 2);
638     vmask = stuff->valueMask;
639     if (len != Ones (vmask))
640         return BadLength;
641     vlist = (XID *) &stuff[1];
642     while (vmask)
643     {
644         index2 = (Mask) lowbit (vmask);
645         vmask &= ~index2;
646         switch (index2)
647         {
648         case MultibufferWindowUpdateHint:
649             updateHint = (CARD32) *vlist;
650             switch (updateHint)
651             {
652             case MultibufferUpdateHintFrequent:
653             case MultibufferUpdateHintIntermittent:
654             case MultibufferUpdateHintStatic:
655                 pMultibuffers->updateHint = updateHint;
656                 break;
657             default:
658                 client->errorValue = updateHint;
659                 return BadValue;
660             }
661             vlist++;
662             break;
663         default:
664             client->errorValue = stuff->valueMask;
665             return BadValue;
666         }
667     }
668     return Success;
669 }
670
671 static int
672 ProcGetMBufferAttributes (client)
673     ClientPtr   client;
674 {
675     REQUEST (xMbufGetMBufferAttributesReq);
676     WindowPtr   pWin;
677     MultibuffersPtr     pMultibuffers;
678     XID         *ids;
679     xMbufGetMBufferAttributesReply  rep;
680     int         i, n;
681
682     REQUEST_SIZE_MATCH (xMbufGetMBufferAttributesReq);
683     pWin = LookupWindow (stuff->window, client);
684     if (!pWin)
685         return BadWindow;
686     pMultibuffers = (MultibuffersPtr)LookupIDByType (pWin->drawable.id, MultibuffersResType);
687     if (!pMultibuffers)
688         return BadAccess;
689     ids = (XID *) ALLOCATE_LOCAL (pMultibuffers->numMultibuffer * sizeof (XID));
690     if (!ids)
691         return BadAlloc;
692     for (i = 0; i < pMultibuffers->numMultibuffer; i++)
693         ids[i] = pMultibuffers->buffers[i].pPixmap->drawable.id;
694     rep.type = X_Reply;
695     rep.sequenceNumber = client->sequence;
696     rep.length = pMultibuffers->numMultibuffer;
697     rep.displayedBuffer = pMultibuffers->displayedMultibuffer;
698     rep.updateAction = pMultibuffers->updateAction;
699     rep.updateHint = pMultibuffers->updateHint;
700     rep.windowMode = pMultibuffers->windowMode;
701     if (client->swapped)
702     {
703         swaps(&rep.sequenceNumber, n);
704         swapl(&rep.length, n);
705         swaps(&rep.displayedBuffer, n);
706         SwapLongs (ids, pMultibuffers->numMultibuffer);
707     }
708     WriteToClient (client, sizeof(xMbufGetMBufferAttributesReply),
709                    (char *)&rep);
710     WriteToClient (client, (int)(pMultibuffers->numMultibuffer * sizeof (XID)),
711                    (char *)ids);
712     DEALLOCATE_LOCAL((pointer) ids);
713     return client->noClientException;
714 }
715
716 static int
717 ProcSetBufferAttributes (client)
718     register ClientPtr  client;
719 {
720     REQUEST(xMbufSetBufferAttributesReq);
721     MultibufferPtr      pMultibuffer;
722     int         len;
723     Mask        vmask, index2;
724     XID         *vlist;
725     Mask        eventMask;
726     int         result;
727
728     REQUEST_AT_LEAST_SIZE (xMbufSetBufferAttributesReq);
729     pMultibuffer = (MultibufferPtr) LookupIDByType (stuff->buffer, MultibufferResType);
730     if (!pMultibuffer)
731         return MultibufferErrorBase + MultibufferBadBuffer;
732     len = stuff->length - (sizeof (xMbufSetBufferAttributesReq) >> 2);
733     vmask = stuff->valueMask;
734     if (len != Ones (vmask))
735         return BadLength;
736     vlist = (XID *) &stuff[1];
737     while (vmask)
738     {
739         index2 = (Mask) lowbit (vmask);
740         vmask &= ~index2;
741         switch (index2)
742         {
743         case MultibufferBufferEventMask:
744             eventMask = (Mask) *vlist;
745             vlist++;
746             result = EventSelectForMultibuffer (pMultibuffer, client, eventMask);
747             if (result != Success)
748                 return result;
749             break;
750         default:
751             client->errorValue = stuff->valueMask;
752             return BadValue;
753         }
754     }
755     return Success;
756 }
757
758 int
759 ProcGetBufferAttributes (client)
760     register ClientPtr  client;
761 {
762     REQUEST(xMbufGetBufferAttributesReq);
763     MultibufferPtr      pMultibuffer;
764     xMbufGetBufferAttributesReply       rep;
765     OtherClientsPtr             other;
766     int                         n;
767
768     REQUEST_SIZE_MATCH (xMbufGetBufferAttributesReq);
769     pMultibuffer = (MultibufferPtr) LookupIDByType (stuff->buffer, MultibufferResType);
770     if (!pMultibuffer)
771         return MultibufferErrorBase + MultibufferBadBuffer;
772     rep.type = X_Reply;
773     rep.sequenceNumber = client->sequence;
774     rep.length = 0;
775     rep.window = pMultibuffer->pMultibuffers->pWindow->drawable.id;
776     if (bClient (pMultibuffer) == client)
777         rep.eventMask = pMultibuffer->eventMask;
778     else
779     {
780         rep.eventMask = (Mask) 0L;
781         for (other = pMultibuffer->otherClients; other; other = other->next)
782             if (SameClient (other, client))
783             {
784                 rep.eventMask = other->mask;
785                 break;
786             }
787     }
788     rep.bufferIndex = pMultibuffer->number;
789     rep.side = pMultibuffer->side;
790     if (client->swapped)
791     {
792         swaps(&rep.sequenceNumber, n);
793         swapl(&rep.length, n);
794         swapl(&rep.window, n);
795         swapl(&rep.eventMask, n);
796         swaps(&rep.bufferIndex, n);
797     }
798     WriteToClient(client, sizeof (xMbufGetBufferAttributesReply), (char *)&rep);
799     return (client->noClientException);
800 }
801
802 static int
803 ProcGetBufferInfo (client)
804     register ClientPtr  client;
805 {
806     REQUEST (xMbufGetBufferInfoReq);
807     DrawablePtr             pDrawable;
808     xMbufGetBufferInfoReply rep;
809     ScreenPtr               pScreen;
810     int                     i, j, k;
811     int                     n;
812     xMbufBufferInfo         *pInfo;
813     int                     nInfo;
814     DepthPtr                pDepth;
815
816     pDrawable = (DrawablePtr) LookupDrawable (stuff->drawable, client);
817     if (!pDrawable)
818         return BadDrawable;
819     pScreen = pDrawable->pScreen;
820     nInfo = 0;
821     for (i = 0; i < pScreen->numDepths; i++)
822     {
823         pDepth = &pScreen->allowedDepths[i];
824         nInfo += pDepth->numVids;
825     }
826     pInfo = (xMbufBufferInfo *)
827                 ALLOCATE_LOCAL (nInfo * sizeof (xMbufBufferInfo));
828     if (!pInfo)
829         return BadAlloc;
830
831     rep.type = X_Reply;
832     rep.sequenceNumber = client->sequence;
833     rep.length = nInfo * (sizeof (xMbufBufferInfo) >> 2);
834     rep.normalInfo = nInfo;
835     rep.stereoInfo = 0;
836     if (client->swapped)
837     {
838         swaps(&rep.sequenceNumber, n);
839         swapl(&rep.length, n);
840         swaps(&rep.normalInfo, n);
841         swaps(&rep.stereoInfo, n);
842     }
843
844     k = 0;
845     for (i = 0; i < pScreen->numDepths; i++)
846     {
847         pDepth = &pScreen->allowedDepths[i];
848         for (j = 0; j < pDepth->numVids; j++)
849         {
850             pInfo[k].visualID = pDepth->vids[j];
851             pInfo[k].maxBuffers = 0;
852             pInfo[k].depth = pDepth->depth;
853             if (client->swapped)
854             {
855                 swapl (&pInfo[k].visualID, n);
856                 swaps (&pInfo[k].maxBuffers, n);
857             }
858             k++;
859         }
860     }
861     WriteToClient (client, sizeof (xMbufGetBufferInfoReply), (pointer) &rep);
862     WriteToClient (client, (int) nInfo * sizeof (xMbufBufferInfo), (pointer) pInfo);
863     DEALLOCATE_LOCAL ((pointer) pInfo);
864     return client->noClientException;
865 }
866
867 static int
868 ProcClearImageBufferArea (client)
869     register ClientPtr  client;
870 {
871     REQUEST (xMbufClearImageBufferAreaReq);
872     MultibufferPtr      pMultibuffer;
873     WindowPtr pWin;
874     xRectangle clearRect;
875     int width, height;
876     DrawablePtr pDrawable;
877     ScreenPtr pScreen;
878
879     REQUEST_SIZE_MATCH (xMbufClearImageBufferAreaReq);
880     pMultibuffer = (MultibufferPtr) LookupIDByType (stuff->buffer, MultibufferResType);
881     if (!pMultibuffer)
882         return MultibufferErrorBase + MultibufferBadBuffer;
883     if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse))
884     {
885         client->errorValue = stuff->exposures;
886         return(BadValue);
887     }
888     pWin = pMultibuffer->pMultibuffers->pWindow;
889     width  = pWin->drawable.width;
890     height = pWin->drawable.height;
891     pScreen = pWin->drawable.pScreen;
892
893     clearRect.x = stuff->x;
894     clearRect.y = stuff->y;
895     clearRect.width  = stuff->width  ? stuff->width  : width;
896     clearRect.height = stuff->height ? stuff->height : height;
897
898     if (pWin->backgroundState != None)
899     {
900         GCPtr pClearGC;
901         pClearGC = GetScratchGC (pWin->drawable.depth, pScreen);
902         SetupBackgroundPainter (pWin, pClearGC);
903
904         if (pMultibuffer->number == pMultibuffer->pMultibuffers->displayedMultibuffer)
905             pDrawable = (DrawablePtr)pWin;
906         else
907             pDrawable = (DrawablePtr)pMultibuffer->pPixmap;
908
909         ValidateGC(pDrawable, pClearGC);
910         (*pClearGC->ops->PolyFillRect) (pDrawable, pClearGC, 1, &clearRect);
911         FreeScratchGC(pClearGC);
912     }
913
914     if (stuff->exposures)
915     {
916         RegionRec region;
917         BoxRec box;
918         box.x1 = clearRect.x;
919         box.y1 = clearRect.y;
920         box.x2 = clearRect.x + clearRect.width;
921         box.y2 = clearRect.y + clearRect.height;
922         REGION_INIT(pScreen, &region, &box, 1);
923         MultibufferExpose(pMultibuffer, &region);
924         REGION_UNINIT(pScreen, &region);
925     }
926     return Success;
927 }
928
929 static int
930 ProcMultibufferDispatch (client)
931     register ClientPtr  client;
932 {
933     REQUEST(xReq);
934     switch (stuff->data) {
935     case X_MbufGetBufferVersion:
936         return ProcGetBufferVersion (client);
937     case X_MbufCreateImageBuffers:
938         return ProcCreateImageBuffers (client);
939     case X_MbufDisplayImageBuffers:
940         return ProcDisplayImageBuffers (client);
941     case X_MbufDestroyImageBuffers:
942         return ProcDestroyImageBuffers (client);
943     case X_MbufSetMBufferAttributes:
944         return ProcSetMBufferAttributes (client);
945     case X_MbufGetMBufferAttributes:
946         return ProcGetMBufferAttributes (client);
947     case X_MbufSetBufferAttributes:
948         return ProcSetBufferAttributes (client);
949     case X_MbufGetBufferAttributes:
950         return ProcGetBufferAttributes (client);
951     case X_MbufGetBufferInfo:
952         return ProcGetBufferInfo (client);
953     case X_MbufClearImageBufferArea:
954         return ProcClearImageBufferArea (client);
955     default:
956         return BadRequest;
957     }
958 }
959
960 static int
961 SProcGetBufferVersion (client)
962     register ClientPtr  client;
963 {
964     register int    n;
965     REQUEST (xMbufGetBufferVersionReq);
966
967     swaps (&stuff->length, n);
968     return ProcGetBufferVersion (client);
969 }
970
971 static int
972 SProcCreateImageBuffers (client)
973     register ClientPtr  client;
974 {
975     register int    n;
976     REQUEST (xMbufCreateImageBuffersReq);
977
978     swaps (&stuff->length, n);
979     REQUEST_AT_LEAST_SIZE (xMbufCreateImageBuffersReq);
980     swapl (&stuff->window, n);
981     SwapRestL(stuff);
982     return ProcCreateImageBuffers (client);
983 }
984
985 static int
986 SProcDisplayImageBuffers (client)
987     register ClientPtr  client;
988 {
989     register int    n;
990     REQUEST (xMbufDisplayImageBuffersReq);
991     
992     swaps (&stuff->length, n);
993     REQUEST_AT_LEAST_SIZE (xMbufDisplayImageBuffersReq);
994     swaps (&stuff->minDelay, n);
995     swaps (&stuff->maxDelay, n);
996     SwapRestL(stuff);
997     return ProcDisplayImageBuffers (client);
998 }
999
1000 static int
1001 SProcDestroyImageBuffers (client)
1002     register ClientPtr  client;
1003 {
1004     register int    n;
1005     REQUEST (xMbufDestroyImageBuffersReq);
1006     
1007     swaps (&stuff->length, n);
1008     REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq);
1009     swapl (&stuff->window, n);
1010     return ProcDestroyImageBuffers (client);
1011 }
1012
1013 static int
1014 SProcSetMBufferAttributes (client)
1015     register ClientPtr  client;
1016 {
1017     register int    n;
1018     REQUEST (xMbufSetMBufferAttributesReq);
1019
1020     swaps (&stuff->length, n);
1021     REQUEST_AT_LEAST_SIZE(xMbufSetMBufferAttributesReq);
1022     swapl (&stuff->window, n);
1023     swapl (&stuff->valueMask, n);
1024     SwapRestL(stuff);
1025     return ProcSetMBufferAttributes (client);
1026 }
1027
1028 static int
1029 SProcGetMBufferAttributes (client)
1030     register ClientPtr  client;
1031 {
1032     register int    n;
1033     REQUEST (xMbufGetMBufferAttributesReq);
1034
1035     swaps (&stuff->length, n);
1036     REQUEST_AT_LEAST_SIZE(xMbufGetMBufferAttributesReq);
1037     swapl (&stuff->window, n);
1038     return ProcGetMBufferAttributes (client);
1039 }
1040
1041 static int
1042 SProcSetBufferAttributes (client)
1043     register ClientPtr  client;
1044 {
1045     register int    n;
1046     REQUEST (xMbufSetBufferAttributesReq);
1047
1048     swaps (&stuff->length, n);
1049     REQUEST_AT_LEAST_SIZE(xMbufSetBufferAttributesReq);
1050     swapl (&stuff->buffer, n);
1051     swapl (&stuff->valueMask, n);
1052     SwapRestL(stuff);
1053     return ProcSetBufferAttributes (client);
1054 }
1055
1056 static int
1057 SProcGetBufferAttributes (client)
1058     register ClientPtr  client;
1059 {
1060     register int    n;
1061     REQUEST (xMbufGetBufferAttributesReq);
1062
1063     swaps (&stuff->length, n);
1064     REQUEST_AT_LEAST_SIZE(xMbufGetBufferAttributesReq);
1065     swapl (&stuff->buffer, n);
1066     return ProcGetBufferAttributes (client);
1067 }
1068
1069 static int
1070 SProcGetBufferInfo (client)
1071     register ClientPtr  client;
1072 {
1073     register int    n;
1074     REQUEST (xMbufGetBufferInfoReq);
1075
1076     swaps (&stuff->length, n);
1077     REQUEST_SIZE_MATCH (xMbufGetBufferInfoReq);
1078     swapl (&stuff->drawable, n);
1079     return ProcGetBufferInfo (client);
1080 }
1081
1082 static int
1083 SProcClearImageBufferArea(client)
1084     register ClientPtr client;
1085 {
1086     register char n;
1087     REQUEST(xMbufClearImageBufferAreaReq);
1088
1089     swaps(&stuff->length, n);
1090     REQUEST_SIZE_MATCH (xMbufClearImageBufferAreaReq);
1091     swapl(&stuff->buffer, n);
1092     swaps(&stuff->x, n);
1093     swaps(&stuff->y, n);
1094     swaps(&stuff->width, n);
1095     swaps(&stuff->height, n);
1096     return ProcClearImageBufferArea(client);
1097 }
1098
1099 static int
1100 SProcMultibufferDispatch (client)
1101     register ClientPtr  client;
1102 {
1103     REQUEST(xReq);
1104     switch (stuff->data) {
1105     case X_MbufGetBufferVersion:
1106         return SProcGetBufferVersion (client);
1107     case X_MbufCreateImageBuffers:
1108         return SProcCreateImageBuffers (client);
1109     case X_MbufDisplayImageBuffers:
1110         return SProcDisplayImageBuffers (client);
1111     case X_MbufDestroyImageBuffers:
1112         return SProcDestroyImageBuffers (client);
1113     case X_MbufSetMBufferAttributes:
1114         return SProcSetMBufferAttributes (client);
1115     case X_MbufGetMBufferAttributes:
1116         return SProcGetMBufferAttributes (client);
1117     case X_MbufSetBufferAttributes:
1118         return SProcSetBufferAttributes (client);
1119     case X_MbufGetBufferAttributes:
1120         return SProcGetBufferAttributes (client);
1121     case X_MbufGetBufferInfo:
1122         return SProcGetBufferInfo (client);
1123     case X_MbufClearImageBufferArea:
1124         return SProcClearImageBufferArea (client);
1125     default:
1126         return BadRequest;
1127     }
1128 }
1129
1130 static void
1131 SUpdateNotifyEvent (from, to)
1132     xMbufUpdateNotifyEvent      *from, *to;
1133 {
1134     to->type = from->type;
1135     cpswaps (from->sequenceNumber, to->sequenceNumber);
1136     cpswapl (from->buffer, to->buffer);
1137     cpswapl (from->timeStamp, to->timeStamp);
1138 }
1139
1140 static void
1141 SClobberNotifyEvent (from, to)
1142     xMbufClobberNotifyEvent     *from, *to;
1143 {
1144     to->type = from->type;
1145     cpswaps (from->sequenceNumber, to->sequenceNumber);
1146     cpswapl (from->buffer, to->buffer);
1147     to->state = from->state;
1148 }
1149
1150 static void
1151 PerformDisplayRequest (ppMultibuffers, pMultibuffer, nbuf)
1152     MultibufferPtr          *pMultibuffer;
1153     MultibuffersPtr         *ppMultibuffers;
1154     int             nbuf;
1155 {
1156     GCPtr           pGC;
1157     PixmapPtr       pPrevPixmap, pNewPixmap;
1158     xRectangle      clearRect;
1159     WindowPtr       pWin;
1160     RegionPtr       pExposed;
1161     int             i;
1162     MultibufferPtr  pPrevMultibuffer;
1163     XID             graphicsExpose;
1164
1165     UpdateCurrentTime ();
1166     for (i = 0; i < nbuf; i++)
1167     {
1168         pWin = ppMultibuffers[i]->pWindow;
1169         pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
1170         pPrevMultibuffer =
1171            &ppMultibuffers[i]->buffers[ppMultibuffers[i]->displayedMultibuffer];
1172         pPrevPixmap = pPrevMultibuffer->pPixmap;
1173         pNewPixmap = pMultibuffer[i]->pPixmap;
1174         switch (ppMultibuffers[i]->updateAction)
1175         {
1176         case MultibufferUpdateActionUndefined:
1177             break;
1178         case MultibufferUpdateActionBackground:
1179             SetupBackgroundPainter (pWin, pGC);
1180             ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
1181             clearRect.x = 0;
1182             clearRect.y = 0;
1183             clearRect.width = pPrevPixmap->drawable.width;
1184             clearRect.height = pPrevPixmap->drawable.height;
1185             (*pGC->ops->PolyFillRect) ((DrawablePtr)pPrevPixmap, pGC,
1186                                        1, &clearRect);
1187             break;
1188         case MultibufferUpdateActionUntouched:
1189             /* copy the window to the pixmap that represents the
1190              * currently displayed buffer
1191              */
1192             if (pPrevMultibuffer->eventMask & ExposureMask)
1193             {
1194                 graphicsExpose = TRUE;
1195                 DoChangeGC (pGC, GCGraphicsExposures, &graphicsExpose, FALSE);
1196             }
1197             ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
1198             pExposed = (*pGC->ops->CopyArea)
1199                             ((DrawablePtr) pWin,
1200                              (DrawablePtr) pPrevPixmap,
1201                              pGC,
1202                              0, 0,
1203                              pWin->drawable.width, pWin->drawable.height,
1204                              0, 0);
1205
1206             /* if we couldn't copy the whole window to the buffer,
1207              * send expose events (if any client wants them)
1208              */
1209             if (pPrevMultibuffer->eventMask & ExposureMask)
1210             { /* some client wants expose events */
1211                 if (pExposed)
1212                 {
1213                     RegionPtr   pWinSize;
1214                     ScreenPtr pScreen = pWin->drawable.pScreen;
1215
1216                     pWinSize = CreateUnclippedWinSize (pWin);
1217                     /* pExposed is window-relative, but at this point
1218                      * pWinSize is screen-relative.  Make pWinSize be
1219                      * window-relative so that region ops involving
1220                      * pExposed and pWinSize behave sensibly.
1221                      */
1222                     REGION_TRANSLATE(pScreen, pWinSize,
1223                                      -pWin->drawable.x,
1224                                      -pWin->drawable.y);
1225                     REGION_INTERSECT(pScreen, pExposed, pExposed, pWinSize);
1226                     REGION_DESTROY(pScreen, pWinSize);
1227                     MultibufferExpose (pPrevMultibuffer, pExposed);
1228                     REGION_DESTROY(pScreen, pExposed);
1229                 }
1230                 graphicsExpose = FALSE;
1231                 DoChangeGC (pGC, GCGraphicsExposures, &graphicsExpose, FALSE);
1232             }
1233             break; /* end case MultibufferUpdateActionUntouched */
1234
1235         case MultibufferUpdateActionCopied:
1236             ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
1237             (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap,
1238                                    (DrawablePtr)pPrevPixmap, pGC,
1239                                    0, 0,
1240                                    pWin->drawable.width, pWin->drawable.height,
1241                                    0, 0);
1242             break;
1243         } /* end switch on update action */
1244
1245         /* display the new buffer */
1246         ValidateGC ((DrawablePtr)pWin, pGC);
1247         (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap, (DrawablePtr)pWin, pGC,
1248                                0, 0,
1249                                pWin->drawable.width, pWin->drawable.height,
1250                                0, 0);
1251         ppMultibuffers[i]->lastUpdate = currentTime;
1252         MultibufferUpdate (pMultibuffer[i],
1253                            ppMultibuffers[i]->lastUpdate.milliseconds);
1254         AliasMultibuffer (ppMultibuffers[i],
1255                           pMultibuffer[i] - ppMultibuffers[i]->buffers);
1256         FreeScratchGC (pGC);
1257     }
1258 }
1259
1260 DrawablePtr
1261 GetBufferPointer (pWin, i)
1262     WindowPtr   pWin;
1263     int         i;
1264 {
1265     MultibuffersPtr pMultibuffers;
1266
1267     if (!(pMultibuffers = (MultibuffersPtr) pWin->devPrivates[MultibufferWindowIndex].ptr))
1268         return NULL;
1269     return (DrawablePtr) pMultibuffers->buffers[i].pPixmap;
1270 }
1271
1272 int
1273 DisplayImageBuffers (ids, nbuf)
1274     XID     *ids;
1275     int     nbuf;
1276 {
1277     MultibufferPtr  *pMultibuffer;
1278     MultibuffersPtr *pMultibuffers;
1279     int             i, j;
1280
1281     pMultibuffer = (MultibufferPtr *) ALLOCATE_LOCAL (nbuf * sizeof *pMultibuffer +
1282                                    nbuf * sizeof *pMultibuffers);
1283     if (!pMultibuffer)
1284         return BadAlloc;
1285     pMultibuffers = (MultibuffersPtr *) (pMultibuffer + nbuf);
1286     for (i = 0; i < nbuf; i++)
1287     {
1288         pMultibuffer[i] = (MultibufferPtr) LookupIDByType (ids[i], MultibufferResType);
1289         if (!pMultibuffer[i])
1290         {
1291             DEALLOCATE_LOCAL (pMultibuffer);
1292             return MultibufferErrorBase + MultibufferBadBuffer;
1293         }
1294         pMultibuffers[i] = pMultibuffer[i]->pMultibuffers;
1295         for (j = 0; j < i; j++)
1296             if (pMultibuffers[i] == pMultibuffers[j])
1297             {
1298                 DEALLOCATE_LOCAL (pMultibuffer);
1299                 return BadMatch;
1300             }
1301     }
1302     PerformDisplayRequest (pMultibuffers, pMultibuffer, nbuf);
1303     DEALLOCATE_LOCAL (pMultibuffer);
1304     return Success;
1305 }
1306
1307
1308 static Bool
1309 QueueDisplayRequest (client, activateTime)
1310     ClientPtr       client;
1311     TimeStamp       activateTime;
1312 {
1313     /* see xtest.c:ProcXTestFakeInput for code similar to this */
1314
1315     if (!ClientSleepUntil(client, &activateTime, NULL, NULL))
1316     {
1317         return FALSE;
1318     }
1319     /* swap the request back so we can simply re-execute it */
1320     if (client->swapped)
1321     {
1322         register int    n;
1323         REQUEST (xMbufDisplayImageBuffersReq);
1324         
1325         SwapRestL(stuff);
1326         swaps (&stuff->length, n);
1327         swaps (&stuff->minDelay, n);
1328         swaps (&stuff->maxDelay, n);
1329     }
1330     ResetCurrentRequest (client);
1331     client->sequence--;
1332     return TRUE;
1333 }
1334
1335
1336 /*
1337  * Deliver events to a buffer
1338  */
1339
1340 static int
1341 DeliverEventsToMultibuffer (pMultibuffer, pEvents, count, filter)
1342     MultibufferPtr      pMultibuffer;
1343     xEvent      *pEvents;
1344     int         count;
1345     Mask        filter;
1346 {
1347     int deliveries = 0, nondeliveries = 0;
1348     int attempt;
1349     OtherClients *other;
1350
1351     /* if nobody wants the event, we're done */
1352     if (!((pMultibuffer->otherEventMask|pMultibuffer->eventMask) & filter))
1353         return 0;
1354
1355     /* maybe send event to owner */
1356     if ((attempt = TryClientEvents(
1357         bClient(pMultibuffer), pEvents, count, pMultibuffer->eventMask, filter, (GrabPtr) 0)) != 0)
1358     {
1359         if (attempt > 0)
1360             deliveries++;
1361         else
1362             nondeliveries--;
1363     }
1364
1365     /* maybe send event to other clients */
1366     for (other = pMultibuffer->otherClients; other; other=other->next)
1367     {
1368         if ((attempt = TryClientEvents(
1369               rClient(other), pEvents, count, other->mask, filter, (GrabPtr) 0)) != 0)
1370         {
1371             if (attempt > 0)
1372                 deliveries++;
1373             else
1374                 nondeliveries--;
1375         }
1376     }
1377     if (deliveries)
1378         return deliveries;
1379     return nondeliveries;
1380 }
1381
1382 /*
1383  * Send Expose events to interested clients
1384  */
1385
1386 void
1387 MultibufferExpose (pMultibuffer, pRegion)
1388     MultibufferPtr      pMultibuffer;
1389     RegionPtr   pRegion;
1390 {
1391     if (pRegion && !REGION_NIL(pRegion))
1392     {
1393         xEvent *pEvent;
1394         PixmapPtr   pPixmap;
1395         register xEvent *pe;
1396         register BoxPtr pBox;
1397         register int i;
1398         int numRects;
1399
1400         pPixmap = pMultibuffer->pPixmap;
1401         REGION_TRANSLATE(pPixmap->drawable.pScreen, pRegion,
1402                     -pPixmap->drawable.x, -pPixmap->drawable.y);
1403         /* XXX MultibufferExpose "knows" the region representation */
1404         numRects = REGION_NUM_RECTS(pRegion);
1405         pBox = REGION_RECTS(pRegion);
1406
1407         pEvent = (xEvent *) ALLOCATE_LOCAL(numRects * sizeof(xEvent));
1408         if (pEvent) {
1409             pe = pEvent;
1410
1411             for (i=1; i<=numRects; i++, pe++, pBox++)
1412             {
1413                 pe->u.u.type = Expose;
1414                 pe->u.expose.window = pPixmap->drawable.id;
1415                 pe->u.expose.x = pBox->x1;
1416                 pe->u.expose.y = pBox->y1;
1417                 pe->u.expose.width = pBox->x2 - pBox->x1;
1418                 pe->u.expose.height = pBox->y2 - pBox->y1;
1419                 pe->u.expose.count = (numRects - i);
1420             }
1421             (void) DeliverEventsToMultibuffer (pMultibuffer, pEvent, numRects,
1422                                                ExposureMask);
1423             DEALLOCATE_LOCAL(pEvent);
1424         }
1425     }
1426 }
1427
1428 /* send UpdateNotify event */
1429 void
1430 MultibufferUpdate (pMultibuffer, time2)
1431     MultibufferPtr      pMultibuffer;
1432     CARD32      time2;
1433 {
1434     xMbufUpdateNotifyEvent      event;
1435
1436     event.type = MultibufferEventBase + MultibufferUpdateNotify;
1437     event.buffer = pMultibuffer->pPixmap->drawable.id;
1438     event.timeStamp = time2;
1439     (void) DeliverEventsToMultibuffer (pMultibuffer, (xEvent *)&event,
1440                                 1, (Mask)MultibufferUpdateNotifyMask);
1441 }
1442
1443 /*
1444  * The sample implementation will never generate MultibufferClobberNotify
1445  * events
1446  */
1447
1448 void
1449 MultibufferClobber (pMultibuffer)
1450     MultibufferPtr      pMultibuffer;
1451 {
1452     xMbufClobberNotifyEvent     event;
1453
1454     event.type = MultibufferEventBase + MultibufferClobberNotify;
1455     event.buffer = pMultibuffer->pPixmap->drawable.id;
1456     event.state = pMultibuffer->clobber;
1457     (void) DeliverEventsToMultibuffer (pMultibuffer, (xEvent *)&event,
1458                                 1, (Mask)MultibufferClobberNotifyMask);
1459 }
1460
1461 /*
1462  * make the resource id for buffer i refer to the window
1463  * drawable instead of the pixmap;
1464  */
1465
1466 static void
1467 AliasMultibuffer (pMultibuffers, i)
1468     MultibuffersPtr     pMultibuffers;
1469     int         i;
1470 {
1471     MultibufferPtr      pMultibuffer;
1472
1473     if (i == pMultibuffers->displayedMultibuffer)
1474         return;
1475     /*
1476      * remove the old association
1477      */
1478     if (pMultibuffers->displayedMultibuffer >= 0)
1479     {
1480         pMultibuffer = &pMultibuffers->buffers[pMultibuffers->displayedMultibuffer];
1481         ChangeResourceValue (pMultibuffer->pPixmap->drawable.id,
1482                              MultibufferDrawableResType,
1483                              (pointer) pMultibuffer->pPixmap);
1484     }
1485     /*
1486      * make the new association
1487      */
1488     pMultibuffer = &pMultibuffers->buffers[i];
1489     ChangeResourceValue (pMultibuffer->pPixmap->drawable.id,
1490                          MultibufferDrawableResType,
1491                          (pointer) pMultibuffers->pWindow);
1492     pMultibuffers->displayedMultibuffer = i;
1493 }
1494
1495 /*
1496  * free everything associated with multibuffering for this
1497  * window
1498  */
1499
1500 void
1501 DestroyImageBuffers (pWin)
1502     WindowPtr   pWin;
1503 {
1504     FreeResourceByType (pWin->drawable.id, MultibuffersResType, FALSE);
1505     /* Zero out the window's pointer to the buffers so they won't be reused */
1506     pWin->devPrivates[MultibufferWindowIndex].ptr = NULL;
1507 }
1508
1509 /*
1510  * resize the buffers when the window is resized
1511  */ 
1512
1513 static Bool
1514 MultibufferPositionWindow (pWin, x, y)
1515     WindowPtr   pWin;
1516     int         x, y;
1517 {
1518     ScreenPtr       pScreen;
1519     MultibufferScreenPtr pMultibufferScreen;
1520     MultibuffersPtr         pMultibuffers;
1521     MultibufferPtr          pMultibuffer;
1522     int             width, height;
1523     int             i;
1524     int             dx, dy, dw, dh;
1525     int             sourcex, sourcey;
1526     int             destx, desty;
1527     PixmapPtr       pPixmap;
1528     GCPtr           pGC;
1529     int             savewidth, saveheight;
1530     xRectangle      clearRect;
1531     Bool            clear;
1532
1533     pScreen = pWin->drawable.pScreen;
1534     pMultibufferScreen = (MultibufferScreenPtr) pScreen->devPrivates[MultibufferScreenIndex].ptr;
1535     (*pMultibufferScreen->PositionWindow) (pWin, x, y);
1536
1537     /* if this window is not multibuffered, we're done */
1538     if (!(pMultibuffers = (MultibuffersPtr) pWin->devPrivates[MultibufferWindowIndex].ptr))
1539         return TRUE;
1540
1541     /* if new size is same as old, we're done */
1542     if (pMultibuffers->width == pWin->drawable.width &&
1543         pMultibuffers->height == pWin->drawable.height)
1544         return TRUE;
1545
1546     width = pWin->drawable.width;
1547     height = pWin->drawable.height;
1548     dx = pWin->drawable.x - pMultibuffers->x;
1549     dy = pWin->drawable.x - pMultibuffers->y;
1550     dw = width - pMultibuffers->width;
1551     dh = height - pMultibuffers->height;
1552     GravityTranslate (0, 0, -dx, -dy, dw, dh,
1553                       pWin->bitGravity, &destx, &desty);
1554
1555     /* if the window grew, remember to paint the window background,
1556      * and maybe send expose events, for the new areas of the buffers
1557      */
1558     clear = pMultibuffers->width < width || pMultibuffers->height < height ||
1559                 pWin->bitGravity == ForgetGravity;
1560
1561     sourcex = 0;
1562     sourcey = 0;
1563     savewidth = pMultibuffers->width;
1564     saveheight = pMultibuffers->height;
1565     /* clip rectangle to source and destination */
1566     if (destx < 0)
1567     {
1568         savewidth += destx;
1569         sourcex -= destx;
1570         destx = 0;
1571     }
1572     if (destx + savewidth > width)
1573         savewidth = width - destx;
1574     if (desty < 0)
1575     {
1576         saveheight += desty;
1577         sourcey -= desty;
1578         desty = 0;
1579     }
1580     if (desty + saveheight > height)
1581         saveheight = height - desty;
1582
1583     pMultibuffers->width = width;
1584     pMultibuffers->height = height;
1585     pMultibuffers->x = pWin->drawable.x;
1586     pMultibuffers->y = pWin->drawable.y;
1587
1588     pGC = GetScratchGC (pWin->drawable.depth, pScreen);
1589     if (clear)
1590     {
1591         SetupBackgroundPainter (pWin, pGC);
1592         clearRect.x = 0;
1593         clearRect.y = 0;
1594         clearRect.width = width;
1595         clearRect.height = height;
1596     }
1597     for (i = 0; i < pMultibuffers->numMultibuffer; i++)
1598     {
1599         pMultibuffer = &pMultibuffers->buffers[i];
1600         pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1601                                             pWin->drawable.depth);
1602         if (!pPixmap)
1603         {
1604             DestroyImageBuffers (pWin);
1605             break;
1606         }
1607         ValidateGC ((DrawablePtr)pPixmap, pGC);
1608         /*
1609          * I suppose this could avoid quite a bit of work if
1610          * it computed the minimal area required.
1611          */
1612         if (clear)
1613             (*pGC->ops->PolyFillRect) ((DrawablePtr)pPixmap, pGC, 1, &clearRect);
1614         if (pWin->bitGravity != ForgetGravity)
1615         {
1616             (*pGC->ops->CopyArea) ((DrawablePtr)pMultibuffer->pPixmap,
1617                                    (DrawablePtr)pPixmap, pGC,
1618                                     sourcex, sourcey, savewidth, saveheight,
1619                                     destx, desty);
1620         }
1621         pPixmap->drawable.id = pMultibuffer->pPixmap->drawable.id;
1622         (*pScreen->DestroyPixmap) (pMultibuffer->pPixmap);
1623         pMultibuffer->pPixmap = pPixmap;
1624         if (i != pMultibuffers->displayedMultibuffer)
1625         {
1626             ChangeResourceValue (pPixmap->drawable.id,
1627                                  MultibufferDrawableResType,
1628                                  (pointer) pPixmap);
1629         }
1630     }
1631     FreeScratchGC (pGC);
1632     return TRUE;
1633 }
1634
1635 /* Resource delete func for MultibufferDrawableResType */
1636 /*ARGSUSED*/
1637 static int
1638 MultibufferDrawableDelete (value, id)
1639     pointer     value;
1640     XID         id;
1641 {
1642     DrawablePtr pDrawable = (DrawablePtr)value;
1643     WindowPtr   pWin;
1644     MultibuffersPtr     pMultibuffers;
1645     PixmapPtr   pPixmap;
1646
1647     if (pDrawable->type == DRAWABLE_WINDOW)
1648     {
1649         pWin = (WindowPtr) pDrawable;
1650         pMultibuffers = (MultibuffersPtr) pWin->devPrivates[MultibufferWindowIndex].ptr;
1651         pPixmap = pMultibuffers->buffers[pMultibuffers->displayedMultibuffer].pPixmap;
1652     }
1653     else
1654     {
1655         pPixmap = (PixmapPtr) pDrawable;
1656     }
1657     (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
1658     return Success;
1659 }
1660
1661 /* Resource delete func for MultibufferResType */
1662 /*ARGSUSED*/
1663 static int
1664 MultibufferDelete (value, id)
1665     pointer     value;
1666     XID         id;
1667 {
1668     MultibufferPtr      pMultibuffer = (MultibufferPtr)value;
1669     MultibuffersPtr     pMultibuffers;
1670
1671     pMultibuffers = pMultibuffer->pMultibuffers;
1672     if (--pMultibuffers->refcnt == 0)
1673     {
1674         FreeResourceByType (pMultibuffers->pWindow->drawable.id,
1675                             MultibuffersResType, TRUE);
1676         xfree (pMultibuffers);
1677     }
1678     return Success;
1679 }
1680
1681 /* Resource delete func for MultibuffersResType */
1682 /*ARGSUSED*/
1683 static int
1684 MultibuffersDelete (value, id)
1685     pointer     value;
1686     XID         id;
1687 {
1688     MultibuffersPtr     pMultibuffers = (MultibuffersPtr)value;
1689     int i;
1690
1691     if (pMultibuffers->refcnt == pMultibuffers->numMultibuffer)
1692     {
1693         for (i = pMultibuffers->numMultibuffer; --i >= 0; )
1694             FreeResource (pMultibuffers->buffers[i].pPixmap->drawable.id, 0);
1695     }
1696     return Success;
1697 }
1698
1699 /* Resource delete func for OtherClientResType */
1700 static int
1701 OtherClientDelete (value, id)
1702     pointer     value;
1703     XID         id;
1704 {
1705     MultibufferPtr      pMultibuffer = (MultibufferPtr)value;
1706     register OtherClientsPtr    other, prev;
1707
1708     prev = 0;
1709     for (other = pMultibuffer->otherClients; other; other = other->next)
1710     {
1711         if (other->resource == id)
1712         {
1713             if (prev)
1714                 prev->next = other->next;
1715             else
1716                 pMultibuffer->otherClients = other->next;
1717             xfree (other);
1718             RecalculateMultibufferOtherEvents (pMultibuffer);
1719             break;
1720         }
1721         prev = other;
1722     }
1723     return Success;
1724 }
1725
1726 static int
1727 EventSelectForMultibuffer (pMultibuffer, client, mask)
1728     MultibufferPtr      pMultibuffer;
1729     ClientPtr   client;
1730     Mask        mask;
1731 {
1732     OtherClientsPtr     other;
1733
1734     if (mask & ~ValidEventMasks)
1735     {
1736         client->errorValue = mask;
1737         return BadValue;
1738     }
1739     if (bClient (pMultibuffer) == client)
1740     {
1741         pMultibuffer->eventMask = mask;
1742     }
1743     else /* some other client besides the creator wants events */
1744     {
1745         for (other = pMultibuffer->otherClients; other; other = other->next)
1746         {
1747             if (SameClient (other, client))
1748             {
1749                 if (mask == 0)
1750                 {
1751                     FreeResource (other->resource, RT_NONE);
1752                     break;
1753                 }
1754                 other->mask = mask;
1755                 break;
1756             }
1757         }
1758         if (!other)
1759         { /* new client that never selected events on this buffer before */
1760             other = (OtherClients *) xalloc (sizeof (OtherClients));
1761             if (!other)
1762                 return BadAlloc;
1763             other->mask = mask;
1764             other->resource = FakeClientID (client->index);
1765             if (!AddResource (other->resource, OtherClientResType, (pointer) pMultibuffer))
1766             {
1767                 xfree (other);
1768                 return BadAlloc;
1769             }
1770             other->next = pMultibuffer->otherClients;
1771             pMultibuffer->otherClients = other;
1772         }
1773         RecalculateMultibufferOtherEvents (pMultibuffer);
1774     }
1775     return (client->noClientException);
1776 }
1777
1778 /* or together all the otherClients event masks */
1779 static void
1780 RecalculateMultibufferOtherEvents (pMultibuffer)
1781     MultibufferPtr      pMultibuffer;
1782 {
1783     Mask            otherEventMask;
1784     OtherClients    *other;
1785
1786     otherEventMask = 0L;
1787     for (other = pMultibuffer->otherClients; other; other = other->next)
1788         otherEventMask |= other->mask;
1789     pMultibuffer->otherEventMask = otherEventMask;
1790 }
1791
1792 /* add milliseconds to a timestamp, handling overflow */
1793 static void
1794 BumpTimeStamp (ts, inc)
1795 TimeStamp   *ts;
1796 CARD32      inc;
1797 {
1798     CARD32  newms;
1799
1800     newms = ts->milliseconds + inc;
1801     if (newms < ts->milliseconds)
1802         ts->months++;
1803     ts->milliseconds = newms;
1804 }