double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1, int X2, int Y2) { double a, A, o; sraRegionPtr r, R; sraRectangleIterator *iter; sraRect rt; a = nabs((x2 - x1) * (y2 - y1)); A = nabs((X2 - X1) * (Y2 - Y1)); r = sraRgnCreateRect(x1, y1, x2, y2); R = sraRgnCreateRect(X1, Y1, X2, Y2); sraRgnAnd(r, R); o = 0.0; iter = sraRgnGetIterator(r); while (sraRgnIteratorNext(iter, &rt)) { o += nabs( (rt.x2 - rt.x1) * (rt.y2 - rt.y1) ); } sraRgnReleaseIterator(iter); sraRgnDestroy(r); sraRgnDestroy(R); if (a < A) { o = o/a; } else { o = o/A; } return o; }
static void * clientOutput(void *data) { rfbClientPtr cl = (rfbClientPtr)data; Bool haveUpdate; sraRegion* updateRegion; while (1) { haveUpdate = false; while (!haveUpdate) { if (cl->sock == -1) { /* Client has disconnected. */ return NULL; } LOCK(cl->updateMutex); haveUpdate = FB_UPDATE_PENDING(cl); if(!haveUpdate) { updateRegion = sraRgnCreateRgn(cl->modifiedRegion); haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion); sraRgnDestroy(updateRegion); } UNLOCK(cl->updateMutex); if (!haveUpdate) { TIMEDWAIT(cl->updateCond, cl->updateMutex, PING_MS); UNLOCK(cl->updateMutex); /* we really needn't lock now. */ if (!haveUpdate) rfbSendPing(cl); } } /* OK, now, to save bandwidth, wait a little while for more updates to come along. */ usleep(cl->screen->rfbDeferUpdateTime * 1000); /* Now, get the region we're going to update, and remove it from cl->modifiedRegion _before_ we send the update. That way, if anything that overlaps the region we're sending is updated, we'll be sure to do another update later. */ LOCK(cl->updateMutex); updateRegion = sraRgnCreateRgn(cl->modifiedRegion); UNLOCK(cl->updateMutex); /* Now actually send the update. */ rfbIncrClientRef(cl); rfbSendFramebufferUpdate(cl, updateRegion); rfbDecrClientRef(cl); sraRgnDestroy(updateRegion); } return NULL; }
static void * clientOutput(void *data) { rfbClientPtr cl = (rfbClientPtr)data; rfbBool haveUpdate; sraRegion* updateRegion; while (1) { haveUpdate = false; while (!haveUpdate) { if (cl->sock == -1) { /* Client has disconnected. */ return NULL; } if (cl->state != RFB_NORMAL || cl->onHold) { /* just sleep until things get normal */ usleep(cl->screen->deferUpdateTime * 1000); continue; } LOCK(cl->updateMutex); if (sraRgnEmpty(cl->requestedRegion)) { ; /* always require a FB Update Request (otherwise can crash.) */ } else { haveUpdate = FB_UPDATE_PENDING(cl); if(!haveUpdate) { updateRegion = sraRgnCreateRgn(cl->modifiedRegion); haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion); sraRgnDestroy(updateRegion); } } if (!haveUpdate) { WAIT(cl->updateCond, cl->updateMutex); } UNLOCK(cl->updateMutex); } /* OK, now, to save bandwidth, wait a little while for more updates to come along. */ usleep(cl->screen->deferUpdateTime * 1000); /* Now, get the region we're going to update, and remove it from cl->modifiedRegion _before_ we send the update. That way, if anything that overlaps the region we're sending is updated, we'll be sure to do another update later. */ LOCK(cl->updateMutex); updateRegion = sraRgnCreateRgn(cl->modifiedRegion); UNLOCK(cl->updateMutex); /* Now actually send the update. */ rfbIncrClientRef(cl); LOCK(cl->sendMutex); rfbSendFramebufferUpdate(cl, updateRegion); UNLOCK(cl->sendMutex); rfbDecrClientRef(cl); sraRgnDestroy(updateRegion); } /* Not reached. */ return NULL; }
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) { rfbClientIteratorPtr iterator; rfbClientPtr cl; iterator=rfbGetClientIterator(rfbScreen); while((cl=rfbClientIteratorNext(iterator))) { LOCK(cl->updateMutex); if(cl->useCopyRect) { sraRegionPtr modifiedRegionBackup; if(!sraRgnEmpty(cl->copyRegion)) { if(cl->copyDX!=dx || cl->copyDY!=dy) { /* if a copyRegion was not yet executed, treat it as a * modifiedRegion. The idea: in this case it could be * source of the new copyRect or modified anyway. */ sraRgnOr(cl->modifiedRegion,cl->copyRegion); sraRgnMakeEmpty(cl->copyRegion); } else { /* we have to set the intersection of the source of the copy * and the old copy to modified. */ modifiedRegionBackup=sraRgnCreateRgn(copyRegion); sraRgnOffset(modifiedRegionBackup,-dx,-dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); } } sraRgnOr(cl->copyRegion,copyRegion); cl->copyDX = dx; cl->copyDY = dy; /* if there were modified regions, which are now copied, * mark them as modified, because the source of these can be overlapped * either by new modified or now copied regions. */ modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); sraRgnOffset(modifiedRegionBackup,dx,dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); if(!cl->enableCursorShapeUpdates) { /* * n.b. (dx, dy) is the vector pointing in the direction the * copyrect displacement will take place. copyRegion is the * destination rectangle (say), not the source rectangle. */ sraRegionPtr cursorRegion; int x = cl->cursorX - cl->screen->cursor->xhot; int y = cl->cursorY - cl->screen->cursor->yhot; int w = cl->screen->cursor->width; int h = cl->screen->cursor->height; cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); sraRgnAnd(cursorRegion, cl->copyRegion); if(!sraRgnEmpty(cursorRegion)) { /* * current cursor rect overlaps with the copy region *dest*, * mark it as modified since we won't copy-rect stuff to it. */ sraRgnOr(cl->modifiedRegion, cursorRegion); } sraRgnDestroy(cursorRegion); cursorRegion = sraRgnCreateRect(x, y, x + w, y + h); /* displace it to check for overlap with copy region source: */ sraRgnOffset(cursorRegion, dx, dy); sraRgnAnd(cursorRegion, cl->copyRegion); if(!sraRgnEmpty(cursorRegion)) { /* * current cursor rect overlaps with the copy region *source*, * mark the *displaced* cursorRegion as modified since we * won't copyrect stuff to it. */ sraRgnOr(cl->modifiedRegion, cursorRegion); } sraRgnDestroy(cursorRegion); } } else { sraRgnOr(cl->modifiedRegion,copyRegion); } TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }
int xdamage_hint_skip(int y) { static sraRegionPtr scanline = NULL; static sraRegionPtr tmpl_y = NULL; int fast_tmpl = 1; sraRegionPtr reg, tmpl; int ret, i, n, nreg; #ifndef NO_NCACHE static int ncache_no_skip = 0; static double last_ncache_no_skip = 0.0; static double last_ncache_no_skip_long = 0.0, ncache_fac = 0.25; #endif if (! xdamage_present || ! use_xdamage) { return 0; /* cannot skip */ } if (! xdamage_regions) { return 0; /* cannot skip */ } if (! scanline) { /* keep it around to avoid malloc etc, recreate */ scanline = sraRgnCreate(); } if (! tmpl_y) { tmpl_y = sraRgnCreateRect(0, 0, dpy_x, 1); } nreg = (xdamage_memory * NSCAN) + 1; #ifndef NO_NCACHE if (ncache > 0) { if (ncache_no_skip == 0) { double now = g_now; if (now > last_ncache_no_skip + 8.0) { ncache_no_skip = 1; } else if (now < last_bs_restore + 0.5) { ncache_no_skip = 1; } else if (now < last_su_restore + 0.5) { ncache_no_skip = 1; } else if (now < last_copyrect + 0.5) { ncache_no_skip = 1; } if (ncache_no_skip) { last_ncache_no_skip = dnow(); if (now > last_ncache_no_skip_long + 60.0) { ncache_fac = 2.0; last_ncache_no_skip_long = now; } else { ncache_fac = 0.25; } return 0; } } else { if (ncache_no_skip++ >= ncache_fac*nreg + 4) { ncache_no_skip = 0; } else { return 0; } } } #endif if (fast_tmpl) { sraRgnOffset(tmpl_y, 0, y); tmpl = tmpl_y; } else { tmpl = sraRgnCreateRect(0, y, dpy_x, y+1); } ret = 1; for (i=0; i<nreg; i++) { /* go back thru the history starting at most recent */ n = (xdamage_ticker + nreg - i) % nreg; reg = xdamage_regions[n]; if (reg == NULL) { continue; } if (sraRgnEmpty(reg)) { /* checking for emptiness is very fast */ continue; } sraRgnMakeEmpty(scanline); sraRgnOr(scanline, tmpl); if (sraRgnAnd(scanline, reg)) { ret = 0; break; } } if (fast_tmpl) { sraRgnOffset(tmpl_y, 0, -y); } else { sraRgnDestroy(tmpl); } if (0) fprintf(stderr, "xdamage_hint_skip: %d -> %d\n", y, ret); return ret; }
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) { rfbClientIteratorPtr iterator; rfbClientPtr cl; iterator=rfbGetClientIterator(rfbScreen); while((cl=rfbClientIteratorNext(iterator))) { LOCK(cl->updateMutex); if(cl->useCopyRect) { sraRegionPtr modifiedRegionBackup; if(!sraRgnEmpty(cl->copyRegion)) { if(cl->copyDX!=dx || cl->copyDY!=dy) { /* if a copyRegion was not yet executed, treat it as a * modifiedRegion. The idea: in this case it could be * source of the new copyRect or modified anyway. */ sraRgnOr(cl->modifiedRegion,cl->copyRegion); sraRgnMakeEmpty(cl->copyRegion); } else { /* we have to set the intersection of the source of the copy * and the old copy to modified. */ modifiedRegionBackup=sraRgnCreateRgn(copyRegion); sraRgnOffset(modifiedRegionBackup,-dx,-dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); } } sraRgnOr(cl->copyRegion,copyRegion); cl->copyDX = dx; cl->copyDY = dy; /* if there were modified regions, which are now copied, * mark them as modified, because the source of these can be overlapped * either by new modified or now copied regions. */ modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion); sraRgnOffset(modifiedRegionBackup,dx,dy); sraRgnAnd(modifiedRegionBackup,cl->copyRegion); sraRgnOr(cl->modifiedRegion,modifiedRegionBackup); sraRgnDestroy(modifiedRegionBackup); #if 0 /* TODO: is this needed? Or does it mess up deferring? */ /* while(!sraRgnEmpty(cl->copyRegion)) */ { { sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion); sraRgnOr(updateRegion,cl->copyRegion); UNLOCK(cl->updateMutex); rfbSendFramebufferUpdate(cl,updateRegion); sraRgnDestroy(updateRegion); continue; } } #endif } else { sraRgnOr(cl->modifiedRegion,copyRegion); } UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }