Bool rfbSendRichCursorUpdate(rfbClientPtr cl) { rfbFramebufferUpdateRectHeader rect; rfbPixelFormat cursorFormat; unsigned char *cursorData; int bufferMaskOffset; int cursorSize; // Size of cursor data from size int cursorRowBytes; int cursorDataSize; // Size to be sent to client int cursorMaskSize; // Mask Size to be sent to client int cursorDepth; int cursorBitsPerComponent; BOOL cursorIsDifferentFormat = FALSE; CGError err; CGSConnectionRef connection = getConnection(); int components; // Cursor Components CGPoint hotspot; CGRect cursorRect; //rfbLog("Sending Cursor To Client"); //GetCursorInfo(); if (!connection) { if (!maxFailsRemaining) cl->useRichCursorEncoding = FALSE; return FALSE; } if (CGSGetGlobalCursorDataSize(connection, &cursorDataSize) != kCGErrorSuccess) { rfbLog("Error obtaining cursor data - cursor not sent\n"); return FALSE; } cursorData = (unsigned char*)malloc(sizeof(unsigned char) * cursorDataSize); err = CGSGetGlobalCursorData(connection, cursorData, &cursorDataSize, &cursorRowBytes, &cursorRect, &hotspot, &cursorDepth, &components, &cursorBitsPerComponent); //CGSReleaseConnection(connection); if (err != kCGErrorSuccess) { rfbLog("Error obtaining cursor data - cursor not sent\n"); return FALSE; } if (cursorRect.size.height > 128 || cursorRect.size.width > 128) { // Wow That's one big cursor! We don't handle cursors this big // (they are probably cursors with lots of states and that doesn't work so good for VNC. // For now just ignore them cl->currentCursorSeed = CGSCurrentCursorSeed(); return FALSE; } // For This We Don't send location just the cursor shape (and Hot Spot) cursorFormat.depth = (cursorDepth == 32 ? 24 : cursorDepth); cursorFormat.bitsPerPixel = cursorDepth; cursorFormat.bigEndian = TRUE; cursorFormat.trueColour = TRUE; cursorFormat.redMax = cursorFormat.greenMax = cursorFormat.blueMax = (unsigned short) ((1<<cursorBitsPerComponent) - 1); cursorFormat.bigEndian = !littleEndian; cursorFormat.redShift = (unsigned char) (cursorBitsPerComponent * 2); cursorFormat.greenShift = (unsigned char) (cursorBitsPerComponent * 1); cursorFormat.blueShift = (unsigned char) (cursorBitsPerComponent * 0); //GetCursorInfo(); //PrintPixelFormat(&cursorFormat); cursorIsDifferentFormat = !(PF_EQ(cursorFormat,rfbServerFormat)); cursorSize = (cursorRect.size.width * cursorRect.size.height * (cl->format.bitsPerPixel / 8)); cursorMaskSize = floor((cursorRect.size.width+7)/8) * cursorRect.size.height; // Make Sure we have space on the buffer (otherwise push the data out now) if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + cursorSize + cursorMaskSize > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } // Send The Header rect.r.x = Swap16IfLE((short) hotspot.x); rect.r.y = Swap16IfLE((short) hotspot.y); rect.r.w = Swap16IfLE((short) cursorRect.size.width); rect.r.h = Swap16IfLE((short) cursorRect.size.height); rect.encoding = Swap32IfLE(rfbEncodingRichCursor); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; // Apple Cursors can use a full Alpha channel. // Since we can only send a bit mask - to get closer we will compose the full color with a white // This requires us to jump ahead to write in the update buffer bufferMaskOffset = cl->ublen + cursorSize; // For starters we'll set mask to OFF (transparent) everywhere) memset(&cl->updateBuf[bufferMaskOffset], 0, cursorMaskSize); // This algorithm assumes the Alpha channel is the first component { unsigned char *cursorRowData = cursorData; unsigned char *cursorColumnData = cursorData; unsigned int cursorBytesPerPixel = (cursorDepth/8); unsigned char mask = 0; unsigned int alphaShift = (8 - cursorBitsPerComponent); unsigned char fullOn = (0xFF) >> alphaShift; unsigned char alphaThreshold = (0x60) >> alphaShift; // Only include the pixel if it's coverage is greater than this int dataX, dataY, componentIndex; for (dataY = 0; dataY < cursorRect.size.height; dataY++) { cursorColumnData = cursorRowData; for (dataX = 0; dataX < cursorRect.size.width; dataX++) { if (littleEndian) mask = (unsigned char)(*(cursorColumnData+(cursorBytesPerPixel-1))) >> alphaShift; else mask = (unsigned char)(*cursorColumnData) >> alphaShift; if (mask > alphaThreshold) { // Write the Bit For The Mask to be ON (opaque) cl->updateBuf[bufferMaskOffset+(dataX/8)] |= (0x0080 >> (dataX % 8)); // Composite Alpha into the cursors other channels - only for 32 bit if (cursorDepth == 32 && mask != fullOn) { for (componentIndex = 0; componentIndex < components; componentIndex++) { *cursorColumnData = (unsigned char) (fullOn - mask + ((*cursorColumnData * mask)/fullOn)) & 0xFF; cursorColumnData++; } } else cursorColumnData += cursorBytesPerPixel; } else cursorColumnData += cursorBytesPerPixel; }
rfbBool rfbSetTranslateFunction(rfbClientPtr cl) { ///rfbLog("Pixel format for client %s:\n",cl->host); ///PrintPixelFormat(&cl->format); /* * Check that bits per pixel values are valid */ if ((cl->screen->serverFormat.bitsPerPixel != 8) && (cl->screen->serverFormat.bitsPerPixel != 16) && #ifdef LIBVNCSERVER_ALLOW24BPP (cl->screen->serverFormat.bitsPerPixel != 24) && #endif (cl->screen->serverFormat.bitsPerPixel != 32)) { ///rfbErr("%s: server bits per pixel not 8, 16 or 32 (is %d)\n", /// "rfbSetTranslateFunction", /// cl->screen->serverFormat.bitsPerPixel); rfbCloseClient(cl); return FALSE; } if ((cl->format.bitsPerPixel != 8) && (cl->format.bitsPerPixel != 16) && #ifdef LIBVNCSERVER_ALLOW24BPP (cl->format.bitsPerPixel != 24) && #endif (cl->format.bitsPerPixel != 32)) { ///rfbErr("%s: client bits per pixel not 8, 16 or 32\n", /// "rfbSetTranslateFunction"); rfbCloseClient(cl); return FALSE; } if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) { ///rfbErr("rfbSetTranslateFunction: client has colour map " /// "but %d-bit - can only cope with 8-bit colour maps\n", /// cl->format.bitsPerPixel); rfbCloseClient(cl); return FALSE; } /* * bpp is valid, now work out how to translate */ if (!cl->format.trueColour) { /* * truecolour -> colour map * * Set client's colour map to BGR233, then effectively it's * truecolour as well */ if (!rfbSetClientColourMapBGR233(cl)) return FALSE; cl->format = BGR233Format; } /* truecolour -> truecolour */ if (PF_EQ(cl->format,cl->screen->serverFormat)) { /* client & server the same */ ///rfbLog("no translation needed\n"); cl->translateFn = rfbTranslateNone; return TRUE; } if ((cl->screen->serverFormat.bitsPerPixel < 16) || ((!cl->screen->serverFormat.trueColour || !rfbEconomicTranslate) && (cl->screen->serverFormat.bitsPerPixel == 16))) { /* we can use a single lookup table for <= 16 bpp */ cl->translateFn = rfbTranslateWithSingleTableFns [BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)] [BPP2OFFSET(cl->format.bitsPerPixel)]; if(cl->screen->serverFormat.trueColour) (*rfbInitTrueColourSingleTableFns [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable, &(cl->screen->serverFormat), &cl->format); else (*rfbInitColourMapSingleTableFns [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable, &(cl->screen->serverFormat), &cl->format,&cl->screen->colourMap); } else { /* otherwise we use three separate tables for red, green and blue */ cl->translateFn = rfbTranslateWithRGBTablesFns [BPP2OFFSET(cl->screen->serverFormat.bitsPerPixel)] [BPP2OFFSET(cl->format.bitsPerPixel)]; (*rfbInitTrueColourRGBTablesFns [BPP2OFFSET(cl->format.bitsPerPixel)]) (&cl->translateLookupTable, &(cl->screen->serverFormat), &cl->format); } return TRUE; }
Bool rfbSetTranslateFunctionUsingFormat(rfbClientPtr cl, rfbPixelFormat inFormat) { /* * Check that bits per pixel values are valid */ if ((inFormat.bitsPerPixel != 8) && (inFormat.bitsPerPixel != 16) && (inFormat.bitsPerPixel != 32)) { rfbLog("%s: server bits per pixel not 8, 16 or 32\n", "rfbSetTranslateFunction"); rfbCloseClient(cl); return FALSE; } if ((cl->format.bitsPerPixel != 8) && (cl->format.bitsPerPixel != 16) && (cl->format.bitsPerPixel != 32)) { rfbLog("%s: client bits per pixel not 8, 16 or 32\n", "rfbSetTranslateFunction"); rfbCloseClient(cl); return FALSE; } if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) { rfbLog("rfbSetTranslateFunction: client has colour map " "but %d-bit - can only cope with 8-bit colour maps\n", cl->format.bitsPerPixel); rfbCloseClient(cl); return FALSE; } /* * bpp is valid, now work out how to translate */ if (!cl->format.trueColour) { /* * truecolour -> colour map * * Set client's colour map to BGR233, then effectively it's * truecolour as well */ rfbLog("setting the client's color map to BGR233\n"); if (!rfbSetClientColourMapBGR233(cl)) return FALSE; cl->format = BGR233Format; } /* truecolour -> truecolour */ if (PF_EQ(cl->format,inFormat)) { /* client & server the same */ //rfbLog("no translation needed\n"); cl->translateFn = rfbTranslateNone; return TRUE; } if ((inFormat.bitsPerPixel < 16) || (!rfbEconomicTranslate && (inFormat.bitsPerPixel == 16))) { /* we can use a single lookup table for <= 16 bpp */ //rfbLog("single lookup table translation, function [%d][%d]\n", inFormat.bitsPerPixel / 16, cl->format.bitsPerPixel / 16); cl->translateFn = rfbTranslateWithSingleTableFns [inFormat.bitsPerPixel / 16] [cl->format.bitsPerPixel / 16]; (*rfbInitTrueColourSingleTableFns [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable, &inFormat, &cl->format); } else { //rfbLog("three tables for R, G, B\n"); /* otherwise we use three separate tables for red, green and blue */ cl->translateFn = rfbTranslateWithRGBTablesFns [inFormat.bitsPerPixel / 16] [cl->format.bitsPerPixel / 16]; (*rfbInitTrueColourRGBTablesFns [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable, &inFormat, &cl->format); } return TRUE; }