home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / extensions / server / multibuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  46.7 KB  |  1,738 lines

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