diff --git a/hw/dmx/dmx.h b/hw/dmx/dmx.h index c347f2872..26ae18436 100644 --- a/hw/dmx/dmx.h +++ b/hw/dmx/dmx.h @@ -104,6 +104,9 @@ typedef struct _DMXPropTrans { Atom type; } DMXPropTrans; +/** Opcode for xcb_implementation. */ +#define DMX_DETACHED 0xff + /** Provide the typedef globally, but keep the contents opaque outside * of the input routines. \see dmxinput.h */ typedef struct _DMXInputInfo DMXInputInfo; @@ -142,6 +145,7 @@ typedef struct _DMXScreenInfo { int beNumDepths; /**< Number of depths on BE server */ int *beDepths; /**< Depths from BE server */ int alive; + int broken; int beNumPixmapFormats; /**< Number of pixmap formats on BE */ XPixmapFormatValues *bePixmapFormats; /**< Pixmap formats on BE */ @@ -162,6 +166,11 @@ typedef struct _DMXScreenInfo { int beRandrEventBase; #endif +#ifdef MITSHM + Bool beShm; /**< Use MIT-SHM support on BE server */ + int beShmEventBase; +#endif + char *authType; char *authData; int authDataLen; diff --git a/hw/dmx/dmxextension.c b/hw/dmx/dmxextension.c index 563a58016..cc13a9593 100644 --- a/hw/dmx/dmxextension.c +++ b/hw/dmx/dmxextension.c @@ -51,6 +51,7 @@ #include "dmxgc.h" #include "dmxfont.h" #include "dmxcmap.h" +#include "dmxshm.h" #ifdef RENDER #include "dmxpict.h" #endif @@ -1145,6 +1146,8 @@ static void dmxBECreateResources(pointer value, XID id, RESTYPE type, ColormapPtr pCmap = value; if (pCmap->pScreen->myNum == scrnNum) (void)dmxBECreateColormap((ColormapPtr)value); + } else if ((type & TypeMask) == (DMX_SHMSEG & TypeMask)) { + dmxBEAttachShmSeg (&dmxScreens[scrnNum], (dmxShmSegInfoPtr) value); #if 0 #ifdef RENDER /* TODO: Recreate Picture and GlyphSet resources */ @@ -1882,6 +1885,16 @@ dmxAttachScreen (int idx, return 1; } +#ifdef MITSHM + dmxScreen->beShm = FALSE; + + XLIB_PROLOGUE (dmxScreen); + dmxScreen->beShm = XShmQueryExtension (dmxScreen->beDisplay); + if (dmxScreen->beShm) + dmxScreen->beShmEventBase = XShmGetEventBase (dmxScreen->beDisplay); + XLIB_EPILOGUE (dmxScreen); +#endif + #ifdef RANDR dmxScreen->beRandr = FALSE; #endif @@ -2328,6 +2341,8 @@ static void dmxBEDestroyResources(pointer value, XID id, RESTYPE type, ColormapPtr pCmap = value; if (pCmap->pScreen->myNum == scrnNum) dmxBEFreeColormap((ColormapPtr)value); + } else if ((type & TypeMask) == (DMX_SHMSEG & TypeMask)) { + dmxBEDetachShmSeg (&dmxScreens[scrnNum], (dmxShmSegInfoPtr) value); #ifdef RENDER } else if ((type & TypeMask) == (PictureType & TypeMask)) { PicturePtr pPict = value; diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c index c5a09ee8b..44d14920b 100644 --- a/hw/dmx/dmxinit.c +++ b/hw/dmx/dmxinit.c @@ -296,6 +296,7 @@ Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen) return FALSE; dmxScreen->alive = 1; + dmxScreen->broken = 0; dmxScreen->inDispatch = FALSE; dmxScreen->fd = XConnectionNumber (dmxScreen->beDisplay); dmxScreen->connection = XGetXCBConnection (dmxScreen->beDisplay); diff --git a/hw/dmx/dmxscrinit.c b/hw/dmx/dmxscrinit.c index 726d60bae..7cdf9be94 100644 --- a/hw/dmx/dmxscrinit.c +++ b/hw/dmx/dmxscrinit.c @@ -693,30 +693,6 @@ dmxScreenEventCheckIgnore (ScreenPtr pScreen, return FALSE; } -static void -dmxScreenCheckForIOError (ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - if (xcb_connection_has_error (dmxScreen->connection)) - { - int i; - - dmxScreen->alive = FALSE; - - dmxLogOutput (dmxScreen, "Detected broken connection\n"); - dmxDetachScreen (pScreen->myNum); - - for (i = 0; i < dmxNumScreens; i++) - if (i != pScreen->myNum && dmxScreens[i].beDisplay) - break; - - if (i == dmxNumScreens) - dmxLog (dmxFatal, "No back-end server connection, " - "giving up\n"); - } -} - void dmxBEDispatch (ScreenPtr pScreen) { @@ -733,14 +709,28 @@ dmxBEDispatch (ScreenPtr pScreen) !dmxScreenEventCheckManageWindow (pScreen, event) && !dmxScreenEventCheckExpose (pScreen, event) && +#ifdef MITSHM + !dmxScreenEventCheckShm (pScreen, event) && +#endif + #ifdef RANDR !dmxScreenEventCheckRR (pScreen, event) && #endif !dmxScreenEventCheckIgnore (pScreen, event)) { - dmxLogOutput (dmxScreen, "unhandled event type %d\n", - event->response_type); + if (event->response_type == 0) + { + xcb_generic_error_t *error = (xcb_generic_error_t *) event; + + dmxLogOutput (dmxScreen, "unhandled error type %d\n", + error->error_code); + } + else + { + dmxLogOutput (dmxScreen, "unhandled event type %d\n", + event->response_type); + } } free (event); @@ -783,9 +773,68 @@ dmxBEDispatch (ScreenPtr pScreen) free (head); } + if (xcb_connection_has_error (dmxScreen->connection)) + { + if (!dmxScreen->broken) + { + static xcb_generic_error_t detached_error = { 0, DMX_DETACHED }; + + dmxScreenEventCheckInput (pScreen, (xcb_generic_event_t *) + &detached_error); + dmxScreenEventCheckManageWindow (pScreen, (xcb_generic_event_t *) + &detached_error); + dmxScreenEventCheckExpose (pScreen, (xcb_generic_event_t *) + &detached_error); + +#ifdef MITSHM + dmxScreenEventCheckShm (pScreen, (xcb_generic_event_t *) + &detached_error); +#endif + +#ifdef RANDR + dmxScreenEventCheckRR (pScreen, (xcb_generic_event_t *) + &detached_error); +#endif + + dmxScreenReplyCheckSync (pScreen, 0, (xcb_generic_reply_t *) + &detached_error); + dmxScreenReplyCheckInput (pScreen, 0, (xcb_generic_reply_t *) + &detached_error); + + dmxScreen->broken = TRUE; + } + } + dmxScreen->inDispatch--; } +static void +dmxScreenCheckForIOError (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (xcb_connection_has_error (dmxScreen->connection)) + { + int i; + + dmxScreen->alive = FALSE; + + if (!dmxScreen->broken) + dmxBEDispatch (pScreen); + + dmxLogOutput (dmxScreen, "Detected broken connection\n"); + dmxDetachScreen (pScreen->myNum); + + for (i = 0; i < dmxNumScreens; i++) + if (i != pScreen->myNum && dmxScreens[i].beDisplay) + break; + + if (i == dmxNumScreens) + dmxLog (dmxFatal, "No back-end server connection, " + "giving up\n"); + } +} + static void dmxScreenBlockHandler (pointer blockData, OSTimePtr pTimeout, @@ -869,6 +918,10 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) dmxScreen->request.head = NULL; dmxScreen->request.tail = &dmxScreen->request.head; +#ifdef MITSHM + dmxScreen->beShm = FALSE; +#endif + #ifdef RANDR dmxScreen->beRandr = FALSE; dmxScreen->beRandrPending = FALSE; @@ -992,6 +1045,15 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) #ifdef MITSHM ShmRegisterDmxFuncs (pScreen); + if (dmxScreen->beDisplay) + { + XLIB_PROLOGUE (dmxScreen); + dmxScreen->beShm = XShmQueryExtension (dmxScreen->beDisplay); + if (dmxScreen->beShm) + dmxScreen->beShmEventBase = + XShmGetEventBase (dmxScreen->beDisplay); + XLIB_EPILOGUE (dmxScreen); + } #endif #ifdef PANORAMIX diff --git a/hw/dmx/dmxshm.c b/hw/dmx/dmxshm.c index 437908e00..085d63e82 100644 --- a/hw/dmx/dmxshm.c +++ b/hw/dmx/dmxshm.c @@ -44,8 +44,13 @@ #ifdef MITSHM +#include +#include + unsigned long DMX_SHMSEG; +static dmxShmSegInfoPtr shmSegs = NULL; + extern int (*ProcShmVector[ShmNumberRequests])(ClientPtr); static int (*dmxSaveProcVector[ShmNumberRequests]) (ClientPtr); @@ -160,33 +165,170 @@ dmxShmPutImage (DrawablePtr pDraw, } } +void +dmxBEAttachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo) +{ + if (!dmxScreen->beShm) + return; + + if (!pShmInfo->shmseg[dmxScreen->index]) + { + pShmInfo->shmseg[dmxScreen->index] = + xcb_generate_id (dmxScreen->connection); + + xcb_shm_attach (dmxScreen->connection, + pShmInfo->shmseg[dmxScreen->index], + pShmInfo->shmid, + pShmInfo->readOnly); + } +} + +void +dmxBEDetachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo) +{ + if (!dmxScreen->beShm) + return; + + if (pShmInfo->shmseg[dmxScreen->index]) + { + xcb_shm_detach (dmxScreen->connection, + pShmInfo->shmseg[dmxScreen->index]); + + pShmInfo->shmseg[dmxScreen->index] = None; + pShmInfo->cookie[dmxScreen->index].sequence = 0; + } +} + +Bool +dmxScreenEventCheckShm (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxShmSegInfoPtr pShmInfo; + xcb_shm_seg_t shmseg = 0; + unsigned int sequence = 0; + + if (!dmxScreen->beShm) + return FALSE; + + if (event->response_type) + { + switch ((event->response_type & ~0x80) - dmxScreen->beShmEventBase) { + case XCB_SHM_COMPLETION: { + /* XCB protocol description for XCB_SHM_COMPLETION is wrong */ + xShmCompletionEvent *xcompletion = + (xShmCompletionEvent *) event; + + shmseg = xcompletion->shmseg; + } break; + default: + return FALSE; + } + } + else + { + xcb_generic_error_t *error = (xcb_generic_error_t *) event; + + if (event->pad0 != DMX_DETACHED) + sequence = error->sequence; + } + + for (pShmInfo = shmSegs; pShmInfo; pShmInfo = pShmInfo->next) + { + if (shmseg && shmseg != pShmInfo->shmseg[pScreen->myNum]) + continue; + + if (!pShmInfo->cookie[pScreen->myNum].sequence) + continue; + + if (sequence && sequence != pShmInfo->cookie[pScreen->myNum].sequence) + continue; + + pShmInfo->pendingEvents--; + pShmInfo->cookie[pScreen->myNum].sequence = 0; + } + + return TRUE; +} + static int dmxFreeShmSeg (pointer value, XID id) { + dmxShmSegInfoPtr *pPrev, pShmInfo = (dmxShmSegInfoPtr) value; + int i; + + if (--pShmInfo->refcnt) + return TRUE; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + + dmxBEDetachShmSeg (dmxScreen, pShmInfo); + } + + for (pPrev = &shmSegs; *pPrev != pShmInfo; pPrev = &(*pPrev)->next) + ; + *pPrev = pShmInfo->next; + + xfree (pShmInfo); return Success; } static int dmxProcShmAttach (ClientPtr client) { - int err; + dmxShmSegInfoPtr pShmInfo; + int i, err; + REQUEST(xShmAttachReq); err = (*dmxSaveProcVector[X_ShmAttach]) (client); if (err != Success) return err; - return Success; -} + for (pShmInfo = shmSegs; + pShmInfo && (pShmInfo->shmid != stuff->shmid); + pShmInfo = pShmInfo->next) + ; + if (pShmInfo) + { + pShmInfo->refcnt++; + } + else + { + pShmInfo = xalloc (sizeof (dmxShmSegInfoRec)); + if (!pShmInfo) + return Success; -static int -dmxProcShmDetach (ClientPtr client) -{ - int err; + pShmInfo->refcnt = 1; + pShmInfo->shmid = stuff->shmid; + pShmInfo->readOnly = stuff->readOnly; + pShmInfo->pendingEvents = 0; - err = (*dmxSaveProcVector[X_ShmDetach]) (client); - if (err != Success) - return err; + memset (pShmInfo->shmseg, 0, sizeof (pShmInfo->shmseg)); + memset (pShmInfo->cookie, 0, sizeof (pShmInfo->cookie)); + + pShmInfo->next = shmSegs; + shmSegs = pShmInfo; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (!dmxScreen->beDisplay) + continue; + + dmxBEAttachShmSeg (dmxScreen, pShmInfo); + } + } + + AddResource (stuff->shmseg, DMX_SHMSEG, (pointer) pShmInfo); return Success; } @@ -194,25 +336,272 @@ dmxProcShmDetach (ClientPtr client) static int dmxProcShmGetImage (ClientPtr client) { - int err; + DrawablePtr pDraw; + long lenPer = 0, length; + Mask plane = 0; + xShmGetImageReply xgi; + ShmDescPtr shmdesc; + dmxShmSegInfoPtr pShmInfo; + Drawable draw; + int n, rc; - err = (*dmxSaveProcVector[X_ShmGetImage]) (client); - if (err != Success) - return err; + REQUEST(xShmGetImageReq); - return Success; + REQUEST_SIZE_MATCH(xShmGetImageReq); + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) + { + client->errorValue = stuff->format; + return(BadValue); + } + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + + for (pShmInfo = shmSegs; + pShmInfo && (pShmInfo->shmid != shmdesc->shmid); + pShmInfo = pShmInfo->next) + ; + + if (!pShmInfo || !pShmInfo->shmseg[pDraw->pScreen->myNum]) + return (*dmxSaveProcVector[X_ShmGetImage]) (client); + + if (pDraw->type == DRAWABLE_WINDOW) + { + if( /* check for being viewable */ + !((WindowPtr) pDraw)->realized || + /* check for being on screen */ + pDraw->x + stuff->x < 0 || + pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width || + pDraw->y + stuff->y < 0 || + pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height || + /* check for being inside of border */ + stuff->x < - wBorderWidth((WindowPtr)pDraw) || + stuff->x + (int)stuff->width > + wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || + stuff->y < -wBorderWidth((WindowPtr)pDraw) || + stuff->y + (int)stuff->height > + wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height + ) + return(BadMatch); + xgi.visual = wVisual(((WindowPtr)pDraw)); + draw = (DMX_GET_WINDOW_PRIV ((WindowPtr) (pDraw)))->window; + } + else + { + if (stuff->x < 0 || + stuff->x+(int)stuff->width > pDraw->width || + stuff->y < 0 || + stuff->y+(int)stuff->height > pDraw->height + ) + return(BadMatch); + xgi.visual = None; + draw = (DMX_GET_PIXMAP_PRIV ((PixmapPtr) (pDraw)))->pixmap; + } + xgi.type = X_Reply; + xgi.length = 0; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if(stuff->format == ZPixmap) + { + length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; + } + else + { + lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; + plane = ((Mask)1) << (pDraw->depth - 1); + /* only planes asked for */ + length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); + } + + VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); + xgi.size = length; + + if (length) + { + xcb_shm_get_image_cookie_t cookie; + xcb_shm_get_image_reply_t *reply; + DMXScreenInfo *dmxScreen = + &dmxScreens[pDraw->pScreen->myNum]; + + cookie = xcb_shm_get_image (dmxScreen->connection, draw, + stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->planeMask, stuff->format, + pShmInfo->shmseg[dmxScreen->index], + stuff->offset); + do { + dmxDispatch (); + + if (xcb_poll_for_reply (dmxScreen->connection, + cookie.sequence, + (void **) &reply, + NULL)) + break; + } while (dmxWaitForResponse () && dmxScreen->alive); + } + + if (client->swapped) { + swaps(&xgi.sequenceNumber, n); + swapl(&xgi.length, n); + swapl(&xgi.visual, n); + swapl(&xgi.size, n); + } + WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); + + return(client->noClientException); } static int dmxProcShmPutImage (ClientPtr client) { - int err; + GCPtr pGC; + DrawablePtr pDraw; + long length; + ShmDescPtr shmdesc; + dmxShmSegInfoPtr pShmInfo; + REQUEST(xShmPutImageReq); - err = (*dmxSaveProcVector[X_ShmPutImage]) (client); - if (err != Success) - return err; + REQUEST_SIZE_MATCH(xShmPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); + if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) + return BadValue; + if (stuff->format == XYBitmap) + { + if (stuff->depth != 1) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + } + else if (stuff->format == XYPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + length *= stuff->depth; + } + else if (stuff->format == ZPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, stuff->depth); + } + else + { + client->errorValue = stuff->format; + return BadValue; + } - return Success; + /* + * There's a potential integer overflow in this check: + * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, + * client); + * the version below ought to avoid it + */ + if (stuff->totalHeight != 0 && + length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { + client->errorValue = stuff->totalWidth; + return BadValue; + } + if (stuff->srcX > stuff->totalWidth) + { + client->errorValue = stuff->srcX; + return BadValue; + } + if (stuff->srcY > stuff->totalHeight) + { + client->errorValue = stuff->srcY; + return BadValue; + } + if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) + { + client->errorValue = stuff->srcWidth; + return BadValue; + } + if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) + { + client->errorValue = stuff->srcHeight; + return BadValue; + } + + for (pShmInfo = shmSegs; + pShmInfo && (pShmInfo->shmid != shmdesc->shmid); + pShmInfo = pShmInfo->next) + ; + + if (pShmInfo && pShmInfo->shmseg[pDraw->pScreen->myNum]) + { + DMXScreenInfo *dmxScreen = &dmxScreens[pDraw->pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV (pGC); + xcb_drawable_t draw; + + if (pDraw->type == DRAWABLE_WINDOW) + draw = (DMX_GET_WINDOW_PRIV ((WindowPtr) (pDraw)))->window; + else + draw = (DMX_GET_PIXMAP_PRIV ((PixmapPtr) (pDraw)))->pixmap; + + if (dmxScreen->beDisplay && draw) + { + pShmInfo->cookie[dmxScreen->index] = + xcb_shm_put_image (dmxScreen->connection, + draw, + XGContextFromGC (pGCPriv->gc), + stuff->totalWidth, stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, stuff->srcHeight, + stuff->dstX, stuff->dstY, + stuff->depth, + stuff->format, + TRUE, + pShmInfo->shmseg[dmxScreen->index], + stuff->offset); + + pShmInfo->pendingEvents++; + } + } + else + { + dmxShmPutImage (pDraw, pGC, stuff->depth, stuff->format, + stuff->totalWidth, stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, stuff->srcHeight, + stuff->dstX, stuff->dstY, + shmdesc->addr + stuff->offset); + } + + if (!pDraw->pScreen->myNum) + { + /* we could handle this completely asynchrounsly and continue to + process client requests until all pending completion events + have been collected but some clients seem to assume that + the server is done using the shared memory segment once it + has processed the request */ + if (pShmInfo) + { + /* wait for all back-end servers to complete */ + do { + dmxDispatch (); + } while (pShmInfo->pendingEvents && dmxWaitForResponse ()); + } + } + + if (stuff->sendEvent) + { + xShmCompletionEvent ev; + + ev.type = ShmCompletionCode; + ev.drawable = stuff->drawable; + ev.sequenceNumber = client->sequence; + ev.minorEvent = X_ShmPutImage; + ev.majorEvent = ShmReqCode; + ev.shmseg = stuff->shmseg; + ev.offset = stuff->offset; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } + + return (client->noClientException); } void dmxInitShm (void) @@ -225,10 +614,8 @@ void dmxInitShm (void) dmxSaveProcVector[i] = ProcShmVector[i]; ProcShmVector[X_ShmAttach] = dmxProcShmAttach; - ProcShmVector[X_ShmDetach] = dmxProcShmDetach; ProcShmVector[X_ShmGetImage] = dmxProcShmGetImage; ProcShmVector[X_ShmPutImage] = dmxProcShmPutImage; - ProcShmVector[X_ShmGetImage] = dmxProcShmGetImage; } void dmxResetShm (void) diff --git a/hw/dmx/dmxshm.h b/hw/dmx/dmxshm.h index 2be79376f..167b324a5 100644 --- a/hw/dmx/dmxshm.h +++ b/hw/dmx/dmxshm.h @@ -27,8 +27,32 @@ #define DMXSHM_H #ifdef MITSHM + +#include +#include + +typedef struct _dmxShmSegInfo { + struct _dmxShmSegInfo *next; + uint32_t shmid; + int refcnt; + uint8_t readOnly; + uint32_t pendingEvents; + xcb_shm_seg_t shmseg[MAXSCREENS]; + xcb_void_cookie_t cookie[MAXSCREENS]; +} dmxShmSegInfoRec, *dmxShmSegInfoPtr; + +extern unsigned long DMX_SHMSEG; + extern void ShmRegisterDmxFuncs (ScreenPtr pScreen); +extern void dmxBEAttachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo); +extern void dmxBEDetachShmSeg (DMXScreenInfo *dmxScreen, + dmxShmSegInfoPtr pShmInfo); + +extern Bool dmxScreenEventCheckShm (ScreenPtr pScreen, + xcb_generic_event_t *event); + extern void dmxInitShm (void); extern void dmxResetShm (void); #endif diff --git a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c index d93d64b2a..a0fc78df8 100644 --- a/hw/dmx/dmxsync.c +++ b/hw/dmx/dmxsync.c @@ -142,23 +142,10 @@ static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) pending replies */ dmxSyncTimer = NULL; - while (dmxSyncRequest && dmxWaitForResponse ()) - { + /* wait for all pending sync replies */ + do { dmxDispatch (); - - for (i = 0; i < dmxNumScreens; i++) - { - if (!dmxScreens[i].alive) - { - /* remove pending replies from disconnected screens */ - if (dmxScreens[i].sync.sequence) - { - dmxScreens[i].sync.sequence = 0; - dmxSyncRequest--; - } - } - } - } + } while (dmxSyncRequest && dmxWaitForResponse ()); if (dmxSyncPending) { @@ -301,20 +288,21 @@ dmxScreenReplyCheckSync (ScreenPtr pScreen, { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - if (sequence != dmxScreen->sync.sequence) - return FALSE; + if (reply->response_type || reply->pad0 != DMX_DETACHED) + if (sequence != dmxScreen->sync.sequence) + return FALSE; - dmxScreen->sync.sequence = 0; - - dmxSyncRequest--; - if (dmxSyncRequest == 0) + if (dmxScreen->sync.sequence) { - if (dmxSyncPending == 0 && dmxSyncTimer) + dmxScreen->sync.sequence = 0; + dmxSyncRequest--; + + if (dmxSyncRequest == 0 && dmxSyncPending == 0 && dmxSyncTimer) { TimerFree (dmxSyncTimer); dmxSyncTimer = NULL; } } - + return TRUE; }