Bool HandleRFBServerMessage() { rfbServerToClientMsg msg; if (!ReadFromRFBServer((char *)&msg, 1)) return False; switch (msg.type) { case rfbSetColourMapEntries: { int i; CARD16 rgb[3]; XColor xc; if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) return False; msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour); msg.scme.nColours = Swap16IfLE(msg.scme.nColours); for (i = 0; i < msg.scme.nColours; i++) { if (!ReadFromRFBServer((char *)rgb, 6)) return False; xc.pixel = msg.scme.firstColour + i; xc.red = Swap16IfLE(rgb[0]); xc.green = Swap16IfLE(rgb[1]); xc.blue = Swap16IfLE(rgb[2]); xc.flags = DoRed|DoGreen|DoBlue; XStoreColor(dpy, cmap, &xc); } break; } case rfbFramebufferUpdate: { rfbFramebufferUpdateRectHeader rect; int linesToRead; int bytesPerLine; int i; int usecs; if (!ReadFromRFBServer(((char *)&msg.fu) + 1, sz_rfbFramebufferUpdateMsg - 1)) return False; msg.fu.nRects = Swap16IfLE(msg.fu.nRects); for (i = 0; i < msg.fu.nRects; i++) { if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) return False; rect.encoding = Swap32IfLE(rect.encoding); if (rect.encoding == rfbEncodingLastRect) break; rect.r.x = Swap16IfLE(rect.r.x); rect.r.y = Swap16IfLE(rect.r.y); rect.r.w = Swap16IfLE(rect.r.w); rect.r.h = Swap16IfLE(rect.r.h); if (rect.encoding == rfbEncodingXCursor || rect.encoding == rfbEncodingRichCursor) { if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, rect.encoding)) { return False; } continue; } if (rect.encoding == rfbEncodingPointerPos) { if (!HandleCursorPos(rect.r.x, rect.r.y)) { return False; } continue; } if ((rect.r.x + rect.r.w > si.framebufferWidth) || (rect.r.y + rect.r.h > si.framebufferHeight)) { fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); return False; } if (rect.r.h * rect.r.w == 0) { fprintf(stderr,"Zero size rect - ignoring\n"); continue; } /* If RichCursor encoding is used, we should prevent collisions between framebuffer updates and cursor drawing operations. */ SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); switch (rect.encoding) { case rfbEncodingRaw: bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; linesToRead = BUFFER_SIZE / bytesPerLine; while (rect.r.h > 0) { if (linesToRead > rect.r.h) linesToRead = rect.r.h; if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) return False; CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, linesToRead); rect.r.h -= linesToRead; rect.r.y += linesToRead; } break; case rfbEncodingCopyRect: { rfbCopyRect cr; if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) return False; cr.srcX = Swap16IfLE(cr.srcX); cr.srcY = Swap16IfLE(cr.srcY); /* If RichCursor encoding is used, we should extend our "cursor lock area" (previously set to destination rectangle) to the source rectangle as well. */ SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h); if (appData.copyRectDelay != 0) { XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); #if VNC_CAPTURE myxfillrec(dpy, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); #endif XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); #if VNC_CAPTURE myxfillrec(dpy, dstGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); #endif XSync(dpy,False); usleep(appData.copyRectDelay * 1000); XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); #if VNC_CAPTURE myxfillrec(dpy, dstGC, rect.r.x, rect.r.y, rect.r.w, rect.r.h); #endif XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); #if VNC_CAPTURE myxfillrec(dpy, srcGC, cr.srcX, cr.srcY, rect.r.w, rect.r.h); #endif } XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY, rect.r.w, rect.r.h, rect.r.x, rect.r.y); #if VNC_CAPTURE myxcparea(dpy, gc, cr.srcX, cr.srcY, rect.r.w, rect.r.h,rect.r.x,rect.r.y); #endif break; } case rfbEncodingRRE: { switch (myFormat.bitsPerPixel) { case 8: if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 16: if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 32: if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } break; } case rfbEncodingCoRRE: { switch (myFormat.bitsPerPixel) { case 8: if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 16: if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 32: if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } break; } case rfbEncodingHextile: { switch (myFormat.bitsPerPixel) { case 8: if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 16: if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 32: if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } break; } case rfbEncodingZlib: { switch (myFormat.bitsPerPixel) { case 8: if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 16: if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 32: if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } break; } case rfbEncodingTight: { switch (myFormat.bitsPerPixel) { case 8: if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 16: if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; case 32: if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } break; } default: fprintf(stderr,"Unknown rect encoding %d\n", (int)rect.encoding); return False; } /* Now we may discard "soft cursor locks". */ SoftCursorUnlockScreen(); } #ifdef MITSHM /* if using shared memory PutImage, make sure that the X server has updated its framebuffer before we reuse the shared memory. This is mainly to avoid copyrect using invalid screen contents - not sure if we'd need it otherwise. */ if (appData.useShm) XSync(dpy, False); #endif if (!SendIncrementalFramebufferUpdateRequest()) return False; break; } case rfbBell: { Window toplevelWin; XBell(dpy, 0); if (appData.raiseOnBeep) { toplevelWin = XtWindow(toplevel); XMapRaised(dpy, toplevelWin); } break; } case rfbServerCutText: { if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbServerCutTextMsg - 1)) return False; msg.sct.length = Swap32IfLE(msg.sct.length); if (serverCutText) free(serverCutText); serverCutText = malloc(msg.sct.length+1); if (!ReadFromRFBServer(serverCutText, msg.sct.length)) return False; serverCutText[msg.sct.length] = 0; newServerCutText = True; break; } default: fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type); return False; } return True; }
Bool HandleRFBServerMessage() { rfbServerToClientMsg msg; if (!ReadFromRFBServer((char *)&msg, 1)) return False; switch (msg.type) { case rfbSetColourMapEntries: { fprintf(stderr, "Received unsupported rfbSetColourMapEntries\n"); return False; /* unsupported */ } case rfbFramebufferUpdate: { rfbFramebufferUpdateRectHeader rect; int linesToRead; int bytesPerLine; int i; if (!ReadFromRFBServer(((char *)&msg.fu) + 1, sz_rfbFramebufferUpdateMsg - 1)) return False; msg.fu.nRects = Swap16IfLE(msg.fu.nRects); for (i = 0; i < msg.fu.nRects; i++) { if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader)) return False; rect.r.x = Swap16IfLE(rect.r.x); rect.r.y = Swap16IfLE(rect.r.y); rect.r.w = Swap16IfLE(rect.r.w); rect.r.h = Swap16IfLE(rect.r.h); rect.encoding = Swap32IfLE(rect.encoding); if (rect.encoding == rfbEncodingXCursor) { if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, rfbEncodingXCursor)) { return False; } continue; } if (rect.encoding == rfbEncodingRichCursor) { if (!HandleCursorShape(rect.r.x, rect.r.y, rect.r.w, rect.r.h, rfbEncodingRichCursor)) { return False; } continue; } if (rect.encoding == rfbEncodingPointerPos) { if (!HandleCursorPos(rect.r.x, rect.r.y)) { return False; } appData.gotCursorPos = 1; continue; } if ((rect.r.x + rect.r.w > si.framebufferWidth) || (rect.r.y + rect.r.h > si.framebufferHeight)) { fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); return False; } if ((rect.r.h * rect.r.w) == 0) { fprintf(stderr,"Zero size rect - ignoring\n"); continue; } /* If RichCursor encoding is used, we should prevent collisions between framebuffer updates and cursor drawing operations. */ SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h); switch (rect.encoding) { case rfbEncodingRaw: bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8; linesToRead = BUFFER_SIZE / bytesPerLine; while (rect.r.h > 0) { if (linesToRead > rect.r.h) linesToRead = rect.r.h; if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead)) return False; CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, linesToRead); rect.r.h -= linesToRead; rect.r.y += linesToRead; } break; case rfbEncodingCopyRect: { rfbCopyRect cr; char *buffer; if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect)) return False; if (!BufferWritten()) { /* Ignore attempts to do copy-rect when we have nothing to * copy from. */ break; } cr.srcX = Swap16IfLE(cr.srcX); cr.srcY = Swap16IfLE(cr.srcY); /* If RichCursor encoding is used, we should extend our "cursor lock area" (previously set to destination rectangle) to the source rectangle as well. */ SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h); buffer = CopyScreenToData(cr.srcX, cr.srcY, rect.r.w, rect.r.h); CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w, rect.r.h); free(buffer); break; } case rfbEncodingRRE: { if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } case rfbEncodingCoRRE: { if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } case rfbEncodingHextile: { if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } case rfbEncodingZlib: { if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } case rfbEncodingTight: { if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; } case rfbEncodingZRLE: if (!zrleDecode(rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return False; break; default: fprintf(stderr,"Unknown rect encoding %d\n", (int)rect.encoding); return False; } /* Now we may discard "soft cursor locks". */ SoftCursorUnlockScreen(); /* Done. Save the screen image. */ } /* RealVNC sometimes returns an initial black screen. */ if (BufferIsBlank() && appData.ignoreBlank) { if (!appData.quiet && appData.ignoreBlank != 1) { /* user did not specify either -quiet or -ignoreblank */ fprintf(stderr, "Warning: discarding received blank screen (use -allowblank to accept,\n or -ignoreblank to suppress this message)\n"); appData.ignoreBlank = 1; } RequestNewUpdate(); } else { return False; } break; } case rfbBell: /* ignore */ break; case rfbServerCutText: { if (!ReadFromRFBServer(((char *)&msg) + 1, sz_rfbServerCutTextMsg - 1)) return False; msg.sct.length = Swap32IfLE(msg.sct.length); if (serverCutText) free(serverCutText); serverCutText = malloc(msg.sct.length+1); if (!ReadFromRFBServer(serverCutText, msg.sct.length)) return False; serverCutText[msg.sct.length] = 0; newServerCutText = True; break; } default: fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type); return False; } return True; }