Exemple #1
0
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;
            }
Exemple #2
0
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;
}
Exemple #3
0
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;
}