void rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) { sraRectangleIterator* i; sraRect rect; int j,widthInBytes,bpp=rfbScreen->rfbServerFormat.bitsPerPixel/8, rowstride=rfbScreen->paddedWidthInBytes; char *in,*out; rfbUndrawCursor(rfbScreen); /* copy it, really */ i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0); while(sraRgnIteratorNext(i,&rect)) { widthInBytes = (rect.x2-rect.x1)*bpp; out = rfbScreen->frameBuffer+rect.x1*bpp+rect.y1*rowstride; in = rfbScreen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride; if(dy<0) for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride) memmove(out,in,widthInBytes); else { out += rowstride*(rect.y2-rect.y1-1); in += rowstride*(rect.y2-rect.y1-1); for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride) memmove(out,in,widthInBytes); } } rfbScheduleCopyRegion(rfbScreen,copyRegion,dx,dy); }
void defaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl) { if(x!=cl->screen->cursorX || y!=cl->screen->cursorY) { cl->cursorWasMoved = TRUE; if(cl->screen->cursorIsDrawn) rfbUndrawCursor(cl->screen); LOCK(cl->screen->cursorMutex); if(!cl->screen->cursorIsDrawn) { cl->screen->cursorX = x; cl->screen->cursorY = y; } UNLOCK(cl->screen->cursorMutex); } }
int rfbSelectBox(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font, char** list, int x1,int y1,int x2,int y2, Pixel colour,Pixel backColour, int border,SelectionChangedHookPtr selChangedHook) { int bpp = rfbScreen->bitsPerPixel/8; char* frameBufferBackup; void* screenDataBackup = rfbScreen->screenData; KbdAddEventProcPtr kbdAddEventBackup = rfbScreen->kbdAddEvent; PtrAddEventProcPtr ptrAddEventBackup = rfbScreen->ptrAddEvent; GetCursorProcPtr getCursorPtrBackup = rfbScreen->getCursorPtr; DisplayHookPtr displayHookBackup = rfbScreen->displayHook; rfbSelectData selData; int i,j,k; int fx1,fy1,fx2,fy2; /* for font bbox */ if(list==0 || *list==0) return(-1); rfbWholeFontBBox(font, &fx1, &fy1, &fx2, &fy2); selData.textH = fy2-fy1; /* I need at least one line for the choice and one for the buttons */ if(y2-y1<selData.textH*2+3*border) return(-1); selData.xhot = -fx1; selData.yhot = -fy2; selData.x1 = x1+border; selData.y1 = y1+border; selData.y2 = y2-selData.textH-3*border; selData.x2 = x2-2*border; selData.pageH = (selData.y2-selData.y1)/selData.textH; i = rfbWidthOfString(font,okStr); j = rfbWidthOfString(font,cancelStr); selData.buttonWidth= k = 4*border+(i<j)?j:i; selData.okBX = x1+(x2-x1-2*k)/3; if(selData.okBX<x1+border) /* too narrow! */ return(-1); selData.cancelBX = x1+k+(x2-x1-2*k)*2/3; selData.okX = selData.okBX+(k-i)/2; selData.cancelX = selData.cancelBX+(k-j)/2; selData.okY = y2-border; rfbUndrawCursor(rfbScreen); frameBufferBackup = (char*)malloc(bpp*(x2-x1)*(y2-y1)); selData.state = SELECTING; selData.screen = rfbScreen; selData.font = font; selData.list = list; selData.colour = colour; selData.backColour = backColour; for(i=0;list[i];i++); selData.selected = i; selData.listSize = i; selData.displayStart = i; selData.lastButtons = 0; selData.selChangedHook = selChangedHook; rfbScreen->screenData = &selData; rfbScreen->kbdAddEvent = selKbdAddEvent; rfbScreen->ptrAddEvent = selPtrAddEvent; rfbScreen->getCursorPtr = selGetCursorPtr; rfbScreen->displayHook = 0; /* backup screen */ for(j=0;j<y2-y1;j++) memcpy(frameBufferBackup+j*(x2-x1)*bpp, rfbScreen->frameBuffer+j*rfbScreen->paddedWidthInBytes+x1*bpp, (x2-x1)*bpp); /* paint list and buttons */ rfbFillRect(rfbScreen,x1,y1,x2,y2,colour); selPaintButtons(&selData,FALSE,FALSE); selSelect(&selData,0); /* modal loop */ while(selData.state == SELECTING) rfbProcessEvents(rfbScreen,20000); /* copy back screen data */ for(j=0;j<y2-y1;j++) memcpy(rfbScreen->frameBuffer+j*rfbScreen->paddedWidthInBytes+x1*bpp, frameBufferBackup+j*(x2-x1)*bpp, (x2-x1)*bpp); free(frameBufferBackup); rfbMarkRectAsModified(rfbScreen,x1,y1,x2,y2); rfbScreen->screenData = screenDataBackup; rfbScreen->kbdAddEvent = kbdAddEventBackup; rfbScreen->ptrAddEvent = ptrAddEventBackup; rfbScreen->getCursorPtr = getCursorPtrBackup; rfbScreen->displayHook = displayHookBackup; if(selData.state==CANCEL) selData.selected=-1; return(selData.selected); }
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) { rfbClientIteratorPtr iterator; rfbClientPtr cl; rfbUndrawCursor(rfbScreen); 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)) */ { #ifdef HAVE_PTHREADS if(!cl->screen->backgroundLoop) #endif { sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion); sraRgnOr(updateRegion,cl->copyRegion); UNLOCK(cl->updateMutex); rfbSendFramebufferUpdate(cl,updateRegion); sraRgnDestroy(updateRegion); continue; } } #endif } else { sraRgnOr(cl->modifiedRegion,copyRegion); } TSIGNAL(cl->updateCond); UNLOCK(cl->updateMutex); } rfbReleaseClientIterator(iterator); }