diff --git a/libvncclient/corre.c b/libvncclient/corre.c index baf91cc..66e3b08 100644 --- a/libvncclient/corre.c +++ b/libvncclient/corre.c @@ -46,7 +46,7 @@ HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix))) return FALSE; - FillRectangle(client, rx, ry, rw, rh, pix); + client->GotFillRect(client, rx, ry, rw, rh, pix); if (!ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8)))) return FALSE; @@ -61,7 +61,7 @@ HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh) w = *ptr++; h = *ptr++; - FillRectangle(client, rx+x, ry+y, w, h, pix); + client->GotFillRect(client, rx+x, ry+y, w, h, pix); } return TRUE; diff --git a/libvncclient/hextile.c b/libvncclient/hextile.c index 8698445..05a7cf5 100644 --- a/libvncclient/hextile.c +++ b/libvncclient/hextile.c @@ -55,7 +55,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8))) return FALSE; - CopyRectangle(client, (uint8_t *)client->buffer, x, y, w, h); + client->GotBitmap(client, (uint8_t *)client->buffer, x, y, w, h); continue; } @@ -64,7 +64,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg))) return FALSE; - FillRectangle(client, x, y, w, h, bg); + client->GotFillRect(client, x, y, w, h, bg); if (subencoding & rfbHextileForegroundSpecified) if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg))) @@ -100,7 +100,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh) sh = rfbHextileExtractH(*ptr); ptr++; - FillRectangle(client, x+sx, y+sy, sw, sh, fg); + client->GotFillRect(client, x+sx, y+sy, sw, sh, fg); } } else { @@ -115,7 +115,7 @@ HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh) sh = rfbHextileExtractH(*ptr); ptr++; - FillRectangle(client, x+sx, y+sy, sw, sh, fg); + client->GotFillRect(client, x+sx, y+sy, sw, sh, fg); } } } diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index 4ff1d3b..e099f1a 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -145,125 +145,6 @@ void* rfbClientGetClientData(rfbClient* client, void* tag) return NULL; } -/* messages */ - -static rfbBool CheckRect(rfbClient* client, int x, int y, int w, int h) { - return x + w <= client->width && y + h <= client->height; -} - -static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) { - int i,j; - - if (client->frameBuffer == NULL) { - return; - } - - if (!CheckRect(client, x, y, w, h)) { - rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h); - return; - } - -#define FILL_RECT(BPP) \ - for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \ - for(i=x;iframeBuffer)[j+i]=colour; - - switch(client->format.bitsPerPixel) { - case 8: FILL_RECT(8); break; - case 16: FILL_RECT(16); break; - case 32: FILL_RECT(32); break; - default: - rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); - } -} - -static void CopyRectangle(rfbClient* client, uint8_t* buffer, int x, int y, int w, int h) { - int j; - - if (client->frameBuffer == NULL) { - return; - } - - if (!CheckRect(client, x, y, w, h)) { - rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h); - return; - } - -#define COPY_RECT(BPP) \ - { \ - int rs = w * BPP / 8, rs2 = client->width * BPP / 8; \ - for (j = ((x * (BPP / 8)) + (y * rs2)); j < (y + h) * rs2; j += rs2) { \ - memcpy(client->frameBuffer + j, buffer, rs); \ - buffer += rs; \ - } \ - } - - switch(client->format.bitsPerPixel) { - case 8: COPY_RECT(8); break; - case 16: COPY_RECT(16); break; - case 32: COPY_RECT(32); break; - default: - rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); - } -} - -/* TODO: test */ -static void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { - int i,j; - - if (client->frameBuffer == NULL) { - return; - } - - if (!CheckRect(client, src_x, src_y, w, h)) { - rfbClientLog("Source rect out of bounds: %dx%d at (%d, %d)\n", src_x, src_y, w, h); - return; - } - - if (!CheckRect(client, dest_x, dest_y, w, h)) { - rfbClientLog("Dest rect out of bounds: %dx%d at (%d, %d)\n", dest_x, dest_y, w, h); - return; - } - -#define COPY_RECT_FROM_RECT(BPP) \ - { \ - uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \ - if (dest_y < src_y) { \ - for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \ - if (dest_x < src_x) { \ - for(i = dest_x; i < dest_x+w; i++) { \ - ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ - } \ - } else { \ - for(i = dest_x+w-1; i >= dest_x; i--) { \ - ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ - } \ - } \ - } \ - } else { \ - for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \ - if (dest_x < src_x) { \ - for(i = dest_x; i < dest_x+w; i++) { \ - ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ - } \ - } else { \ - for(i = dest_x+w-1; i >= dest_x; i--) { \ - ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ - } \ - } \ - } \ - } \ - } - - switch(client->format.bitsPerPixel) { - case 8: COPY_RECT_FROM_RECT(8); break; - case 16: COPY_RECT_FROM_RECT(16); break; - case 32: COPY_RECT_FROM_RECT(32); break; - default: - rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); - } -} - static rfbBool HandleRRE8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleRRE16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleRRE32(rfbClient* client, int rx, int ry, int rw, int rh); @@ -1980,7 +1861,7 @@ HandleRFBServerMessage(rfbClient* client) if (!ReadFromRFBServer(client, client->buffer,bytesPerLine * linesToRead)) return FALSE; - CopyRectangle(client, (uint8_t *)client->buffer, + client->GotBitmap(client, (uint8_t *)client->buffer, rect.r.x, y, rect.r.w,linesToRead); h -= linesToRead; @@ -2006,13 +1887,8 @@ HandleRFBServerMessage(rfbClient* client) client->SoftCursorLockArea(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h); - if (client->GotCopyRect != NULL) { - client->GotCopyRect(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h, - rect.r.x, rect.r.y); - } else - CopyRectangleFromRectangle(client, - cr.srcX, cr.srcY, rect.r.w, rect.r.h, - rect.r.x, rect.r.y); + client->GotCopyRect(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h, + rect.r.x, rect.r.y); break; } diff --git a/libvncclient/rre.c b/libvncclient/rre.c index 94158c9..752d7cc 100644 --- a/libvncclient/rre.c +++ b/libvncclient/rre.c @@ -45,7 +45,7 @@ HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix))) return FALSE; - FillRectangle(client, rx, ry, rw, rh, pix); + client->GotFillRect(client, rx, ry, rw, rh, pix); for (i = 0; i < hdr.nSubrects; i++) { if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix))) @@ -59,7 +59,7 @@ HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh) subrect.w = rfbClientSwap16IfLE(subrect.w); subrect.h = rfbClientSwap16IfLE(subrect.h); - FillRectangle(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix); + client->GotFillRect(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix); } return TRUE; diff --git a/libvncclient/tight.c b/libvncclient/tight.c index 2f9fbab..2447ad8 100644 --- a/libvncclient/tight.c +++ b/libvncclient/tight.c @@ -131,7 +131,7 @@ HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh) return FALSE; #endif - FillRectangle(client, rx, ry, rw, rh, fill_colour); + client->GotFillRect(client, rx, ry, rw, rh, fill_colour); return TRUE; } @@ -198,7 +198,7 @@ HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh) buffer2 = &client->buffer[TIGHT_MIN_TO_COMPRESS * 4]; filterFn(client, rh, (CARDBPP *)buffer2); - CopyRectangle(client, (uint8_t *)buffer2, rx, ry, rw, rh); + client->GotBitmap(client, (uint8_t *)buffer2, rx, ry, rw, rh); return TRUE; } @@ -277,7 +277,7 @@ HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (extraBytes > 0) memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes); - CopyRectangle(client, (uint8_t *)buffer2, rx, ry+rowsProcessed, rw, numRows); + client->GotBitmap(client, (uint8_t *)buffer2, rx, ry+rowsProcessed, rw, numRows); rowsProcessed += numRows; } @@ -547,6 +547,9 @@ DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h) return FALSE; } + if(client->GotJpeg != NULL) + return client->GotJpeg(client, compressedData, compressedLen, x, y, w, h); + cinfo.err = jpeg_std_error(&jerr); cinfo.client_data = client; jpeg_create_decompress(&cinfo); @@ -577,7 +580,7 @@ DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h) *pixelPtr++ = RGB24_TO_PIXEL(BPP, client->buffer[dx*3], client->buffer[dx*3+1], client->buffer[dx*3+2]); } - CopyRectangle(client, (uint8_t *)&client->buffer[RFB_BUFFER_SIZE / 2], x, y + dy, w, 1); + client->GotBitmap(client, (uint8_t *)&client->buffer[RFB_BUFFER_SIZE / 2], x, y + dy, w, 1); dy++; } diff --git a/libvncclient/ultra.c b/libvncclient/ultra.c index 32a1b2b..a82e2ed 100644 --- a/libvncclient/ultra.c +++ b/libvncclient/ultra.c @@ -98,7 +98,7 @@ HandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh) /* Put the uncompressed contents of the update on the screen. */ if ( inflateResult == LZO_E_OK ) { - CopyRectangle(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh); + client->GotBitmap(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh); } else { @@ -199,7 +199,7 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) if (se == rfbEncodingRaw) { - CopyRectangle(client, (unsigned char *)ptr, sx, sy, sw, sh); + client->GotBitmap(client, (unsigned char *)ptr, sx, sy, sw, sh); ptr += ((sw * sh) * (BPP / 8)); } } diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c index d81e298..afd84fd 100644 --- a/libvncclient/vncviewer.c +++ b/libvncclient/vncviewer.c @@ -113,6 +113,125 @@ static rfbBool MallocFrameBuffer(rfbClient* client) { return client->frameBuffer?TRUE:FALSE; } +/* messages */ + +static rfbBool CheckRect(rfbClient* client, int x, int y, int w, int h) { + return x + w <= client->width && y + h <= client->height; +} + +static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) { + int i,j; + + if (client->frameBuffer == NULL) { + return; + } + + if (!CheckRect(client, x, y, w, h)) { + rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h); + return; + } + +#define FILL_RECT(BPP) \ + for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \ + for(i=x;iframeBuffer)[j+i]=colour; + + switch(client->format.bitsPerPixel) { + case 8: FILL_RECT(8); break; + case 16: FILL_RECT(16); break; + case 32: FILL_RECT(32); break; + default: + rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); + } +} + +static void CopyRectangle(rfbClient* client, uint8_t* buffer, int x, int y, int w, int h) { + int j; + + if (client->frameBuffer == NULL) { + return; + } + + if (!CheckRect(client, x, y, w, h)) { + rfbClientLog("Rect out of bounds: %dx%d at (%d, %d)\n", x, y, w, h); + return; + } + +#define COPY_RECT(BPP) \ + { \ + int rs = w * BPP / 8, rs2 = client->width * BPP / 8; \ + for (j = ((x * (BPP / 8)) + (y * rs2)); j < (y + h) * rs2; j += rs2) { \ + memcpy(client->frameBuffer + j, buffer, rs); \ + buffer += rs; \ + } \ + } + + switch(client->format.bitsPerPixel) { + case 8: COPY_RECT(8); break; + case 16: COPY_RECT(16); break; + case 32: COPY_RECT(32); break; + default: + rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); + } +} + +/* TODO: test */ +static void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { + int i,j; + + if (client->frameBuffer == NULL) { + return; + } + + if (!CheckRect(client, src_x, src_y, w, h)) { + rfbClientLog("Source rect out of bounds: %dx%d at (%d, %d)\n", src_x, src_y, w, h); + return; + } + + if (!CheckRect(client, dest_x, dest_y, w, h)) { + rfbClientLog("Dest rect out of bounds: %dx%d at (%d, %d)\n", dest_x, dest_y, w, h); + return; + } + +#define COPY_RECT_FROM_RECT(BPP) \ + { \ + uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \ + if (dest_y < src_y) { \ + for(j = dest_y*client->width; j < (dest_y+h)*client->width; j += client->width) { \ + if (dest_x < src_x) { \ + for(i = dest_x; i < dest_x+w; i++) { \ + ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ + } \ + } else { \ + for(i = dest_x+w-1; i >= dest_x; i--) { \ + ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ + } \ + } \ + } \ + } else { \ + for(j = (dest_y+h-1)*client->width; j >= dest_y*client->width; j-=client->width) { \ + if (dest_x < src_x) { \ + for(i = dest_x; i < dest_x+w; i++) { \ + ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ + } \ + } else { \ + for(i = dest_x+w-1; i >= dest_x; i--) { \ + ((uint##BPP##_t*)client->frameBuffer)[j+i]=_buffer[j+i]; \ + } \ + } \ + } \ + } \ + } + + switch(client->format.bitsPerPixel) { + case 8: COPY_RECT_FROM_RECT(8); break; + case 16: COPY_RECT_FROM_RECT(16); break; + case 32: COPY_RECT_FROM_RECT(32); break; + default: + rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); + } +} + static void initAppData(AppData* data) { data->shareDesktop=TRUE; data->viewOnly=FALSE; @@ -208,6 +327,9 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, client->SoftCursorLockArea = DummyRect; client->SoftCursorUnlockScreen = Dummy; client->GotFrameBufferUpdate = DummyRect; + client->GotCopyRect = CopyRectangleFromRectangle; + client->GotFillRect = FillRectangle; + client->GotBitmap = CopyRectangle; client->FinishedFrameBufferUpdate = NULL; client->GetPassword = ReadPassword; client->MallocFrameBuffer = MallocFrameBuffer; diff --git a/libvncclient/zlib.c b/libvncclient/zlib.c index e872d40..fc6f138 100644 --- a/libvncclient/zlib.c +++ b/libvncclient/zlib.c @@ -142,7 +142,7 @@ HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh) if ( inflateResult == Z_OK ) { /* Put the uncompressed contents of the update on the screen. */ - CopyRectangle(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh); + client->GotBitmap(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh); } else { diff --git a/libvncclient/zrle.c b/libvncclient/zrle.c index 0128146..e732046 100644 --- a/libvncclient/zrle.c +++ b/libvncclient/zrle.c @@ -278,7 +278,7 @@ static int HandleZRLETile(rfbClient* client, for(i=x; iframeBuffer)[j+i] = UncompressCPixel(buffer); #else - CopyRectangle(client, buffer, x, y, w, h); + client->GotBitmap(client, buffer, x, y, w, h); buffer+=w*h*REALBPP/8; #endif } @@ -289,7 +289,7 @@ static int HandleZRLETile(rfbClient* client, if(1+REALBPP/8>buffer_length) return -4; - FillRectangle(client, x, y, w, h, color); + client->GotFillRect(client, x, y, w, h, color); buffer+=REALBPP/8; diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h index 9fdb008..505dd9c 100644 --- a/rfb/rfbclient.h +++ b/rfb/rfbclient.h @@ -186,6 +186,9 @@ typedef void (*BellProc)(struct _rfbClient* client); */ typedef void (*GotCursorShapeProc)(struct _rfbClient* client, int xhot, int yhot, int width, int height, int bytesPerPixel); typedef void (*GotCopyRectProc)(struct _rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y); +typedef void (*GotFillRectProc)(struct _rfbClient* client, int x, int y, int w, int h, uint32_t colour); +typedef void (*GotBitmapProc)(struct _rfbClient* client, const uint8_t* buffer, int x, int y, int w, int h); +typedef rfbBool (*GotJpegProc)(struct _rfbClient* client, const uint8_t* buffer, int length, int x, int y, int w, int h); typedef rfbBool (*LockWriteToTLSProc)(struct _rfbClient* client); typedef rfbBool (*UnlockWriteToTLSProc)(struct _rfbClient* client); @@ -371,6 +374,18 @@ typedef struct _rfbClient { LockWriteToTLSProc LockWriteToTLS; UnlockWriteToTLSProc UnlockWriteToTLS; + /** Hooks for custom rendering + * + * VNC rendering boils down to 3 activities: + * - GotCopyRect: copy an area of the framebuffer + * - GotFillRect: fill an area of the framebuffer with a solid color + * - GotBitmap: copy the bitmap in the buffer into the framebuffer + * The client application should either set all three of these or none! + */ + GotFillRectProc GotFillRect; + GotBitmapProc GotBitmap; + /** Hook for custom JPEG decoding and rendering */ + GotJpegProc GotJpeg; } rfbClient; /* cursor.c */